aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-08-22 16:58:43 -0500
committerxoviat <[email protected]>2023-08-22 16:58:43 -0500
commit7d6edd7b15d2209ac0b96ff8814ecefce2964e36 (patch)
tree7988a9b46855ac187a92cbfc5f38cbbbff695e8d
parent9e3266b74554ea397bdd963ff12a26aa51e77b63 (diff)
parent7bff2ebab3b36cc922505e9db961840109c509ed (diff)
Merge branch 'main' of https://github.com/embassy-rs/embassy into rtc-lp
-rwxr-xr-x.github/ci/doc.sh14
-rw-r--r--.vscode/settings.json17
-rwxr-xr-xci.sh3
-rw-r--r--cyw43/Cargo.toml2
-rw-r--r--cyw43/src/bus.rs2
-rw-r--r--embassy-boot/nrf/src/lib.rs37
-rw-r--r--embassy-boot/rp/src/lib.rs41
-rw-r--r--embassy-boot/stm32/src/lib.rs33
-rw-r--r--embassy-embedded-hal/Cargo.toml4
-rw-r--r--embassy-embedded-hal/src/adapter/blocking_async.rs11
-rw-r--r--embassy-executor/CHANGELOG.md13
-rw-r--r--embassy-executor/Cargo.toml9
-rw-r--r--embassy-executor/src/arch/cortex_m.rs88
-rw-r--r--embassy-executor/src/arch/riscv32.rs18
-rw-r--r--embassy-executor/src/arch/std.rs17
-rw-r--r--embassy-executor/src/arch/wasm.rs33
-rw-r--r--embassy-executor/src/arch/xtensa.rs22
-rw-r--r--embassy-executor/src/raw/mod.rs228
-rw-r--r--embassy-executor/src/spawner.rs3
-rw-r--r--embassy-lora/Cargo.toml5
-rw-r--r--embassy-net-driver-channel/README.md2
-rw-r--r--embassy-net-enc28j60/Cargo.toml23
-rw-r--r--embassy-net-enc28j60/README.md19
-rw-r--r--embassy-net-enc28j60/src/bank0.rs69
-rw-r--r--embassy-net-enc28j60/src/bank1.rs84
-rw-r--r--embassy-net-enc28j60/src/bank2.rs86
-rw-r--r--embassy-net-enc28j60/src/bank3.rs53
-rw-r--r--embassy-net-enc28j60/src/common.rs106
-rw-r--r--embassy-net-enc28j60/src/fmt.rs225
-rw-r--r--embassy-net-enc28j60/src/header.rs30
-rw-r--r--embassy-net-enc28j60/src/lib.rs717
-rw-r--r--embassy-net-enc28j60/src/macros.rs89
-rw-r--r--embassy-net-enc28j60/src/phy.rs35
-rw-r--r--embassy-net-enc28j60/src/traits.rs57
-rw-r--r--embassy-net-esp-hosted/Cargo.toml4
-rw-r--r--embassy-net-esp-hosted/src/control.rs136
-rw-r--r--embassy-net-esp-hosted/src/lib.rs36
-rw-r--r--embassy-net-w5500/README.md7
-rw-r--r--embassy-net-w5500/src/device.rs131
-rw-r--r--embassy-net-w5500/src/socket.rs80
-rw-r--r--embassy-net-w5500/src/spi.rs32
-rw-r--r--embassy-net-wiznet/Cargo.toml (renamed from embassy-net-w5500/Cargo.toml)17
-rw-r--r--embassy-net-wiznet/README.md27
-rw-r--r--embassy-net-wiznet/src/chip/mod.rs48
-rw-r--r--embassy-net-wiznet/src/chip/w5100s.rs61
-rw-r--r--embassy-net-wiznet/src/chip/w5500.rs72
-rw-r--r--embassy-net-wiznet/src/device.rs195
-rw-r--r--embassy-net-wiznet/src/lib.rs (renamed from embassy-net-w5500/src/lib.rs)44
-rw-r--r--embassy-net/README.md2
-rw-r--r--embassy-net/src/tcp.rs141
-rw-r--r--embassy-net/src/udp.rs20
-rw-r--r--embassy-nrf/Cargo.toml6
-rw-r--r--embassy-nrf/src/spim.rs3
-rw-r--r--embassy-nrf/src/uarte.rs48
-rw-r--r--embassy-rp/Cargo.toml6
-rw-r--r--embassy-rp/src/dma.rs5
-rw-r--r--embassy-rp/src/flash.rs100
-rw-r--r--embassy-rp/src/uart/buffered.rs26
-rw-r--r--embassy-rp/src/uart/mod.rs38
-rw-r--r--embassy-stm32-wpan/src/mac/driver.rs10
-rw-r--r--embassy-stm32-wpan/src/mac/runner.rs2
-rw-r--r--embassy-stm32/Cargo.toml10
-rw-r--r--embassy-stm32/build.rs6
-rw-r--r--embassy-stm32/src/adc/mod.rs16
-rw-r--r--embassy-stm32/src/adc/sample_time.rs2
-rw-r--r--embassy-stm32/src/can/bxcan.rs13
-rw-r--r--embassy-stm32/src/dma/bdma.rs74
-rw-r--r--embassy-stm32/src/dma/dma.rs74
-rw-r--r--embassy-stm32/src/dma/ringbuffer.rs103
-rw-r--r--embassy-stm32/src/flash/h7.rs12
-rw-r--r--embassy-stm32/src/flash/mod.rs4
-rw-r--r--embassy-stm32/src/rcc/f2.rs32
-rw-r--r--embassy-stm32/src/rcc/h7.rs49
-rw-r--r--embassy-stm32/src/rcc/l4.rs3
-rw-r--r--embassy-stm32/src/rcc/mod.rs2
-rw-r--r--embassy-stm32/src/rcc/wl.rs5
-rw-r--r--embassy-stm32/src/rng.rs11
-rw-r--r--embassy-stm32/src/rtc/v2.rs2
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs9
-rw-r--r--embassy-stm32/src/timer/mod.rs49
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs8
-rw-r--r--embassy-stm32/src/usart/buffered.rs26
-rw-r--r--embassy-stm32/src/usart/mod.rs86
-rw-r--r--embassy-sync/src/blocking_mutex/raw.rs2
-rw-r--r--embassy-sync/src/channel.rs190
-rw-r--r--embassy-time/Cargo.toml4
-rw-r--r--embassy-usb/src/class/cdc_ncm/mod.rs21
-rw-r--r--embassy-usb/src/msos.rs2
-rw-r--r--examples/boot/application/rp/src/bin/a.rs4
-rw-r--r--examples/boot/bootloader/nrf/src/main.rs4
-rw-r--r--examples/boot/bootloader/rp/src/main.rs4
-rw-r--r--examples/boot/bootloader/stm32/src/main.rs4
-rw-r--r--examples/nrf52840/Cargo.toml10
-rw-r--r--examples/nrf52840/src/bin/channel.rs2
-rw-r--r--examples/nrf52840/src/bin/channel_sender_receiver.rs2
-rw-r--r--examples/nrf52840/src/bin/ethernet_enc28j60.rs124
-rw-r--r--examples/nrf52840/src/bin/uart_split.rs2
-rw-r--r--examples/nrf52840/src/bin/wifi_esp_hosted.rs6
-rw-r--r--examples/rp/Cargo.toml12
-rw-r--r--examples/rp/src/bin/ethernet_w5500_multisocket.rs8
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_client.rs8
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_server.rs9
-rw-r--r--examples/rp/src/bin/ethernet_w5500_udp.rs9
-rw-r--r--examples/rp/src/bin/flash.rs34
-rw-r--r--examples/rp/src/bin/lora_p2p_send_multicore.rs2
-rw-r--r--examples/rp/src/bin/multicore.rs2
-rw-r--r--examples/stm32f3/src/bin/button_events.rs4
-rw-r--r--examples/stm32h5/Cargo.toml4
-rw-r--r--examples/stm32h5/src/bin/usart_split.rs2
-rw-r--r--examples/stm32h7/Cargo.toml4
-rw-r--r--examples/stm32h7/src/bin/usart_split.rs2
-rw-r--r--examples/stm32l0/Cargo.toml3
-rw-r--r--examples/stm32l4/Cargo.toml4
-rw-r--r--examples/stm32wl/Cargo.toml3
-rw-r--r--rust-toolchain.toml2
-rw-r--r--tests/nrf/Cargo.toml4
-rw-r--r--tests/nrf/src/bin/buffered_uart.rs3
-rw-r--r--tests/nrf/src/bin/buffered_uart_spam.rs3
-rw-r--r--tests/nrf/src/bin/ethernet_enc28j60_perf.rs250
-rw-r--r--tests/nrf/src/bin/timer.rs3
-rw-r--r--tests/nrf/src/bin/wifi_esp_hosted_perf.rs13
-rw-r--r--tests/nrf/src/common.rs1
-rw-r--r--tests/rp/Cargo.toml9
-rw-r--r--tests/rp/src/bin/adc.rs3
-rw-r--r--tests/rp/src/bin/cyw43-perf.rs3
-rw-r--r--tests/rp/src/bin/dma_copy_async.rs3
-rw-r--r--tests/rp/src/bin/ethernet_w5100s_perf.rs249
-rw-r--r--tests/rp/src/bin/flash.rs17
-rw-r--r--tests/rp/src/bin/float.rs3
-rw-r--r--tests/rp/src/bin/gpio.rs3
-rw-r--r--tests/rp/src/bin/gpio_async.rs3
-rw-r--r--tests/rp/src/bin/gpio_multicore.rs9
-rw-r--r--tests/rp/src/bin/multicore.rs7
-rw-r--r--tests/rp/src/bin/pio_irq.rs3
-rw-r--r--tests/rp/src/bin/pio_multi_load.rs3
-rw-r--r--tests/rp/src/bin/pwm.rs3
-rw-r--r--tests/rp/src/bin/spi.rs3
-rw-r--r--tests/rp/src/bin/spi_async.rs3
-rw-r--r--tests/rp/src/bin/uart.rs3
-rw-r--r--tests/rp/src/bin/uart_buffered.rs3
-rw-r--r--tests/rp/src/bin/uart_dma.rs3
-rw-r--r--tests/rp/src/bin/uart_upgrade.rs3
-rw-r--r--tests/rp/src/common.rs1
-rw-r--r--tests/stm32/Cargo.toml4
-rw-r--r--tests/stm32/src/bin/can.rs4
145 files changed, 3930 insertions, 1273 deletions
diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh
index 06c6fa00b..57184dc1d 100755
--- a/.github/ci/doc.sh
+++ b/.github/ci/doc.sh
@@ -15,7 +15,6 @@ export BUILDER_COMPRESS=true
15# which makes rustup very sad 15# which makes rustup very sad
16rustc --version > /dev/null 16rustc --version > /dev/null
17 17
18docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup
19docserver-builder -i ./embassy-boot/boot -o webroot/crates/embassy-boot/git.zup 18docserver-builder -i ./embassy-boot/boot -o webroot/crates/embassy-boot/git.zup
20docserver-builder -i ./embassy-boot/nrf -o webroot/crates/embassy-boot-nrf/git.zup 19docserver-builder -i ./embassy-boot/nrf -o webroot/crates/embassy-boot-nrf/git.zup
21docserver-builder -i ./embassy-boot/rp -o webroot/crates/embassy-boot-rp/git.zup 20docserver-builder -i ./embassy-boot/rp -o webroot/crates/embassy-boot-rp/git.zup
@@ -36,11 +35,20 @@ docserver-builder -i ./embassy-usb-driver -o webroot/crates/embassy-usb-driver/g
36docserver-builder -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup 35docserver-builder -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup
37docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup 36docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup
38docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup 37docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup
39docserver-builder -i ./embassy-net-w5500 -o webroot/crates/embassy-net-w5500/git.zup 38docserver-builder -i ./embassy-net-wiznet -o webroot/crates/embassy-net-wiznet/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
42 42
43export KUBECONFIG=/ci/secrets/kubeconfig.yml 43export KUBECONFIG=/ci/secrets/kubeconfig.yml
44POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) 44POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
45kubectl cp webroot/crates $POD:/data 45kubectl cp webroot/crates $POD:/data
46kubectl cp webroot/static $POD:/data \ No newline at end of file 46kubectl cp webroot/static $POD:/data
47
48# build and upload stm32 last
49# so that it doesn't prevent other crates from getting docs updates when it breaks.
50rm -rf webroot
51docserver-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})
54kubectl cp webroot/crates $POD:/data
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 29e8812e3..d48f7ba1e 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -6,16 +6,21 @@
6 "rust-analyzer.check.allTargets": false, 6 "rust-analyzer.check.allTargets": false,
7 "rust-analyzer.check.noDefaultFeatures": true, 7 "rust-analyzer.check.noDefaultFeatures": true,
8 "rust-analyzer.cargo.noDefaultFeatures": true, 8 "rust-analyzer.cargo.noDefaultFeatures": true,
9 "rust-analyzer.cargo.target": "thumbv7m-none-eabi", 9 "rust-analyzer.showUnlinkedFileNotification": false,
10 // uncomment the target of your chip.
11 //"rust-analyzer.cargo.target": "thumbv6m-none-eabi",
12 //"rust-analyzer.cargo.target": "thumbv7m-none-eabi",
13 "rust-analyzer.cargo.target": "thumbv7em-none-eabi",
10 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", 14 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
11 "rust-analyzer.cargo.features": [ 15 "rust-analyzer.cargo.features": [
12 ///"nightly", 16 // Uncomment if the example has a "nightly" feature.
17 "nightly",
13 ], 18 ],
14 "rust-analyzer.linkedProjects": [ 19 "rust-analyzer.linkedProjects": [
15 // Declare for the target you wish to develop 20 // Uncomment ONE line for the chip you want to work on.
16 // "embassy-executor/Cargo.toml", 21 // This makes rust-analyzer work on the example crate and all its dependencies.
17 // "embassy-sync/Cargo.toml", 22 "examples/nrf52840/Cargo.toml",
18 "examples/stm32wl/Cargo.toml", 23 // "examples/nrf52840-rtic/Cargo.toml",
19 // "examples/nrf5340/Cargo.toml", 24 // "examples/nrf5340/Cargo.toml",
20 // "examples/nrf-rtos-trace/Cargo.toml", 25 // "examples/nrf-rtos-trace/Cargo.toml",
21 // "examples/rp/Cargo.toml", 26 // "examples/rp/Cargo.toml",
diff --git a/ci.sh b/ci.sh
index 146a1c508..e83b3b847 100755
--- a/ci.sh
+++ b/ci.sh
@@ -3,7 +3,7 @@
3set -euo pipefail 3set -euo pipefail
4 4
5export RUSTFLAGS=-Dwarnings 5export RUSTFLAGS=-Dwarnings
6export DEFMT_LOG=trace,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info 6export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info
7 7
8TARGET=$(rustc -vV | sed -n 's|host: ||p') 8TARGET=$(rustc -vV | sed -n 's|host: ||p')
9 9
@@ -81,6 +81,7 @@ cargo batch \
81 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,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 \
82 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \ 82 --- 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 \ 83 --- 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 \
84 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits \ 85 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits \
85 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits \ 86 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits \
86 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,unstable-traits \ 87 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,unstable-traits \
diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml
index 50fb7c5db..855d54b11 100644
--- a/cyw43/Cargo.toml
+++ b/cyw43/Cargo.toml
@@ -24,7 +24,7 @@ cortex-m = "0.7.6"
24cortex-m-rt = "0.7.0" 24cortex-m-rt = "0.7.0"
25futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } 25futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] }
26 26
27embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.11" } 27embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-rc.1" }
28num_enum = { version = "0.5.7", default-features = false } 28num_enum = { version = "0.5.7", default-features = false }
29 29
30[package.metadata.embassy_docs] 30[package.metadata.embassy_docs]
diff --git a/cyw43/src/bus.rs b/cyw43/src/bus.rs
index e26f11120..0b5632cf8 100644
--- a/cyw43/src/bus.rs
+++ b/cyw43/src/bus.rs
@@ -102,7 +102,7 @@ where
102 cmd_buf[0] = cmd; 102 cmd_buf[0] = cmd;
103 cmd_buf[1..][..buf.len()].copy_from_slice(buf); 103 cmd_buf[1..][..buf.len()].copy_from_slice(buf);
104 104
105 self.status = self.spi.cmd_write(&cmd_buf).await; 105 self.status = self.spi.cmd_write(&cmd_buf[..buf.len() + 1]).await;
106 } 106 }
107 107
108 #[allow(unused)] 108 #[allow(unused)]
diff --git a/embassy-boot/nrf/src/lib.rs b/embassy-boot/nrf/src/lib.rs
index df94819fc..b9d86eb17 100644
--- a/embassy-boot/nrf/src/lib.rs
+++ b/embassy-boot/nrf/src/lib.rs
@@ -14,28 +14,17 @@ use embassy_nrf::wdt;
14use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; 14use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash};
15 15
16/// A bootloader for nRF devices. 16/// A bootloader for nRF devices.
17pub struct BootLoader<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize = PAGE_SIZE> { 17pub struct BootLoader<const BUFFER_SIZE: usize = PAGE_SIZE>;
18 boot: embassy_boot::BootLoader<ACTIVE, DFU, STATE>, 18
19 aligned_buf: AlignedBuffer<BUFFER_SIZE>, 19impl<const BUFFER_SIZE: usize> BootLoader<BUFFER_SIZE> {
20} 20 /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware.
21 21 pub fn prepare<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash>(
22impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize> 22 config: BootLoaderConfig<ACTIVE, DFU, STATE>,
23 BootLoader<ACTIVE, DFU, STATE, BUFFER_SIZE> 23 ) -> Self {
24{ 24 let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]);
25 /// Create a new bootloader instance using the supplied partitions for active, dfu and state. 25 let mut boot = embassy_boot::BootLoader::new(config);
26 pub fn new(config: BootLoaderConfig<ACTIVE, DFU, STATE>) -> Self { 26 boot.prepare_boot(&mut aligned_buf.0).expect("Boot prepare error");
27 Self { 27 Self
28 boot: embassy_boot::BootLoader::new(config),
29 aligned_buf: AlignedBuffer([0; BUFFER_SIZE]),
30 }
31 }
32
33 /// Inspect the bootloader state and perform actions required before booting, such as swapping
34 /// firmware.
35 pub fn prepare(&mut self) {
36 self.boot
37 .prepare_boot(&mut self.aligned_buf.0)
38 .expect("Boot prepare error");
39 } 28 }
40 29
41 /// Boots the application without softdevice mechanisms. 30 /// Boots the application without softdevice mechanisms.
@@ -45,8 +34,6 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize>
45 /// This modifies the stack pointer and reset vector and will run code placed in the active partition. 34 /// This modifies the stack pointer and reset vector and will run code placed in the active partition.
46 #[cfg(not(feature = "softdevice"))] 35 #[cfg(not(feature = "softdevice"))]
47 pub unsafe fn load(self, start: u32) -> ! { 36 pub unsafe fn load(self, start: u32) -> ! {
48 core::mem::drop(self.boot);
49
50 let mut p = cortex_m::Peripherals::steal(); 37 let mut p = cortex_m::Peripherals::steal();
51 p.SCB.invalidate_icache(); 38 p.SCB.invalidate_icache();
52 p.SCB.vtor.write(start); 39 p.SCB.vtor.write(start);
@@ -59,7 +46,7 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize>
59 /// 46 ///
60 /// This modifies the stack pointer and reset vector and will run code placed in the active partition. 47 /// This modifies the stack pointer and reset vector and will run code placed in the active partition.
61 #[cfg(feature = "softdevice")] 48 #[cfg(feature = "softdevice")]
62 pub unsafe fn load(&mut self, _app: u32) -> ! { 49 pub unsafe fn load(self, _app: u32) -> ! {
63 use nrf_softdevice_mbr as mbr; 50 use nrf_softdevice_mbr as mbr;
64 const NRF_SUCCESS: u32 = 0; 51 const NRF_SUCCESS: u32 = 0;
65 52
diff --git a/embassy-boot/rp/src/lib.rs b/embassy-boot/rp/src/lib.rs
index f5aefa416..989e7521b 100644
--- a/embassy-boot/rp/src/lib.rs
+++ b/embassy-boot/rp/src/lib.rs
@@ -15,28 +15,17 @@ use embassy_time::Duration;
15use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; 15use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash};
16 16
17/// A bootloader for RP2040 devices. 17/// A bootloader for RP2040 devices.
18pub struct BootLoader<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize = ERASE_SIZE> { 18pub struct BootLoader<const BUFFER_SIZE: usize = ERASE_SIZE>;
19 boot: embassy_boot::BootLoader<ACTIVE, DFU, STATE>,
20 aligned_buf: AlignedBuffer<BUFFER_SIZE>,
21}
22
23impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize>
24 BootLoader<ACTIVE, DFU, STATE, BUFFER_SIZE>
25{
26 /// Create a new bootloader instance using the supplied partitions for active, dfu and state.
27 pub fn new(config: BootLoaderConfig<ACTIVE, DFU, STATE>) -> Self {
28 Self {
29 boot: embassy_boot::BootLoader::new(config),
30 aligned_buf: AlignedBuffer([0; BUFFER_SIZE]),
31 }
32 }
33 19
34 /// Inspect the bootloader state and perform actions required before booting, such as swapping 20impl<const BUFFER_SIZE: usize> BootLoader<BUFFER_SIZE> {
35 /// firmware. 21 /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware
36 pub fn prepare(&mut self) { 22 pub fn prepare<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash>(
37 self.boot 23 config: BootLoaderConfig<ACTIVE, DFU, STATE>,
38 .prepare_boot(self.aligned_buf.as_mut()) 24 ) -> Self {
39 .expect("Boot prepare error"); 25 let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]);
26 let mut boot = embassy_boot::BootLoader::new(config);
27 boot.prepare_boot(aligned_buf.as_mut()).expect("Boot prepare error");
28 Self
40 } 29 }
41 30
42 /// Boots the application. 31 /// Boots the application.
@@ -45,8 +34,6 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize>
45 /// 34 ///
46 /// This modifies the stack pointer and reset vector and will run code placed in the active partition. 35 /// This modifies the stack pointer and reset vector and will run code placed in the active partition.
47 pub unsafe fn load(self, start: u32) -> ! { 36 pub unsafe fn load(self, start: u32) -> ! {
48 core::mem::drop(self.boot);
49
50 trace!("Loading app at 0x{:x}", start); 37 trace!("Loading app at 0x{:x}", start);
51 #[allow(unused_mut)] 38 #[allow(unused_mut)]
52 let mut p = cortex_m::Peripherals::steal(); 39 let mut p = cortex_m::Peripherals::steal();
@@ -67,7 +54,7 @@ pub struct WatchdogFlash<'d, const SIZE: usize> {
67impl<'d, const SIZE: usize> WatchdogFlash<'d, SIZE> { 54impl<'d, const SIZE: usize> WatchdogFlash<'d, SIZE> {
68 /// Start a new watchdog with a given flash and watchdog peripheral and a timeout 55 /// Start a new watchdog with a given flash and watchdog peripheral and a timeout
69 pub fn start(flash: FLASH, watchdog: WATCHDOG, timeout: Duration) -> Self { 56 pub fn start(flash: FLASH, watchdog: WATCHDOG, timeout: Duration) -> Self {
70 let flash = Flash::<_, Blocking, SIZE>::new(flash); 57 let flash = Flash::<_, Blocking, SIZE>::new_blocking(flash);
71 let mut watchdog = Watchdog::new(watchdog); 58 let mut watchdog = Watchdog::new(watchdog);
72 watchdog.start(timeout); 59 watchdog.start(timeout);
73 Self { flash, watchdog } 60 Self { flash, watchdog }
@@ -84,11 +71,11 @@ impl<'d, const SIZE: usize> NorFlash for WatchdogFlash<'d, SIZE> {
84 71
85 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { 72 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
86 self.watchdog.feed(); 73 self.watchdog.feed();
87 self.flash.erase(from, to) 74 self.flash.blocking_erase(from, to)
88 } 75 }
89 fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> { 76 fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> {
90 self.watchdog.feed(); 77 self.watchdog.feed();
91 self.flash.write(offset, data) 78 self.flash.blocking_write(offset, data)
92 } 79 }
93} 80}
94 81
@@ -96,7 +83,7 @@ impl<'d, const SIZE: usize> ReadNorFlash for WatchdogFlash<'d, SIZE> {
96 const READ_SIZE: usize = <Flash<'d, FLASH, Blocking, SIZE> as ReadNorFlash>::READ_SIZE; 83 const READ_SIZE: usize = <Flash<'d, FLASH, Blocking, SIZE> as ReadNorFlash>::READ_SIZE;
97 fn read(&mut self, offset: u32, data: &mut [u8]) -> Result<(), Self::Error> { 84 fn read(&mut self, offset: u32, data: &mut [u8]) -> Result<(), Self::Error> {
98 self.watchdog.feed(); 85 self.watchdog.feed();
99 self.flash.read(offset, data) 86 self.flash.blocking_read(offset, data)
100 } 87 }
101 fn capacity(&self) -> usize { 88 fn capacity(&self) -> usize {
102 self.flash.capacity() 89 self.flash.capacity()
diff --git a/embassy-boot/stm32/src/lib.rs b/embassy-boot/stm32/src/lib.rs
index 25f029423..c6350c495 100644
--- a/embassy-boot/stm32/src/lib.rs
+++ b/embassy-boot/stm32/src/lib.rs
@@ -11,28 +11,17 @@ pub use embassy_boot::{FirmwareState, FirmwareUpdater};
11use embedded_storage::nor_flash::NorFlash; 11use embedded_storage::nor_flash::NorFlash;
12 12
13/// A bootloader for STM32 devices. 13/// A bootloader for STM32 devices.
14pub struct BootLoader<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize> { 14pub struct BootLoader;
15 boot: embassy_boot::BootLoader<ACTIVE, DFU, STATE>,
16 aligned_buf: AlignedBuffer<BUFFER_SIZE>,
17}
18
19impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize>
20 BootLoader<ACTIVE, DFU, STATE, BUFFER_SIZE>
21{
22 /// Create a new bootloader instance using the supplied partitions for active, dfu and state.
23 pub fn new(config: BootLoaderConfig<ACTIVE, DFU, STATE>) -> Self {
24 Self {
25 boot: embassy_boot::BootLoader::new(config),
26 aligned_buf: AlignedBuffer([0; BUFFER_SIZE]),
27 }
28 }
29 15
30 /// Inspect the bootloader state and perform actions required before booting, such as swapping 16impl BootLoader {
31 /// firmware. 17 /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware
32 pub fn prepare(&mut self) { 18 pub fn prepare<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize>(
33 self.boot 19 config: BootLoaderConfig<ACTIVE, DFU, STATE>,
34 .prepare_boot(self.aligned_buf.as_mut()) 20 ) -> Self {
35 .expect("Boot prepare error"); 21 let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]);
22 let mut boot = embassy_boot::BootLoader::new(config);
23 boot.prepare_boot(aligned_buf.as_mut()).expect("Boot prepare error");
24 Self
36 } 25 }
37 26
38 /// Boots the application. 27 /// Boots the application.
@@ -41,8 +30,6 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize>
41 /// 30 ///
42 /// This modifies the stack pointer and reset vector and will run code placed in the active partition. 31 /// This modifies the stack pointer and reset vector and will run code placed in the active partition.
43 pub unsafe fn load(self, start: u32) -> ! { 32 pub unsafe fn load(self, start: u32) -> ! {
44 core::mem::drop(self.boot);
45
46 trace!("Loading app at 0x{:x}", start); 33 trace!("Loading app at 0x{:x}", start);
47 #[allow(unused_mut)] 34 #[allow(unused_mut)]
48 let mut p = cortex_m::Peripherals::steal(); 35 let mut p = cortex_m::Peripherals::steal();
diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml
index bba3d48be..fd921d277 100644
--- a/embassy-embedded-hal/Cargo.toml
+++ b/embassy-embedded-hal/Cargo.toml
@@ -25,8 +25,8 @@ embassy-time = { version = "0.1.2", 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] }
28embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" } 28embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
29embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true } 29embedded-hal-async = { version = "=1.0.0-rc.1", optional = true }
30embedded-storage = "0.3.0" 30embedded-storage = "0.3.0"
31embedded-storage-async = { version = "0.4.0", optional = true } 31embedded-storage-async = { version = "0.4.0", optional = true }
32nb = "1.0.0" 32nb = "1.0.0"
diff --git a/embassy-embedded-hal/src/adapter/blocking_async.rs b/embassy-embedded-hal/src/adapter/blocking_async.rs
index 98ae2b02c..ae0d0a7f9 100644
--- a/embassy-embedded-hal/src/adapter/blocking_async.rs
+++ b/embassy-embedded-hal/src/adapter/blocking_async.rs
@@ -1,4 +1,4 @@
1use embedded_hal_02::{blocking, serial}; 1use embedded_hal_02::blocking;
2 2
3/// Wrapper that implements async traits using blocking implementations. 3/// Wrapper that implements async traits using blocking implementations.
4/// 4///
@@ -103,15 +103,6 @@ where
103 } 103 }
104} 104}
105 105
106// Uart implementatinos
107impl<T, E> embedded_hal_1::serial::ErrorType for BlockingAsync<T>
108where
109 T: serial::Read<u8, Error = E>,
110 E: embedded_hal_1::serial::Error + 'static,
111{
112 type Error = E;
113}
114
115/// NOR flash wrapper 106/// NOR flash wrapper
116use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; 107use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash};
117use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash}; 108use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};
diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md
index 4fd3dccf7..43d94e540 100644
--- a/embassy-executor/CHANGELOG.md
+++ b/embassy-executor/CHANGELOG.md
@@ -5,6 +5,19 @@ 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## Unreleased
9
10- Replaced Pender. Implementations now must define an extern function called `__pender`.
11- Made `raw::AvailableTask` public
12- Made `SpawnToken::new_failed` public
13
14## 0.2.1 - 2023-08-10
15
16- Avoid calling `pend()` when waking expired timers
17- Properly reset finished task state with `integrated-timers` enabled
18- Introduce `InterruptExecutor::spawner()`
19- Fix incorrect critical section in Xtensa executor
20
8## 0.2.0 - 2023-04-27 21## 0.2.0 - 2023-04-27
9 22
10- Replace unnecessary atomics in runqueue 23- Replace unnecessary atomics in runqueue
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index 590718e3e..d190c95a3 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-executor" 2name = "embassy-executor"
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 = "async/await executor designed for embedded usage" 6description = "async/await executor designed for embedded usage"
@@ -14,7 +14,7 @@ categories = [
14[package.metadata.embassy_docs] 14[package.metadata.embassy_docs]
15src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/" 15src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/"
16src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/" 16src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/"
17features = ["nightly", "defmt", "pender-callback"] 17features = ["nightly", "defmt"]
18flavors = [ 18flavors = [
19 { name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] }, 19 { name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] },
20 { name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] }, 20 { name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] },
@@ -25,7 +25,7 @@ flavors = [
25[package.metadata.docs.rs] 25[package.metadata.docs.rs]
26default-target = "thumbv7em-none-eabi" 26default-target = "thumbv7em-none-eabi"
27targets = ["thumbv7em-none-eabi"] 27targets = ["thumbv7em-none-eabi"]
28features = ["nightly", "defmt", "pender-callback", "arch-cortex-m", "executor-thread", "executor-interrupt"] 28features = ["nightly", "defmt", "arch-cortex-m", "executor-thread", "executor-interrupt"]
29 29
30[features] 30[features]
31 31
@@ -37,9 +37,6 @@ arch-xtensa = ["_arch"]
37arch-riscv32 = ["_arch"] 37arch-riscv32 = ["_arch"]
38arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"] 38arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"]
39 39
40# Enable creating a `Pender` from an arbitrary function pointer callback.
41pender-callback = []
42
43# Enable the thread-mode executor (using WFE/SEV in Cortex-M, WFI in other embedded archs) 40# Enable the thread-mode executor (using WFE/SEV in Cortex-M, WFI in other embedded archs)
44executor-thread = [] 41executor-thread = []
45# Enable the interrupt-mode executor (available in Cortex-M only) 42# Enable the interrupt-mode executor (available in Cortex-M only)
diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs
index 94c8134d6..0806a22ab 100644
--- a/embassy-executor/src/arch/cortex_m.rs
+++ b/embassy-executor/src/arch/cortex_m.rs
@@ -1,3 +1,49 @@
1const THREAD_PENDER: usize = usize::MAX;
2
3#[export_name = "__pender"]
4#[cfg(any(feature = "executor-thread", feature = "executor-interrupt"))]
5fn __pender(context: *mut ()) {
6 unsafe {
7 // Safety: `context` is either `usize::MAX` created by `Executor::run`, or a valid interrupt
8 // request number given to `InterruptExecutor::start`.
9
10 let context = context as usize;
11
12 #[cfg(feature = "executor-thread")]
13 // Try to make Rust optimize the branching away if we only use thread mode.
14 if !cfg!(feature = "executor-interrupt") || context == THREAD_PENDER {
15 core::arch::asm!("sev");
16 return;
17 }
18
19 #[cfg(feature = "executor-interrupt")]
20 {
21 use cortex_m::interrupt::InterruptNumber;
22 use cortex_m::peripheral::NVIC;
23
24 #[derive(Clone, Copy)]
25 struct Irq(u16);
26 unsafe impl InterruptNumber for Irq {
27 fn number(self) -> u16 {
28 self.0
29 }
30 }
31
32 let irq = Irq(context as u16);
33
34 // STIR is faster, but is only available in v7 and higher.
35 #[cfg(not(armv6m))]
36 {
37 let mut nvic: NVIC = core::mem::transmute(());
38 nvic.request(irq);
39 }
40
41 #[cfg(armv6m)]
42 NVIC::pend(irq);
43 }
44 }
45}
46
1#[cfg(feature = "executor-thread")] 47#[cfg(feature = "executor-thread")]
2pub use thread::*; 48pub use thread::*;
3#[cfg(feature = "executor-thread")] 49#[cfg(feature = "executor-thread")]
@@ -8,18 +54,9 @@ mod thread {
8 #[cfg(feature = "nightly")] 54 #[cfg(feature = "nightly")]
9 pub use embassy_macros::main_cortex_m as main; 55 pub use embassy_macros::main_cortex_m as main;
10 56
11 use crate::raw::{Pender, PenderInner}; 57 use crate::arch::THREAD_PENDER;
12 use crate::{raw, Spawner}; 58 use crate::{raw, Spawner};
13 59
14 #[derive(Copy, Clone)]
15 pub(crate) struct ThreadPender;
16
17 impl ThreadPender {
18 pub(crate) fn pend(self) {
19 unsafe { core::arch::asm!("sev") }
20 }
21 }
22
23 /// Thread mode executor, using WFE/SEV. 60 /// Thread mode executor, using WFE/SEV.
24 /// 61 ///
25 /// This is the simplest and most common kind of executor. It runs on 62 /// This is the simplest and most common kind of executor. It runs on
@@ -39,7 +76,7 @@ mod thread {
39 /// Create a new Executor. 76 /// Create a new Executor.
40 pub fn new() -> Self { 77 pub fn new() -> Self {
41 Self { 78 Self {
42 inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender))), 79 inner: raw::Executor::new(THREAD_PENDER as *mut ()),
43 not_send: PhantomData, 80 not_send: PhantomData,
44 } 81 }
45 } 82 }
@@ -86,30 +123,7 @@ mod interrupt {
86 use cortex_m::interrupt::InterruptNumber; 123 use cortex_m::interrupt::InterruptNumber;
87 use cortex_m::peripheral::NVIC; 124 use cortex_m::peripheral::NVIC;
88 125
89 use crate::raw::{self, Pender, PenderInner}; 126 use crate::raw;
90
91 #[derive(Clone, Copy)]
92 pub(crate) struct InterruptPender(u16);
93
94 impl InterruptPender {
95 pub(crate) fn pend(self) {
96 // STIR is faster, but is only available in v7 and higher.
97 #[cfg(not(armv6m))]
98 {
99 let mut nvic: cortex_m::peripheral::NVIC = unsafe { core::mem::transmute(()) };
100 nvic.request(self);
101 }
102
103 #[cfg(armv6m)]
104 cortex_m::peripheral::NVIC::pend(self);
105 }
106 }
107
108 unsafe impl cortex_m::interrupt::InterruptNumber for InterruptPender {
109 fn number(self) -> u16 {
110 self.0
111 }
112 }
113 127
114 /// Interrupt mode executor. 128 /// Interrupt mode executor.
115 /// 129 ///
@@ -194,9 +208,7 @@ mod interrupt {
194 unsafe { 208 unsafe {
195 (&mut *self.executor.get()) 209 (&mut *self.executor.get())
196 .as_mut_ptr() 210 .as_mut_ptr()
197 .write(raw::Executor::new(Pender(PenderInner::Interrupt(InterruptPender( 211 .write(raw::Executor::new(irq.number() as *mut ()))
198 irq.number(),
199 )))))
200 } 212 }
201 213
202 let executor = unsafe { (&*self.executor.get()).assume_init_ref() }; 214 let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs
index ff7ec1575..40c6877e2 100644
--- a/embassy-executor/src/arch/riscv32.rs
+++ b/embassy-executor/src/arch/riscv32.rs
@@ -11,22 +11,16 @@ mod thread {
11 #[cfg(feature = "nightly")] 11 #[cfg(feature = "nightly")]
12 pub use embassy_macros::main_riscv as main; 12 pub use embassy_macros::main_riscv as main;
13 13
14 use crate::raw::{Pender, PenderInner};
15 use crate::{raw, Spawner}; 14 use crate::{raw, Spawner};
16 15
17 #[derive(Copy, Clone)]
18 pub(crate) struct ThreadPender;
19
20 impl ThreadPender {
21 #[allow(unused)]
22 pub(crate) fn pend(self) {
23 SIGNAL_WORK_THREAD_MODE.store(true, core::sync::atomic::Ordering::SeqCst);
24 }
25 }
26
27 /// global atomic used to keep track of whether there is work to do since sev() is not available on RISCV 16 /// global atomic used to keep track of whether there is work to do since sev() is not available on RISCV
28 static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); 17 static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false);
29 18
19 #[export_name = "__pender"]
20 fn __pender(_context: *mut ()) {
21 SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst);
22 }
23
30 /// RISCV32 Executor 24 /// RISCV32 Executor
31 pub struct Executor { 25 pub struct Executor {
32 inner: raw::Executor, 26 inner: raw::Executor,
@@ -37,7 +31,7 @@ mod thread {
37 /// Create a new Executor. 31 /// Create a new Executor.
38 pub fn new() -> Self { 32 pub fn new() -> Self {
39 Self { 33 Self {
40 inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender))), 34 inner: raw::Executor::new(core::ptr::null_mut()),
41 not_send: PhantomData, 35 not_send: PhantomData,
42 } 36 }
43 } 37 }
diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs
index 4e4a178f0..5b2f7e2e4 100644
--- a/embassy-executor/src/arch/std.rs
+++ b/embassy-executor/src/arch/std.rs
@@ -11,17 +11,12 @@ mod thread {
11 #[cfg(feature = "nightly")] 11 #[cfg(feature = "nightly")]
12 pub use embassy_macros::main_std as main; 12 pub use embassy_macros::main_std as main;
13 13
14 use crate::raw::{Pender, PenderInner};
15 use crate::{raw, Spawner}; 14 use crate::{raw, Spawner};
16 15
17 #[derive(Copy, Clone)] 16 #[export_name = "__pender"]
18 pub(crate) struct ThreadPender(&'static Signaler); 17 fn __pender(context: *mut ()) {
19 18 let signaler: &'static Signaler = unsafe { std::mem::transmute(context) };
20 impl ThreadPender { 19 signaler.signal()
21 #[allow(unused)]
22 pub(crate) fn pend(self) {
23 self.0.signal()
24 }
25 } 20 }
26 21
27 /// Single-threaded std-based executor. 22 /// Single-threaded std-based executor.
@@ -34,9 +29,9 @@ mod thread {
34 impl Executor { 29 impl Executor {
35 /// Create a new Executor. 30 /// Create a new Executor.
36 pub fn new() -> Self { 31 pub fn new() -> Self {
37 let signaler = &*Box::leak(Box::new(Signaler::new())); 32 let signaler = Box::leak(Box::new(Signaler::new()));
38 Self { 33 Self {
39 inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender(signaler)))), 34 inner: raw::Executor::new(signaler as *mut Signaler as *mut ()),
40 not_send: PhantomData, 35 not_send: PhantomData,
41 signaler, 36 signaler,
42 } 37 }
diff --git a/embassy-executor/src/arch/wasm.rs b/embassy-executor/src/arch/wasm.rs
index 08ab16b99..934fd69e5 100644
--- a/embassy-executor/src/arch/wasm.rs
+++ b/embassy-executor/src/arch/wasm.rs
@@ -14,14 +14,12 @@ mod thread {
14 use wasm_bindgen::prelude::*; 14 use wasm_bindgen::prelude::*;
15 15
16 use crate::raw::util::UninitCell; 16 use crate::raw::util::UninitCell;
17 use crate::raw::{Pender, PenderInner};
18 use crate::{raw, Spawner}; 17 use crate::{raw, Spawner};
19 18
20 /// WASM executor, wasm_bindgen to schedule tasks on the JS event loop. 19 #[export_name = "__pender"]
21 pub struct Executor { 20 fn __pender(context: *mut ()) {
22 inner: raw::Executor, 21 let signaler: &'static WasmContext = unsafe { std::mem::transmute(context) };
23 ctx: &'static WasmContext, 22 let _ = signaler.promise.then(unsafe { signaler.closure.as_mut() });
24 not_send: PhantomData<*mut ()>,
25 } 23 }
26 24
27 pub(crate) struct WasmContext { 25 pub(crate) struct WasmContext {
@@ -29,16 +27,6 @@ mod thread {
29 closure: UninitCell<Closure<dyn FnMut(JsValue)>>, 27 closure: UninitCell<Closure<dyn FnMut(JsValue)>>,
30 } 28 }
31 29
32 #[derive(Copy, Clone)]
33 pub(crate) struct ThreadPender(&'static WasmContext);
34
35 impl ThreadPender {
36 #[allow(unused)]
37 pub(crate) fn pend(self) {
38 let _ = self.0.promise.then(unsafe { self.0.closure.as_mut() });
39 }
40 }
41
42 impl WasmContext { 30 impl WasmContext {
43 pub fn new() -> Self { 31 pub fn new() -> Self {
44 Self { 32 Self {
@@ -48,14 +36,21 @@ mod thread {
48 } 36 }
49 } 37 }
50 38
39 /// WASM executor, wasm_bindgen to schedule tasks on the JS event loop.
40 pub struct Executor {
41 inner: raw::Executor,
42 ctx: &'static WasmContext,
43 not_send: PhantomData<*mut ()>,
44 }
45
51 impl Executor { 46 impl Executor {
52 /// Create a new Executor. 47 /// Create a new Executor.
53 pub fn new() -> Self { 48 pub fn new() -> Self {
54 let ctx = &*Box::leak(Box::new(WasmContext::new())); 49 let ctx = Box::leak(Box::new(WasmContext::new()));
55 Self { 50 Self {
56 inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender(ctx)))), 51 inner: raw::Executor::new(ctx as *mut WasmContext as *mut ()),
57 not_send: PhantomData,
58 ctx, 52 ctx,
53 not_send: PhantomData,
59 } 54 }
60 } 55 }
61 56
diff --git a/embassy-executor/src/arch/xtensa.rs b/embassy-executor/src/arch/xtensa.rs
index 017b2c52b..601d85002 100644
--- a/embassy-executor/src/arch/xtensa.rs
+++ b/embassy-executor/src/arch/xtensa.rs
@@ -8,22 +8,16 @@ mod thread {
8 use core::marker::PhantomData; 8 use core::marker::PhantomData;
9 use core::sync::atomic::{AtomicBool, Ordering}; 9 use core::sync::atomic::{AtomicBool, Ordering};
10 10
11 use crate::raw::{Pender, PenderInner};
12 use crate::{raw, Spawner}; 11 use crate::{raw, Spawner};
13 12
14 #[derive(Copy, Clone)]
15 pub(crate) struct ThreadPender;
16
17 impl ThreadPender {
18 #[allow(unused)]
19 pub(crate) fn pend(self) {
20 SIGNAL_WORK_THREAD_MODE.store(true, core::sync::atomic::Ordering::SeqCst);
21 }
22 }
23
24 /// global atomic used to keep track of whether there is work to do since sev() is not available on Xtensa 13 /// global atomic used to keep track of whether there is work to do since sev() is not available on Xtensa
25 static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); 14 static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false);
26 15
16 #[export_name = "__pender"]
17 fn __pender(_context: *mut ()) {
18 SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst);
19 }
20
27 /// Xtensa Executor 21 /// Xtensa Executor
28 pub struct Executor { 22 pub struct Executor {
29 inner: raw::Executor, 23 inner: raw::Executor,
@@ -34,7 +28,7 @@ mod thread {
34 /// Create a new Executor. 28 /// Create a new Executor.
35 pub fn new() -> Self { 29 pub fn new() -> Self {
36 Self { 30 Self {
37 inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender))), 31 inner: raw::Executor::new(core::ptr::null_mut()),
38 not_send: PhantomData, 32 not_send: PhantomData,
39 } 33 }
40 } 34 }
@@ -77,8 +71,8 @@ mod thread {
77 SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst); 71 SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst);
78 72
79 core::arch::asm!( 73 core::arch::asm!(
80 "wsr.ps {0}", 74 "wsr.ps {0}",
81 "rsync", in(reg) token) 75 "rsync", in(reg) token)
82 } else { 76 } else {
83 // waiti sets the PS.INTLEVEL when slipping into sleep 77 // waiti sets the PS.INTLEVEL when slipping into sleep
84 // because critical sections in Xtensa are implemented via increasing 78 // because critical sections in Xtensa are implemented via increasing
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index f3760f589..c1d82e18a 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -147,10 +147,7 @@ impl<F: Future + 'static> TaskStorage<F> {
147 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> { 147 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> {
148 let task = AvailableTask::claim(self); 148 let task = AvailableTask::claim(self);
149 match task { 149 match task {
150 Some(task) => { 150 Some(task) => task.initialize(future),
151 let task = task.initialize(future);
152 unsafe { SpawnToken::<F>::new(task) }
153 }
154 None => SpawnToken::new_failed(), 151 None => SpawnToken::new_failed(),
155 } 152 }
156 } 153 }
@@ -186,12 +183,16 @@ impl<F: Future + 'static> TaskStorage<F> {
186 } 183 }
187} 184}
188 185
189struct AvailableTask<F: Future + 'static> { 186/// An uninitialized [`TaskStorage`].
187pub struct AvailableTask<F: Future + 'static> {
190 task: &'static TaskStorage<F>, 188 task: &'static TaskStorage<F>,
191} 189}
192 190
193impl<F: Future + 'static> AvailableTask<F> { 191impl<F: Future + 'static> AvailableTask<F> {
194 fn claim(task: &'static TaskStorage<F>) -> Option<Self> { 192 /// Try to claim a [`TaskStorage`].
193 ///
194 /// This function returns `None` if a task has already been spawned and has not finished running.
195 pub fn claim(task: &'static TaskStorage<F>) -> Option<Self> {
195 task.raw 196 task.raw
196 .state 197 .state
197 .compare_exchange(0, STATE_SPAWNED | STATE_RUN_QUEUED, Ordering::AcqRel, Ordering::Acquire) 198 .compare_exchange(0, STATE_SPAWNED | STATE_RUN_QUEUED, Ordering::AcqRel, Ordering::Acquire)
@@ -199,61 +200,30 @@ impl<F: Future + 'static> AvailableTask<F> {
199 .map(|_| Self { task }) 200 .map(|_| Self { task })
200 } 201 }
201 202
202 fn initialize(self, future: impl FnOnce() -> F) -> TaskRef { 203 fn initialize_impl<S>(self, future: impl FnOnce() -> F) -> SpawnToken<S> {
203 unsafe { 204 unsafe {
204 self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll)); 205 self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll));
205 self.task.future.write(future()); 206 self.task.future.write(future());
206 }
207 TaskRef::new(self.task)
208 }
209}
210 207
211/// Raw storage that can hold up to N tasks of the same type. 208 let task = TaskRef::new(self.task);
212///
213/// This is essentially a `[TaskStorage<F>; N]`.
214pub struct TaskPool<F: Future + 'static, const N: usize> {
215 pool: [TaskStorage<F>; N],
216}
217 209
218impl<F: Future + 'static, const N: usize> TaskPool<F, N> { 210 SpawnToken::new(task)
219 /// Create a new TaskPool, with all tasks in non-spawned state.
220 pub const fn new() -> Self {
221 Self {
222 pool: [TaskStorage::NEW; N],
223 } 211 }
224 } 212 }
225 213
226 /// Try to spawn a task in the pool. 214 /// Initialize the [`TaskStorage`] to run the given future.
227 /// 215 pub fn initialize(self, future: impl FnOnce() -> F) -> SpawnToken<F> {
228 /// See [`TaskStorage::spawn()`] for details. 216 self.initialize_impl::<F>(future)
229 ///
230 /// This will loop over the pool and spawn the task in the first storage that
231 /// is currently free. If none is free, a "poisoned" SpawnToken is returned,
232 /// which will cause [`Spawner::spawn()`](super::Spawner::spawn) to return the error.
233 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> {
234 let task = self.pool.iter().find_map(AvailableTask::claim);
235 match task {
236 Some(task) => {
237 let task = task.initialize(future);
238 unsafe { SpawnToken::<F>::new(task) }
239 }
240 None => SpawnToken::new_failed(),
241 }
242 } 217 }
243 218
244 /// Like spawn(), but allows the task to be send-spawned if the args are Send even if 219 /// Initialize the [`TaskStorage`] to run the given future.
245 /// the future is !Send.
246 /// 220 ///
247 /// Not covered by semver guarantees. DO NOT call this directly. Intended to be used 221 /// # Safety
248 /// by the Embassy macros ONLY.
249 /// 222 ///
250 /// SAFETY: `future` must be a closure of the form `move || my_async_fn(args)`, where `my_async_fn` 223 /// `future` must be a closure of the form `move || my_async_fn(args)`, where `my_async_fn`
251 /// is an `async fn`, NOT a hand-written `Future`. 224 /// is an `async fn`, NOT a hand-written `Future`.
252 #[doc(hidden)] 225 #[doc(hidden)]
253 pub unsafe fn _spawn_async_fn<FutFn>(&'static self, future: FutFn) -> SpawnToken<impl Sized> 226 pub unsafe fn __initialize_async_fn<FutFn>(self, future: impl FnOnce() -> F) -> SpawnToken<FutFn> {
254 where
255 FutFn: FnOnce() -> F,
256 {
257 // When send-spawning a task, we construct the future in this thread, and effectively 227 // When send-spawning a task, we construct the future in this thread, and effectively
258 // "send" it to the executor thread by enqueuing it in its queue. Therefore, in theory, 228 // "send" it to the executor thread by enqueuing it in its queue. Therefore, in theory,
259 // send-spawning should require the future `F` to be `Send`. 229 // send-spawning should require the future `F` to be `Send`.
@@ -279,66 +249,73 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
279 // 249 //
280 // This ONLY holds for `async fn` futures. The other `spawn` methods can be called directly 250 // This ONLY holds for `async fn` futures. The other `spawn` methods can be called directly
281 // by the user, with arbitrary hand-implemented futures. This is why these return `SpawnToken<F>`. 251 // by the user, with arbitrary hand-implemented futures. This is why these return `SpawnToken<F>`.
282 252 self.initialize_impl::<FutFn>(future)
283 let task = self.pool.iter().find_map(AvailableTask::claim);
284 match task {
285 Some(task) => {
286 let task = task.initialize(future);
287 unsafe { SpawnToken::<FutFn>::new(task) }
288 }
289 None => SpawnToken::new_failed(),
290 }
291 } 253 }
292} 254}
293 255
294#[derive(Clone, Copy)] 256/// Raw storage that can hold up to N tasks of the same type.
295pub(crate) enum PenderInner { 257///
296 #[cfg(feature = "executor-thread")] 258/// This is essentially a `[TaskStorage<F>; N]`.
297 Thread(crate::arch::ThreadPender), 259pub struct TaskPool<F: Future + 'static, const N: usize> {
298 #[cfg(feature = "executor-interrupt")] 260 pool: [TaskStorage<F>; N],
299 Interrupt(crate::arch::InterruptPender),
300 #[cfg(feature = "pender-callback")]
301 Callback { func: fn(*mut ()), context: *mut () },
302} 261}
303 262
304unsafe impl Send for PenderInner {} 263impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
305unsafe impl Sync for PenderInner {} 264 /// Create a new TaskPool, with all tasks in non-spawned state.
265 pub const fn new() -> Self {
266 Self {
267 pool: [TaskStorage::NEW; N],
268 }
269 }
306 270
307/// Platform/architecture-specific action executed when an executor has pending work. 271 fn spawn_impl<T>(&'static self, future: impl FnOnce() -> F) -> SpawnToken<T> {
308/// 272 match self.pool.iter().find_map(AvailableTask::claim) {
309/// When a task within an executor is woken, the `Pender` is called. This does a 273 Some(task) => task.initialize_impl::<T>(future),
310/// platform/architecture-specific action to signal there is pending work in the executor. 274 None => SpawnToken::new_failed(),
311/// When this happens, you must arrange for [`Executor::poll`] to be called. 275 }
312/// 276 }
313/// You can think of it as a waker, but for the whole executor.
314pub struct Pender(pub(crate) PenderInner);
315 277
316impl Pender { 278 /// Try to spawn a task in the pool.
317 /// Create a `Pender` that will call an arbitrary function pointer. 279 ///
280 /// See [`TaskStorage::spawn()`] for details.
281 ///
282 /// This will loop over the pool and spawn the task in the first storage that
283 /// is currently free. If none is free, a "poisoned" SpawnToken is returned,
284 /// which will cause [`Spawner::spawn()`](super::Spawner::spawn) to return the error.
285 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> {
286 self.spawn_impl::<F>(future)
287 }
288
289 /// Like spawn(), but allows the task to be send-spawned if the args are Send even if
290 /// the future is !Send.
318 /// 291 ///
319 /// # Arguments 292 /// Not covered by semver guarantees. DO NOT call this directly. Intended to be used
293 /// by the Embassy macros ONLY.
320 /// 294 ///
321 /// - `func`: The function pointer to call. 295 /// SAFETY: `future` must be a closure of the form `move || my_async_fn(args)`, where `my_async_fn`
322 /// - `context`: Opaque context pointer, that will be passed to the function pointer. 296 /// is an `async fn`, NOT a hand-written `Future`.
323 #[cfg(feature = "pender-callback")] 297 #[doc(hidden)]
324 pub fn new_from_callback(func: fn(*mut ()), context: *mut ()) -> Self { 298 pub unsafe fn _spawn_async_fn<FutFn>(&'static self, future: FutFn) -> SpawnToken<impl Sized>
325 Self(PenderInner::Callback { 299 where
326 func, 300 FutFn: FnOnce() -> F,
327 context: context.into(), 301 {
328 }) 302 // See the comment in AvailableTask::__initialize_async_fn for explanation.
303 self.spawn_impl::<FutFn>(future)
329 } 304 }
330} 305}
331 306
307#[derive(Clone, Copy)]
308pub(crate) struct Pender(*mut ());
309
310unsafe impl Send for Pender {}
311unsafe impl Sync for Pender {}
312
332impl Pender { 313impl Pender {
333 pub(crate) fn pend(&self) { 314 pub(crate) fn pend(self) {
334 match self.0 { 315 extern "Rust" {
335 #[cfg(feature = "executor-thread")] 316 fn __pender(context: *mut ());
336 PenderInner::Thread(x) => x.pend(),
337 #[cfg(feature = "executor-interrupt")]
338 PenderInner::Interrupt(x) => x.pend(),
339 #[cfg(feature = "pender-callback")]
340 PenderInner::Callback { func, context } => func(context),
341 } 317 }
318 unsafe { __pender(self.0) };
342 } 319 }
343} 320}
344 321
@@ -409,7 +386,7 @@ impl SyncExecutor {
409 #[allow(clippy::never_loop)] 386 #[allow(clippy::never_loop)]
410 loop { 387 loop {
411 #[cfg(feature = "integrated-timers")] 388 #[cfg(feature = "integrated-timers")]
412 self.timer_queue.dequeue_expired(Instant::now(), |task| wake_task(task)); 389 self.timer_queue.dequeue_expired(Instant::now(), wake_task_no_pend);
413 390
414 self.run_queue.dequeue_all(|p| { 391 self.run_queue.dequeue_all(|p| {
415 let task = p.header(); 392 let task = p.header();
@@ -472,15 +449,31 @@ impl SyncExecutor {
472/// 449///
473/// - To get the executor to do work, call `poll()`. This will poll all queued tasks (all tasks 450/// - To get the executor to do work, call `poll()`. This will poll all queued tasks (all tasks
474/// that "want to run"). 451/// that "want to run").
475/// - You must supply a [`Pender`]. The executor will call it to notify you it has work 452/// - You must supply a pender function, as shown below. The executor will call it to notify you
476/// to do. You must arrange for `poll()` to be called as soon as possible. 453/// it has work to do. You must arrange for `poll()` to be called as soon as possible.
454/// - Enabling `arch-xx` features will define a pender function for you. This means that you
455/// are limited to using the executors provided to you by the architecture/platform
456/// implementation. If you need a different executor, you must not enable `arch-xx` features.
477/// 457///
478/// The [`Pender`] can be called from *any* context: any thread, any interrupt priority 458/// The pender can be called from *any* context: any thread, any interrupt priority
479/// level, etc. It may be called synchronously from any `Executor` method call as well. 459/// level, etc. It may be called synchronously from any `Executor` method call as well.
480/// You must deal with this correctly. 460/// You must deal with this correctly.
481/// 461///
482/// In particular, you must NOT call `poll` directly from the pender callback, as this violates 462/// In particular, you must NOT call `poll` directly from the pender callback, as this violates
483/// the requirement for `poll` to not be called reentrantly. 463/// the requirement for `poll` to not be called reentrantly.
464///
465/// The pender function must be exported with the name `__pender` and have the following signature:
466///
467/// ```rust
468/// #[export_name = "__pender"]
469/// fn pender(context: *mut ()) {
470/// // schedule `poll()` to be called
471/// }
472/// ```
473///
474/// The `context` argument is a piece of arbitrary data the executor will pass to the pender.
475/// You can set the `context` when calling [`Executor::new()`]. You can use it to, for example,
476/// differentiate between executors, or to pass a pointer to a callback that should be called.
484#[repr(transparent)] 477#[repr(transparent)]
485pub struct Executor { 478pub struct Executor {
486 pub(crate) inner: SyncExecutor, 479 pub(crate) inner: SyncExecutor,
@@ -495,12 +488,12 @@ impl Executor {
495 488
496 /// Create a new executor. 489 /// Create a new executor.
497 /// 490 ///
498 /// When the executor has work to do, it will call the [`Pender`]. 491 /// When the executor has work to do, it will call the pender function and pass `context` to it.
499 /// 492 ///
500 /// See [`Executor`] docs for details on `Pender`. 493 /// See [`Executor`] docs for details on the pender.
501 pub fn new(pender: Pender) -> Self { 494 pub fn new(context: *mut ()) -> Self {
502 Self { 495 Self {
503 inner: SyncExecutor::new(pender), 496 inner: SyncExecutor::new(Pender(context)),
504 _not_sync: PhantomData, 497 _not_sync: PhantomData,
505 } 498 }
506 } 499 }
@@ -523,16 +516,16 @@ impl Executor {
523 /// This loops over all tasks that are queued to be polled (i.e. they're 516 /// This loops over all tasks that are queued to be polled (i.e. they're
524 /// freshly spawned or they've been woken). Other tasks are not polled. 517 /// freshly spawned or they've been woken). Other tasks are not polled.
525 /// 518 ///
526 /// You must call `poll` after receiving a call to the [`Pender`]. It is OK 519 /// You must call `poll` after receiving a call to the pender. It is OK
527 /// to call `poll` even when not requested by the `Pender`, but it wastes 520 /// to call `poll` even when not requested by the pender, but it wastes
528 /// energy. 521 /// energy.
529 /// 522 ///
530 /// # Safety 523 /// # Safety
531 /// 524 ///
532 /// You must NOT call `poll` reentrantly on the same executor. 525 /// You must NOT call `poll` reentrantly on the same executor.
533 /// 526 ///
534 /// In particular, note that `poll` may call the `Pender` synchronously. Therefore, you 527 /// In particular, note that `poll` may call the pender synchronously. Therefore, you
535 /// must NOT directly call `poll()` from the `Pender` callback. Instead, the callback has to 528 /// must NOT directly call `poll()` from the pender callback. Instead, the callback has to
536 /// somehow schedule for `poll()` to be called later, at a time you know for sure there's 529 /// somehow schedule for `poll()` to be called later, at a time you know for sure there's
537 /// no `poll()` already running. 530 /// no `poll()` already running.
538 pub unsafe fn poll(&'static self) { 531 pub unsafe fn poll(&'static self) {
@@ -573,6 +566,31 @@ pub fn wake_task(task: TaskRef) {
573 } 566 }
574} 567}
575 568
569/// Wake a task by `TaskRef` without calling pend.
570///
571/// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`].
572pub fn wake_task_no_pend(task: TaskRef) {
573 let header = task.header();
574
575 let res = header.state.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| {
576 // If already scheduled, or if not started,
577 if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) {
578 None
579 } else {
580 // Mark it as scheduled
581 Some(state | STATE_RUN_QUEUED)
582 }
583 });
584
585 if res.is_ok() {
586 // We have just marked the task as scheduled, so enqueue it.
587 unsafe {
588 let executor = header.executor.get().unwrap_unchecked();
589 executor.run_queue.enqueue(task);
590 }
591 }
592}
593
576#[cfg(feature = "integrated-timers")] 594#[cfg(feature = "integrated-timers")]
577struct TimerQueue; 595struct TimerQueue;
578 596
diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs
index 2b6224045..5a3a0dee1 100644
--- a/embassy-executor/src/spawner.rs
+++ b/embassy-executor/src/spawner.rs
@@ -33,7 +33,8 @@ impl<S> SpawnToken<S> {
33 } 33 }
34 } 34 }
35 35
36 pub(crate) fn new_failed() -> Self { 36 /// Return a SpawnToken that represents a failed spawn.
37 pub fn new_failed() -> Self {
37 Self { 38 Self {
38 raw_task: None, 39 raw_task: None,
39 phantom: PhantomData, 40 phantom: PhantomData,
diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml
index 402ad2d70..feea06582 100644
--- a/embassy-lora/Cargo.toml
+++ b/embassy-lora/Cargo.toml
@@ -23,9 +23,12 @@ log = { version = "0.4.14", optional = true }
23embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true } 23embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true }
24embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 24embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
25embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } 25embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true }
26embedded-hal-async = { version = "=0.2.0-alpha.2" } 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 = "1" }
31lorawan-device = { version = "0.10.0", default-features = false, features = ["async"], optional = true } 31lorawan-device = { version = "0.10.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-net-driver-channel/README.md b/embassy-net-driver-channel/README.md
index dd90e7ad2..8f904ce95 100644
--- a/embassy-net-driver-channel/README.md
+++ b/embassy-net-driver-channel/README.md
@@ -76,7 +76,7 @@ These `embassy-net` drivers are implemented using this crate. You can look at th
76 76
77- [`cyw43`](https://github.com/embassy-rs/embassy/tree/main/cyw43) for WiFi on CYW43xx chips, used in the Raspberry Pi Pico W 77- [`cyw43`](https://github.com/embassy-rs/embassy/tree/main/cyw43) for WiFi on CYW43xx chips, used in the Raspberry Pi Pico W
78- [`embassy-usb`](https://github.com/embassy-rs/embassy/tree/main/embassy-usb) for Ethernet-over-USB (CDC NCM) support. 78- [`embassy-usb`](https://github.com/embassy-rs/embassy/tree/main/embassy-usb) for Ethernet-over-USB (CDC NCM) support.
79- [`embassy-net-w5500`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-w5500) for Wiznet W5500 SPI Ethernet MAC+PHY chip. 79- [`embassy-net-wiznet`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-wiznet) for Wiznet SPI Ethernet MAC+PHY chips.
80- [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU. 80- [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU.
81 81
82 82
diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml
new file mode 100644
index 000000000..e02c984e9
--- /dev/null
+++ b/embassy-net-enc28j60/Cargo.toml
@@ -0,0 +1,23 @@
1[package]
2name = "embassy-net-enc28j60"
3version = "0.1.0"
4description = "embassy-net driver for the ENC28J60 ethernet chip"
5keywords = ["embedded", "enc28j60", "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[dependencies]
11embedded-hal = { 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" }
14embassy-time = { version = "0.1.2", path = "../embassy-time" }
15embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
16
17defmt = { version = "0.3", optional = true }
18log = { version = "0.4.14", optional = true }
19
20[package.metadata.embassy_docs]
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/"
23target = "thumbv7em-none-eabi" \ No newline at end of file
diff --git a/embassy-net-enc28j60/README.md b/embassy-net-enc28j60/README.md
new file mode 100644
index 000000000..39011ca13
--- /dev/null
+++ b/embassy-net-enc28j60/README.md
@@ -0,0 +1,19 @@
1# `embassy-net-enc28j60`
2
3[`embassy-net`](https://crates.io/crates/embassy-net) integration for the Microchip ENC28J60 Ethernet chip.
4
5Based on [@japaric](https://github.com/japaric)'s [`enc28j60`](https://github.com/japaric/enc28j60) crate.
6
7## Interoperability
8
9This crate can run on any executor.
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-enc28j60/src/bank0.rs b/embassy-net-enc28j60/src/bank0.rs
new file mode 100644
index 000000000..1c1b3a7f6
--- /dev/null
+++ b/embassy-net-enc28j60/src/bank0.rs
@@ -0,0 +1,69 @@
1#[allow(dead_code)]
2#[derive(Clone, Copy)]
3pub enum Register {
4 ERDPTL = 0x00,
5 ERDPTH = 0x01,
6 EWRPTL = 0x02,
7 EWRPTH = 0x03,
8 ETXSTL = 0x04,
9 ETXSTH = 0x05,
10 ETXNDL = 0x06,
11 ETXNDH = 0x07,
12 ERXSTL = 0x08,
13 ERXSTH = 0x09,
14 ERXNDL = 0x0a,
15 ERXNDH = 0x0b,
16 ERXRDPTL = 0x0c,
17 ERXRDPTH = 0x0d,
18 ERXWRPTL = 0x0e,
19 ERXWRPTH = 0x0f,
20 EDMASTL = 0x10,
21 EDMASTH = 0x11,
22 EDMANDL = 0x12,
23 EDMANDH = 0x13,
24 EDMADSTL = 0x14,
25 EDMADSTH = 0x15,
26 EDMACSL = 0x16,
27 EDMACSH = 0x17,
28}
29
30impl Register {
31 pub(crate) fn addr(&self) -> u8 {
32 *self as u8
33 }
34
35 pub(crate) fn is_eth_register(&self) -> bool {
36 match *self {
37 Register::ERDPTL => true,
38 Register::ERDPTH => true,
39 Register::EWRPTL => true,
40 Register::EWRPTH => true,
41 Register::ETXSTL => true,
42 Register::ETXSTH => true,
43 Register::ETXNDL => true,
44 Register::ETXNDH => true,
45 Register::ERXSTL => true,
46 Register::ERXSTH => true,
47 Register::ERXNDL => true,
48 Register::ERXNDH => true,
49 Register::ERXRDPTL => true,
50 Register::ERXRDPTH => true,
51 Register::ERXWRPTL => true,
52 Register::ERXWRPTH => true,
53 Register::EDMASTL => true,
54 Register::EDMASTH => true,
55 Register::EDMANDL => true,
56 Register::EDMANDH => true,
57 Register::EDMADSTL => true,
58 Register::EDMADSTH => true,
59 Register::EDMACSL => true,
60 Register::EDMACSH => true,
61 }
62 }
63}
64
65impl Into<super::Register> for Register {
66 fn into(self) -> super::Register {
67 super::Register::Bank0(self)
68 }
69}
diff --git a/embassy-net-enc28j60/src/bank1.rs b/embassy-net-enc28j60/src/bank1.rs
new file mode 100644
index 000000000..30560edf6
--- /dev/null
+++ b/embassy-net-enc28j60/src/bank1.rs
@@ -0,0 +1,84 @@
1#[allow(dead_code)]
2#[derive(Clone, Copy)]
3pub enum Register {
4 EHT0 = 0x00,
5 EHT1 = 0x01,
6 EHT2 = 0x02,
7 EHT3 = 0x03,
8 EHT4 = 0x04,
9 EHT5 = 0x05,
10 EHT6 = 0x06,
11 EHT7 = 0x07,
12 EPMM0 = 0x08,
13 EPMM1 = 0x09,
14 EPMM2 = 0x0a,
15 EPMM3 = 0x0b,
16 EPMM4 = 0x0c,
17 EPMM5 = 0x0d,
18 EPMM6 = 0x0e,
19 EPMM7 = 0x0f,
20 EPMCSL = 0x10,
21 EPMCSH = 0x11,
22 EPMOL = 0x14,
23 EPMOH = 0x15,
24 ERXFCON = 0x18,
25 EPKTCNT = 0x19,
26}
27
28impl Register {
29 pub(crate) fn addr(&self) -> u8 {
30 *self as u8
31 }
32
33 pub(crate) fn is_eth_register(&self) -> bool {
34 match *self {
35 Register::EHT0 => true,
36 Register::EHT1 => true,
37 Register::EHT2 => true,
38 Register::EHT3 => true,
39 Register::EHT4 => true,
40 Register::EHT5 => true,
41 Register::EHT6 => true,
42 Register::EHT7 => true,
43 Register::EPMM0 => true,
44 Register::EPMM1 => true,
45 Register::EPMM2 => true,
46 Register::EPMM3 => true,
47 Register::EPMM4 => true,
48 Register::EPMM5 => true,
49 Register::EPMM6 => true,
50 Register::EPMM7 => true,
51 Register::EPMCSL => true,
52 Register::EPMCSH => true,
53 Register::EPMOL => true,
54 Register::EPMOH => true,
55 Register::ERXFCON => true,
56 Register::EPKTCNT => true,
57 }
58 }
59}
60
61impl Into<super::Register> for Register {
62 fn into(self) -> super::Register {
63 super::Register::Bank1(self)
64 }
65}
66
67register!(ERXFCON, 0b1010_0001, u8, {
68 #[doc = "Broadcast Filter Enable bit"]
69 bcen @ 0,
70 #[doc = "Multicast Filter Enable bit"]
71 mcen @ 1,
72 #[doc = "Hash Table Filter Enable bit"]
73 hten @ 2,
74 #[doc = "Magic Packetâ„¢ Filter Enable bit"]
75 mpen @ 3,
76 #[doc = "Pattern Match Filter Enable bit"]
77 pmen @ 4,
78 #[doc = "Post-Filter CRC Check Enable bit"]
79 crcen @ 5,
80 #[doc = "AND/OR Filter Select bit"]
81 andor @ 6,
82 #[doc = "Unicast Filter Enable bit"]
83 ucen @ 7,
84});
diff --git a/embassy-net-enc28j60/src/bank2.rs b/embassy-net-enc28j60/src/bank2.rs
new file mode 100644
index 000000000..74a1d245f
--- /dev/null
+++ b/embassy-net-enc28j60/src/bank2.rs
@@ -0,0 +1,86 @@
1#[allow(dead_code)]
2#[derive(Clone, Copy)]
3pub enum Register {
4 MACON1 = 0x00,
5 MACON3 = 0x02,
6 MACON4 = 0x03,
7 MABBIPG = 0x04,
8 MAIPGL = 0x06,
9 MAIPGH = 0x07,
10 MACLCON1 = 0x08,
11 MACLCON2 = 0x09,
12 MAMXFLL = 0x0a,
13 MAMXFLH = 0x0b,
14 MICMD = 0x12,
15 MIREGADR = 0x14,
16 MIWRL = 0x16,
17 MIWRH = 0x17,
18 MIRDL = 0x18,
19 MIRDH = 0x19,
20}
21
22impl Register {
23 pub(crate) fn addr(&self) -> u8 {
24 *self as u8
25 }
26
27 pub(crate) fn is_eth_register(&self) -> bool {
28 match *self {
29 Register::MACON1 => false,
30 Register::MACON3 => false,
31 Register::MACON4 => false,
32 Register::MABBIPG => false,
33 Register::MAIPGL => false,
34 Register::MAIPGH => false,
35 Register::MACLCON1 => false,
36 Register::MACLCON2 => false,
37 Register::MAMXFLL => false,
38 Register::MAMXFLH => false,
39 Register::MICMD => false,
40 Register::MIREGADR => false,
41 Register::MIWRL => false,
42 Register::MIWRH => false,
43 Register::MIRDL => false,
44 Register::MIRDH => false,
45 }
46 }
47}
48
49impl Into<super::Register> for Register {
50 fn into(self) -> super::Register {
51 super::Register::Bank2(self)
52 }
53}
54
55register!(MACON1, 0, u8, {
56 #[doc = "Enable packets to be received by the MAC"]
57 marxen @ 0,
58 #[doc = "Control frames will be discarded after being processed by the MAC"]
59 passall @ 1,
60 #[doc = "Inhibit transmissions when pause control frames are received"]
61 rxpaus @ 2,
62 #[doc = "Allow the MAC to transmit pause control frames"]
63 txpaus @ 3,
64});
65
66register!(MACON3, 0, u8, {
67 #[doc = "MAC will operate in Full-Duplex mode"]
68 fuldpx @ 0,
69 #[doc = "The type/length field of transmitted and received frames will be checked"]
70 frmlnen @ 1,
71 #[doc = "Frames bigger than MAMXFL will be aborted when transmitted or received"]
72 hfrmen @ 2,
73 #[doc = "No proprietary header is present"]
74 phdren @ 3,
75 #[doc = "MAC will append a valid CRC to all frames transmitted regardless of PADCFG bit"]
76 txcrcen @ 4,
77 #[doc = "All short frames will be zero-padded to 64 bytes and a valid CRC will then be appended"]
78 padcfg @ 5..7,
79});
80
81register!(MICMD, 0, u8, {
82 #[doc = "MII Read Enable bit"]
83 miird @ 0,
84 #[doc = "MII Scan Enable bit"]
85 miiscan @ 1,
86});
diff --git a/embassy-net-enc28j60/src/bank3.rs b/embassy-net-enc28j60/src/bank3.rs
new file mode 100644
index 000000000..4f7eb9406
--- /dev/null
+++ b/embassy-net-enc28j60/src/bank3.rs
@@ -0,0 +1,53 @@
1#[allow(dead_code)]
2#[derive(Clone, Copy)]
3pub enum Register {
4 MAADR5 = 0x00,
5 MAADR6 = 0x01,
6 MAADR3 = 0x02,
7 MAADR4 = 0x03,
8 MAADR1 = 0x04,
9 MAADR2 = 0x05,
10 EBSTSD = 0x06,
11 EBSTCON = 0x07,
12 EBSTCSL = 0x08,
13 EBSTCSH = 0x09,
14 MISTAT = 0x0a,
15 EREVID = 0x12,
16 ECOCON = 0x15,
17 EFLOCON = 0x17,
18 EPAUSL = 0x18,
19 EPAUSH = 0x19,
20}
21
22impl Register {
23 pub(crate) fn addr(&self) -> u8 {
24 *self as u8
25 }
26
27 pub(crate) fn is_eth_register(&self) -> bool {
28 match *self {
29 Register::MAADR5 => false,
30 Register::MAADR6 => false,
31 Register::MAADR3 => false,
32 Register::MAADR4 => false,
33 Register::MAADR1 => false,
34 Register::MAADR2 => false,
35 Register::EBSTSD => true,
36 Register::EBSTCON => true,
37 Register::EBSTCSL => true,
38 Register::EBSTCSH => true,
39 Register::MISTAT => false,
40 Register::EREVID => true,
41 Register::ECOCON => true,
42 Register::EFLOCON => true,
43 Register::EPAUSL => true,
44 Register::EPAUSH => true,
45 }
46 }
47}
48
49impl Into<super::Register> for Register {
50 fn into(self) -> super::Register {
51 super::Register::Bank3(self)
52 }
53}
diff --git a/embassy-net-enc28j60/src/common.rs b/embassy-net-enc28j60/src/common.rs
new file mode 100644
index 000000000..ef339dd2a
--- /dev/null
+++ b/embassy-net-enc28j60/src/common.rs
@@ -0,0 +1,106 @@
1#[allow(dead_code)]
2#[derive(Clone, Copy)]
3pub enum Register {
4 ECON1 = 0x1f,
5 ECON2 = 0x1e,
6 EIE = 0x1b,
7 EIR = 0x1c,
8 ESTAT = 0x1d,
9}
10
11impl Register {
12 pub(crate) fn addr(&self) -> u8 {
13 *self as u8
14 }
15
16 pub(crate) fn is_eth_register(&self) -> bool {
17 match *self {
18 Register::ECON1 => true,
19 Register::ECON2 => true,
20 Register::EIE => true,
21 Register::EIR => true,
22 Register::ESTAT => true,
23 }
24 }
25}
26
27impl Into<super::Register> for Register {
28 fn into(self) -> super::Register {
29 super::Register::Common(self)
30 }
31}
32
33register!(EIE, 0, u8, {
34 #[doc = "Receive Error Interrupt Enable bit"]
35 rxerie @ 0,
36 #[doc = "Transmit Error Interrupt Enable bit"]
37 txerie @ 1,
38 #[doc = "Transmit Enable bit"]
39 txie @ 3,
40 #[doc = "Link Status Change Interrupt Enable bit"]
41 linkie @ 4,
42 #[doc = "DMA Interrupt Enable bit"]
43 dmaie @ 5,
44 #[doc = "Receive Packet Pending Interrupt Enable bit"]
45 pktie @ 6,
46 #[doc = "Global INT Interrupt Enable bit"]
47 intie @ 7,
48});
49
50register!(EIR, 0, u8, {
51 #[doc = "Receive Error Interrupt Flag bit"]
52 rxerif @ 0,
53 #[doc = "Transmit Error Interrupt Flag bit"]
54 txerif @ 1,
55 #[doc = "Transmit Interrupt Flag bit"]
56 txif @ 3,
57 #[doc = "Link Change Interrupt Flag bit"]
58 linkif @ 4,
59 #[doc = "DMA Interrupt Flag bit"]
60 dmaif @ 5,
61 #[doc = "Receive Packet Pending Interrupt Flag bit"]
62 pktif @ 6,
63});
64
65register!(ESTAT, 0, u8, {
66 #[doc = "Clock Ready bit"]
67 clkrdy @ 0,
68 #[doc = "Transmit Abort Error bit"]
69 txabrt @ 1,
70 #[doc = "Receive Busy bit"]
71 rxbusy @ 2,
72 #[doc = "Late Collision Error bit"]
73 latecol @ 4,
74 #[doc = "Ethernet Buffer Error Status bit"]
75 bufer @ 6,
76 #[doc = "INT Interrupt Flag bit"]
77 int @ 7,
78});
79
80register!(ECON2, 0b1000_0000, u8, {
81 #[doc = "Voltage Regulator Power Save Enable bit"]
82 vrps @ 3,
83 #[doc = "Power Save Enable bit"]
84 pwrsv @ 5,
85 #[doc = "Packet Decrement bit"]
86 pktdec @ 6,
87 #[doc = "Automatic Buffer Pointer Increment Enable bit"]
88 autoinc @ 7,
89});
90
91register!(ECON1, 0, u8, {
92 #[doc = "Bank Select bits"]
93 bsel @ 0..1,
94 #[doc = "Receive Enable bi"]
95 rxen @ 2,
96 #[doc = "Transmit Request to Send bit"]
97 txrts @ 3,
98 #[doc = "DMA Checksum Enable bit"]
99 csumen @ 4,
100 #[doc = "DMA Start and Busy Status bit"]
101 dmast @ 5,
102 #[doc = "Receive Logic Reset bit"]
103 rxrst @ 6,
104 #[doc = "Transmit Logic Reset bit"]
105 txrst @ 7,
106});
diff --git a/embassy-net-enc28j60/src/fmt.rs b/embassy-net-enc28j60/src/fmt.rs
new file mode 100644
index 000000000..066970813
--- /dev/null
+++ b/embassy-net-enc28j60/src/fmt.rs
@@ -0,0 +1,225 @@
1#![macro_use]
2#![allow(unused_macros)]
3
4#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features.");
6
7macro_rules! assert {
8 ($($x:tt)*) => {
9 {
10 #[cfg(not(feature = "defmt"))]
11 ::core::assert!($($x)*);
12 #[cfg(feature = "defmt")]
13 ::defmt::assert!($($x)*);
14 }
15 };
16}
17
18macro_rules! assert_eq {
19 ($($x:tt)*) => {
20 {
21 #[cfg(not(feature = "defmt"))]
22 ::core::assert_eq!($($x)*);
23 #[cfg(feature = "defmt")]
24 ::defmt::assert_eq!($($x)*);
25 }
26 };
27}
28
29macro_rules! assert_ne {
30 ($($x:tt)*) => {
31 {
32 #[cfg(not(feature = "defmt"))]
33 ::core::assert_ne!($($x)*);
34 #[cfg(feature = "defmt")]
35 ::defmt::assert_ne!($($x)*);
36 }
37 };
38}
39
40macro_rules! debug_assert {
41 ($($x:tt)*) => {
42 {
43 #[cfg(not(feature = "defmt"))]
44 ::core::debug_assert!($($x)*);
45 #[cfg(feature = "defmt")]
46 ::defmt::debug_assert!($($x)*);
47 }
48 };
49}
50
51macro_rules! debug_assert_eq {
52 ($($x:tt)*) => {
53 {
54 #[cfg(not(feature = "defmt"))]
55 ::core::debug_assert_eq!($($x)*);
56 #[cfg(feature = "defmt")]
57 ::defmt::debug_assert_eq!($($x)*);
58 }
59 };
60}
61
62macro_rules! debug_assert_ne {
63 ($($x:tt)*) => {
64 {
65 #[cfg(not(feature = "defmt"))]
66 ::core::debug_assert_ne!($($x)*);
67 #[cfg(feature = "defmt")]
68 ::defmt::debug_assert_ne!($($x)*);
69 }
70 };
71}
72
73macro_rules! todo {
74 ($($x:tt)*) => {
75 {
76 #[cfg(not(feature = "defmt"))]
77 ::core::todo!($($x)*);
78 #[cfg(feature = "defmt")]
79 ::defmt::todo!($($x)*);
80 }
81 };
82}
83
84macro_rules! unreachable {
85 ($($x:tt)*) => {
86 {
87 #[cfg(not(feature = "defmt"))]
88 ::core::unreachable!($($x)*);
89 #[cfg(feature = "defmt")]
90 ::defmt::unreachable!($($x)*);
91 }
92 };
93}
94
95macro_rules! panic {
96 ($($x:tt)*) => {
97 {
98 #[cfg(not(feature = "defmt"))]
99 ::core::panic!($($x)*);
100 #[cfg(feature = "defmt")]
101 ::defmt::panic!($($x)*);
102 }
103 };
104}
105
106macro_rules! trace {
107 ($s:literal $(, $x:expr)* $(,)?) => {
108 {
109 #[cfg(feature = "log")]
110 ::log::trace!($s $(, $x)*);
111 #[cfg(feature = "defmt")]
112 ::defmt::trace!($s $(, $x)*);
113 #[cfg(not(any(feature = "log", feature="defmt")))]
114 let _ = ($( & $x ),*);
115 }
116 };
117}
118
119macro_rules! debug {
120 ($s:literal $(, $x:expr)* $(,)?) => {
121 {
122 #[cfg(feature = "log")]
123 ::log::debug!($s $(, $x)*);
124 #[cfg(feature = "defmt")]
125 ::defmt::debug!($s $(, $x)*);
126 #[cfg(not(any(feature = "log", feature="defmt")))]
127 let _ = ($( & $x ),*);
128 }
129 };
130}
131
132macro_rules! info {
133 ($s:literal $(, $x:expr)* $(,)?) => {
134 {
135 #[cfg(feature = "log")]
136 ::log::info!($s $(, $x)*);
137 #[cfg(feature = "defmt")]
138 ::defmt::info!($s $(, $x)*);
139 #[cfg(not(any(feature = "log", feature="defmt")))]
140 let _ = ($( & $x ),*);
141 }
142 };
143}
144
145macro_rules! warn {
146 ($s:literal $(, $x:expr)* $(,)?) => {
147 {
148 #[cfg(feature = "log")]
149 ::log::warn!($s $(, $x)*);
150 #[cfg(feature = "defmt")]
151 ::defmt::warn!($s $(, $x)*);
152 #[cfg(not(any(feature = "log", feature="defmt")))]
153 let _ = ($( & $x ),*);
154 }
155 };
156}
157
158macro_rules! error {
159 ($s:literal $(, $x:expr)* $(,)?) => {
160 {
161 #[cfg(feature = "log")]
162 ::log::error!($s $(, $x)*);
163 #[cfg(feature = "defmt")]
164 ::defmt::error!($s $(, $x)*);
165 #[cfg(not(any(feature = "log", feature="defmt")))]
166 let _ = ($( & $x ),*);
167 }
168 };
169}
170
171#[cfg(feature = "defmt")]
172macro_rules! unwrap {
173 ($($x:tt)*) => {
174 ::defmt::unwrap!($($x)*)
175 };
176}
177
178#[cfg(not(feature = "defmt"))]
179macro_rules! unwrap {
180 ($arg:expr) => {
181 match $crate::fmt::Try::into_result($arg) {
182 ::core::result::Result::Ok(t) => t,
183 ::core::result::Result::Err(e) => {
184 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
185 }
186 }
187 };
188 ($arg:expr, $($msg:expr),+ $(,)? ) => {
189 match $crate::fmt::Try::into_result($arg) {
190 ::core::result::Result::Ok(t) => t,
191 ::core::result::Result::Err(e) => {
192 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
193 }
194 }
195 }
196}
197
198#[derive(Debug, Copy, Clone, Eq, PartialEq)]
199pub struct NoneError;
200
201pub trait Try {
202 type Ok;
203 type Error;
204 fn into_result(self) -> Result<Self::Ok, Self::Error>;
205}
206
207impl<T> Try for Option<T> {
208 type Ok = T;
209 type Error = NoneError;
210
211 #[inline]
212 fn into_result(self) -> Result<T, NoneError> {
213 self.ok_or(NoneError)
214 }
215}
216
217impl<T, E> Try for Result<T, E> {
218 type Ok = T;
219 type Error = E;
220
221 #[inline]
222 fn into_result(self) -> Self {
223 self
224 }
225}
diff --git a/embassy-net-enc28j60/src/header.rs b/embassy-net-enc28j60/src/header.rs
new file mode 100644
index 000000000..c2d4e468f
--- /dev/null
+++ b/embassy-net-enc28j60/src/header.rs
@@ -0,0 +1,30 @@
1register!(RxStatus, 0, u32, {
2 #[doc = "Indicates length of the received frame"]
3 byte_count @ 0..15,
4 #[doc = "Indicates a packet over 50,000 bit times occurred or that a packet was dropped since the last receive"]
5 long_event @ 16,
6 #[doc = "Indicates that at some time since the last receive, a carrier event was detected"]
7 carrier_event @ 18,
8 #[doc = "Indicates that frame CRC field value does not match the CRC calculated by the MAC"]
9 crc_error @ 20,
10 #[doc = "Indicates that frame length field value in the packet does not match the actual data byte length and specifies a valid length"]
11 length_check_error @ 21,
12 #[doc = "Indicates that frame type/length field was larger than 1500 bytes (type field)"]
13 length_out_of_range @ 22,
14 #[doc = "Indicates that at the packet had a valid CRC and no symbol errors"]
15 received_ok @ 23,
16 #[doc = "Indicates packet received had a valid Multicast address"]
17 multicast @ 24,
18 #[doc = "Indicates packet received had a valid Broadcast address."]
19 broadcast @ 25,
20 #[doc = "Indicates that after the end of this packet, an additional 1 to 7 bits were received"]
21 dribble_nibble @ 26,
22 #[doc = "Current frame was recognized as a control frame for having a valid type/length designating it as a control frame"]
23 receive_control_frame @ 27,
24 #[doc = "Current frame was recognized as a control frame containing a valid pause frame opcode and a valid destination address"]
25 receive_pause_control_frame @ 28,
26 #[doc = "Current frame was recognized as a control frame but it contained an unknown opcode"]
27 receive_unknown_opcode @ 29,
28 #[doc = "Current frame was recognized as a VLAN tagged frame"]
29 receive_vlan_type_detected @ 30,
30});
diff --git a/embassy-net-enc28j60/src/lib.rs b/embassy-net-enc28j60/src/lib.rs
new file mode 100644
index 000000000..b44cefaf2
--- /dev/null
+++ b/embassy-net-enc28j60/src/lib.rs
@@ -0,0 +1,717 @@
1#![no_std]
2#![doc = include_str!("../README.md")]
3#![warn(missing_docs)]
4
5// must go first.
6mod fmt;
7
8#[macro_use]
9mod macros;
10mod bank0;
11mod bank1;
12mod bank2;
13mod bank3;
14mod common;
15mod header;
16mod phy;
17mod traits;
18
19use core::cmp;
20use core::convert::TryInto;
21
22use embassy_net_driver::{Capabilities, HardwareAddress, LinkState, Medium};
23use embassy_time::Duration;
24use embedded_hal::digital::OutputPin;
25use embedded_hal::spi::{Operation, SpiDevice};
26use traits::U16Ext;
27
28// Total buffer size (see section 3.2)
29const BUF_SZ: u16 = 8 * 1024;
30
31// Maximum frame length
32const MAX_FRAME_LENGTH: u16 = 1518; // value recommended in the data sheet
33
34// Size of the Frame check sequence (32-bit CRC)
35const CRC_SZ: u16 = 4;
36
37// define the boundaries of the TX and RX buffers
38// to workaround errata #5 we do the opposite of what section 6.1 of the data sheet
39// says: we place the RX buffer at address 0 and the TX buffer after it
40const RXST: u16 = 0x0000;
41const RXND: u16 = 0x19ff;
42const TXST: u16 = 0x1a00;
43const _TXND: u16 = 0x1fff;
44
45const MTU: usize = 1514; // 1500 IP + 14 ethernet header
46
47/// ENC28J60 embassy-net driver
48pub struct Enc28j60<S, O> {
49 mac_addr: [u8; 6],
50
51 spi: S,
52 rst: Option<O>,
53
54 bank: Bank,
55
56 // address of the next packet in buffer memory
57 next_packet: u16,
58}
59
60impl<S, O> Enc28j60<S, O>
61where
62 S: SpiDevice,
63 O: OutputPin,
64{
65 /// Create a new ENC28J60 driver instance.
66 ///
67 /// The RST pin is optional. If None, reset will be done with a SPI
68 /// soft reset command, instead of via the RST pin.
69 pub fn new(spi: S, rst: Option<O>, mac_addr: [u8; 6]) -> Self {
70 let mut res = Self {
71 mac_addr,
72 spi,
73 rst,
74
75 bank: Bank::Bank0,
76 next_packet: RXST,
77 };
78 res.init();
79 res
80 }
81
82 fn init(&mut self) {
83 if let Some(rst) = &mut self.rst {
84 rst.set_low().unwrap();
85 embassy_time::block_for(Duration::from_millis(5));
86 rst.set_high().unwrap();
87 embassy_time::block_for(Duration::from_millis(5));
88 } else {
89 embassy_time::block_for(Duration::from_millis(5));
90 self.soft_reset();
91 embassy_time::block_for(Duration::from_millis(5));
92 }
93
94 debug!(
95 "enc28j60: erevid {=u8:x}",
96 self.read_control_register(bank3::Register::EREVID)
97 );
98 debug!("enc28j60: waiting for clk");
99 while common::ESTAT(self.read_control_register(common::Register::ESTAT)).clkrdy() == 0 {}
100 debug!("enc28j60: clk ok");
101
102 if self.read_control_register(bank3::Register::EREVID) == 0 {
103 panic!("ErevidIsZero");
104 }
105
106 // disable CLKOUT output
107 self.write_control_register(bank3::Register::ECOCON, 0);
108
109 self.init_rx();
110
111 // TX start
112 // "It is recommended that an even address be used for ETXST"
113 debug_assert_eq!(TXST % 2, 0);
114 self.write_control_register(bank0::Register::ETXSTL, TXST.low());
115 self.write_control_register(bank0::Register::ETXSTH, TXST.high());
116
117 // TX end is set in `transmit`
118
119 // MAC initialization (see section 6.5)
120 // 1. Set the MARXEN bit in MACON1 to enable the MAC to receive frames.
121 self.write_control_register(
122 bank2::Register::MACON1,
123 bank2::MACON1::default().marxen(1).passall(0).rxpaus(1).txpaus(1).bits(),
124 );
125
126 // 2. Configure the PADCFG, TXCRCEN and FULDPX bits of MACON3.
127 self.write_control_register(
128 bank2::Register::MACON3,
129 bank2::MACON3::default().frmlnen(1).txcrcen(1).padcfg(0b001).bits(),
130 );
131
132 // 4. Program the MAMXFL registers with the maximum frame length to be permitted to be
133 // received or transmitted
134 self.write_control_register(bank2::Register::MAMXFLL, MAX_FRAME_LENGTH.low());
135 self.write_control_register(bank2::Register::MAMXFLH, MAX_FRAME_LENGTH.high());
136
137 // 5. Configure the Back-to-Back Inter-Packet Gap register, MABBIPG.
138 // Use recommended value of 0x12
139 self.write_control_register(bank2::Register::MABBIPG, 0x12);
140
141 // 6. Configure the Non-Back-to-Back Inter-Packet Gap register low byte, MAIPGL.
142 // Use recommended value of 0x12
143 self.write_control_register(bank2::Register::MAIPGL, 0x12);
144 self.write_control_register(bank2::Register::MAIPGH, 0x0c);
145
146 // 9. Program the local MAC address into the MAADR1:MAADR6 registers
147 self.write_control_register(bank3::Register::MAADR1, self.mac_addr[0]);
148 self.write_control_register(bank3::Register::MAADR2, self.mac_addr[1]);
149 self.write_control_register(bank3::Register::MAADR3, self.mac_addr[2]);
150 self.write_control_register(bank3::Register::MAADR4, self.mac_addr[3]);
151 self.write_control_register(bank3::Register::MAADR5, self.mac_addr[4]);
152 self.write_control_register(bank3::Register::MAADR6, self.mac_addr[5]);
153
154 // Set the PHCON2.HDLDIS bit to prevent automatic loopback of the data which is transmitted
155 self.write_phy_register(phy::Register::PHCON2, phy::PHCON2::default().hdldis(1).bits());
156
157 // Globally enable interrupts
158 //self.bit_field_set(common::Register::EIE, common::EIE::mask().intie());
159
160 // Set the per packet control byte; we'll always use the value 0
161 self.write_buffer_memory(Some(TXST), &mut [0]);
162
163 // Enable reception
164 self.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxen());
165 }
166
167 fn init_rx(&mut self) {
168 // RX start
169 // "It is recommended that the ERXST Pointer be programmed with an even address"
170 self.write_control_register(bank0::Register::ERXSTL, RXST.low());
171 self.write_control_register(bank0::Register::ERXSTH, RXST.high());
172
173 // RX read pointer
174 // NOTE Errata #14 so we are using an *odd* address here instead of ERXST
175 self.write_control_register(bank0::Register::ERXRDPTL, RXND.low());
176 self.write_control_register(bank0::Register::ERXRDPTH, RXND.high());
177
178 // RX end
179 self.write_control_register(bank0::Register::ERXNDL, RXND.low());
180 self.write_control_register(bank0::Register::ERXNDH, RXND.high());
181
182 // decrease the packet count to 0
183 while self.read_control_register(bank1::Register::EPKTCNT) != 0 {
184 self.bit_field_set(common::Register::ECON2, common::ECON2::mask().pktdec());
185 }
186
187 self.next_packet = RXST;
188 }
189
190 fn reset_rx(&mut self) {
191 self.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxrst());
192 self.bit_field_clear(common::Register::ECON1, common::ECON1::mask().rxrst());
193 self.init_rx();
194 self.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxen());
195 }
196
197 /// 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
199 /// return `None` on subsequent invocations
200 pub fn receive<'a>(&mut self, buf: &'a mut [u8]) -> Option<&'a mut [u8]> {
201 if self.pending_packets() == 0 {
202 // Errata #6: we can't rely on PKTIF so we check PKTCNT
203 return None;
204 }
205
206 let curr_packet = self.next_packet;
207
208 // read out the first 6 bytes
209 let mut temp_buf = [0; 6];
210 self.read_buffer_memory(Some(curr_packet), &mut temp_buf);
211
212 // next packet pointer
213 let next_packet = u16::from_parts(temp_buf[0], temp_buf[1]);
214 // status vector
215 let status = header::RxStatus(u32::from_le_bytes(temp_buf[2..].try_into().unwrap()));
216 let len_with_crc = status.byte_count() as u16;
217
218 if len_with_crc < CRC_SZ || len_with_crc > 1600 || next_packet > RXND {
219 warn!("RX buffer corrupted, resetting RX logic to recover...");
220 self.reset_rx();
221 return None;
222 }
223
224 let len = len_with_crc - CRC_SZ;
225 self.read_buffer_memory(None, &mut buf[..len as usize]);
226
227 // update ERXRDPT
228 // due to Errata #14 we must write an odd address to ERXRDPT
229 // we know that ERXST = 0, that ERXND is odd and that next_packet is even
230 let rxrdpt = if self.next_packet < 1 || self.next_packet > RXND + 1 {
231 RXND
232 } else {
233 self.next_packet - 1
234 };
235 // "To move ERXRDPT, the host controller must write to ERXRDPTL first."
236 self.write_control_register(bank0::Register::ERXRDPTL, rxrdpt.low());
237 self.write_control_register(bank0::Register::ERXRDPTH, rxrdpt.high());
238
239 // decrease the packet count
240 self.bit_field_set(common::Register::ECON2, common::ECON2::mask().pktdec());
241
242 self.next_packet = next_packet;
243
244 Some(&mut buf[..len as usize])
245 }
246
247 fn wait_tx_ready(&mut self) {
248 for _ in 0u32..10000 {
249 if common::ECON1(self.read_control_register(common::Register::ECON1)).txrts() == 0 {
250 return;
251 }
252 }
253
254 // work around errata #12 by resetting the transmit logic before every new
255 // transmission
256 self.bit_field_set(common::Register::ECON1, common::ECON1::mask().txrst());
257 self.bit_field_clear(common::Register::ECON1, common::ECON1::mask().txrst());
258 //self.bit_field_clear(common::Register::EIR, {
259 // let mask = common::EIR::mask();
260 // mask.txerif() | mask.txif()
261 //});
262 }
263
264 /// Starts the transmission of `bytes`
265 ///
266 /// It's up to the caller to ensure that `bytes` is a valid Ethernet frame. The interface will
267 /// take care of appending a (4 byte) CRC to the frame and of padding the frame to the minimum
268 /// size allowed by the Ethernet specification (64 bytes, or 46 bytes of payload).
269 ///
270 /// NOTE This method will flush any previous transmission that's in progress
271 ///
272 /// # Panics
273 ///
274 /// If `bytes` length is greater than 1514, the maximum frame length allowed by the interface,
275 /// or greater than the transmit buffer
276 pub fn transmit(&mut self, bytes: &[u8]) {
277 assert!(bytes.len() <= self.mtu() as usize);
278
279 self.wait_tx_ready();
280
281 // NOTE the plus one is to not overwrite the per packet control byte
282 let wrpt = TXST + 1;
283
284 // 1. ETXST was set during initialization
285
286 // 2. write the frame to the IC memory
287 self.write_buffer_memory(Some(wrpt), bytes);
288
289 let txnd = wrpt + bytes.len() as u16 - 1;
290
291 // 3. Set the end address of the transmit buffer
292 self.write_control_register(bank0::Register::ETXNDL, txnd.low());
293 self.write_control_register(bank0::Register::ETXNDH, txnd.high());
294
295 // 4. reset interrupt flag
296 //self.bit_field_clear(common::Register::EIR, common::EIR::mask().txif());
297
298 // 5. start transmission
299 self.bit_field_set(common::Register::ECON1, common::ECON1::mask().txrts());
300
301 // Wait until transmission finishes
302 //while common::ECON1(self.read_control_register(common::Register::ECON1)).txrts() == 1 {}
303
304 /*
305 // read the transmit status vector
306 let mut tx_stat = [0; 7];
307 self.read_buffer_memory(None, &mut tx_stat);
308
309 let stat = common::ESTAT(self.read_control_register(common::Register::ESTAT));
310
311 if stat.txabrt() == 1 {
312 // work around errata #12 by reading the transmit status vector
313 if stat.latecol() == 1 || (tx_stat[2] & (1 << 5)) != 0 {
314 panic!("LateCollision")
315 } else {
316 panic!("TransmitAbort")
317 }
318 }*/
319 }
320
321 /// Get whether the link is up
322 pub fn is_link_up(&mut self) -> bool {
323 let bits = self.read_phy_register(phy::Register::PHSTAT2);
324 phy::PHSTAT2(bits).lstat() == 1
325 }
326
327 /// Returns the interface Maximum Transmission Unit (MTU)
328 ///
329 /// The value returned by this function will never exceed 1514 bytes. The actual value depends
330 /// on the memory assigned to the transmission buffer when initializing the device
331 pub fn mtu(&self) -> u16 {
332 cmp::min(BUF_SZ - RXND - 1, MAX_FRAME_LENGTH - CRC_SZ)
333 }
334
335 /* Miscellaneous */
336 /// Returns the number of packets that have been received but have not been processed yet
337 pub fn pending_packets(&mut self) -> u8 {
338 self.read_control_register(bank1::Register::EPKTCNT)
339 }
340
341 /// Adjusts the receive filter to *accept* these packet types
342 pub fn accept(&mut self, packets: &[Packet]) {
343 let mask = bank1::ERXFCON::mask();
344 let mut val = 0;
345 for packet in packets {
346 match packet {
347 Packet::Broadcast => val |= mask.bcen(),
348 Packet::Multicast => val |= mask.mcen(),
349 Packet::Unicast => val |= mask.ucen(),
350 }
351 }
352
353 self.bit_field_set(bank1::Register::ERXFCON, val)
354 }
355
356 /// Adjusts the receive filter to *ignore* these packet types
357 pub fn ignore(&mut self, packets: &[Packet]) {
358 let mask = bank1::ERXFCON::mask();
359 let mut val = 0;
360 for packet in packets {
361 match packet {
362 Packet::Broadcast => val |= mask.bcen(),
363 Packet::Multicast => val |= mask.mcen(),
364 Packet::Unicast => val |= mask.ucen(),
365 }
366 }
367
368 self.bit_field_clear(bank1::Register::ERXFCON, val)
369 }
370
371 /* Private */
372 /* Read */
373 fn read_control_register<R>(&mut self, register: R) -> u8
374 where
375 R: Into<Register>,
376 {
377 self._read_control_register(register.into())
378 }
379
380 fn _read_control_register(&mut self, register: Register) -> u8 {
381 self.change_bank(register);
382
383 if register.is_eth_register() {
384 let mut buffer = [Instruction::RCR.opcode() | register.addr(), 0];
385 self.spi.transfer_in_place(&mut buffer).unwrap();
386 buffer[1]
387 } else {
388 // MAC, MII regs need a dummy byte.
389 let mut buffer = [Instruction::RCR.opcode() | register.addr(), 0, 0];
390 self.spi.transfer_in_place(&mut buffer).unwrap();
391 buffer[2]
392 }
393 }
394
395 fn read_phy_register(&mut self, register: phy::Register) -> u16 {
396 // set PHY register address
397 self.write_control_register(bank2::Register::MIREGADR, register.addr());
398
399 // start read operation
400 self.write_control_register(bank2::Register::MICMD, bank2::MICMD::default().miird(1).bits());
401
402 // wait until the read operation finishes
403 while self.read_control_register(bank3::Register::MISTAT) & 0b1 != 0 {}
404
405 self.write_control_register(bank2::Register::MICMD, bank2::MICMD::default().miird(0).bits());
406
407 let l = self.read_control_register(bank2::Register::MIRDL);
408 let h = self.read_control_register(bank2::Register::MIRDH);
409 (l as u16) | (h as u16) << 8
410 }
411
412 /* Write */
413 fn _write_control_register(&mut self, register: Register, value: u8) {
414 self.change_bank(register);
415
416 let buffer = [Instruction::WCR.opcode() | register.addr(), value];
417 self.spi.write(&buffer).unwrap();
418 }
419
420 fn write_control_register<R>(&mut self, register: R, value: u8)
421 where
422 R: Into<Register>,
423 {
424 self._write_control_register(register.into(), value)
425 }
426
427 fn write_phy_register(&mut self, register: phy::Register, value: u16) {
428 // set PHY register address
429 self.write_control_register(bank2::Register::MIREGADR, register.addr());
430
431 self.write_control_register(bank2::Register::MIWRL, (value & 0xff) as u8);
432 // this starts the write operation
433 self.write_control_register(bank2::Register::MIWRH, (value >> 8) as u8);
434
435 // wait until the write operation finishes
436 while self.read_control_register(bank3::Register::MISTAT) & 0b1 != 0 {}
437 }
438
439 /* RMW */
440 fn modify_control_register<R, F>(&mut self, register: R, f: F)
441 where
442 F: FnOnce(u8) -> u8,
443 R: Into<Register>,
444 {
445 self._modify_control_register(register.into(), f)
446 }
447
448 fn _modify_control_register<F>(&mut self, register: Register, f: F)
449 where
450 F: FnOnce(u8) -> u8,
451 {
452 let r = self._read_control_register(register);
453 self._write_control_register(register, f(r))
454 }
455
456 /* Auxiliary */
457 fn change_bank(&mut self, register: Register) {
458 let bank = register.bank();
459
460 if let Some(bank) = bank {
461 if self.bank == bank {
462 // already on the register bank
463 return;
464 }
465
466 // change bank
467 self.bank = bank;
468 match bank {
469 Bank::Bank0 => self.bit_field_clear(common::Register::ECON1, 0b11),
470 Bank::Bank1 => self.modify_control_register(common::Register::ECON1, |r| (r & !0b11) | 0b01),
471 Bank::Bank2 => self.modify_control_register(common::Register::ECON1, |r| (r & !0b11) | 0b10),
472 Bank::Bank3 => self.bit_field_set(common::Register::ECON1, 0b11),
473 }
474 } else {
475 // common register
476 }
477 }
478
479 /* Primitive operations */
480 fn bit_field_clear<R>(&mut self, register: R, mask: u8)
481 where
482 R: Into<Register>,
483 {
484 self._bit_field_clear(register.into(), mask)
485 }
486
487 fn _bit_field_clear(&mut self, register: Register, mask: u8) {
488 debug_assert!(register.is_eth_register());
489
490 self.change_bank(register);
491
492 self.spi
493 .write(&[Instruction::BFC.opcode() | register.addr(), mask])
494 .unwrap();
495 }
496
497 fn bit_field_set<R>(&mut self, register: R, mask: u8)
498 where
499 R: Into<Register>,
500 {
501 self._bit_field_set(register.into(), mask)
502 }
503
504 fn _bit_field_set(&mut self, register: Register, mask: u8) {
505 debug_assert!(register.is_eth_register());
506
507 self.change_bank(register);
508
509 self.spi
510 .write(&[Instruction::BFS.opcode() | register.addr(), mask])
511 .unwrap();
512 }
513
514 fn read_buffer_memory(&mut self, addr: Option<u16>, buf: &mut [u8]) {
515 if let Some(addr) = addr {
516 self.write_control_register(bank0::Register::ERDPTL, addr.low());
517 self.write_control_register(bank0::Register::ERDPTH, addr.high());
518 }
519
520 self.spi
521 .transaction(&mut [Operation::Write(&[Instruction::RBM.opcode()]), Operation::Read(buf)])
522 .unwrap();
523 }
524
525 fn soft_reset(&mut self) {
526 self.spi.write(&[Instruction::SRC.opcode()]).unwrap();
527 }
528
529 fn write_buffer_memory(&mut self, addr: Option<u16>, buffer: &[u8]) {
530 if let Some(addr) = addr {
531 self.write_control_register(bank0::Register::EWRPTL, addr.low());
532 self.write_control_register(bank0::Register::EWRPTH, addr.high());
533 }
534
535 self.spi
536 .transaction(&mut [Operation::Write(&[Instruction::WBM.opcode()]), Operation::Write(buffer)])
537 .unwrap();
538 }
539}
540
541#[derive(Clone, Copy, PartialEq)]
542enum Bank {
543 Bank0,
544 Bank1,
545 Bank2,
546 Bank3,
547}
548
549#[derive(Clone, Copy)]
550enum Instruction {
551 /// Read Control Register
552 RCR = 0b000_00000,
553 /// Read Buffer Memory
554 RBM = 0b001_11010,
555 /// Write Control Register
556 WCR = 0b010_00000,
557 /// Write Buffer Memory
558 WBM = 0b011_11010,
559 /// Bit Field Set
560 BFS = 0b100_00000,
561 /// Bit Field Clear
562 BFC = 0b101_00000,
563 /// System Reset Command
564 SRC = 0b111_11111,
565}
566
567impl Instruction {
568 fn opcode(&self) -> u8 {
569 *self as u8
570 }
571}
572
573#[derive(Clone, Copy)]
574enum Register {
575 Bank0(bank0::Register),
576 Bank1(bank1::Register),
577 Bank2(bank2::Register),
578 Bank3(bank3::Register),
579 Common(common::Register),
580}
581
582impl Register {
583 fn addr(&self) -> u8 {
584 match *self {
585 Register::Bank0(r) => r.addr(),
586 Register::Bank1(r) => r.addr(),
587 Register::Bank2(r) => r.addr(),
588 Register::Bank3(r) => r.addr(),
589 Register::Common(r) => r.addr(),
590 }
591 }
592
593 fn bank(&self) -> Option<Bank> {
594 Some(match *self {
595 Register::Bank0(_) => Bank::Bank0,
596 Register::Bank1(_) => Bank::Bank1,
597 Register::Bank2(_) => Bank::Bank2,
598 Register::Bank3(_) => Bank::Bank3,
599 Register::Common(_) => return None,
600 })
601 }
602
603 fn is_eth_register(&self) -> bool {
604 match *self {
605 Register::Bank0(r) => r.is_eth_register(),
606 Register::Bank1(r) => r.is_eth_register(),
607 Register::Bank2(r) => r.is_eth_register(),
608 Register::Bank3(r) => r.is_eth_register(),
609 Register::Common(r) => r.is_eth_register(),
610 }
611 }
612}
613
614/// Packet type, used to configure receive filters
615#[non_exhaustive]
616#[derive(Clone, Copy, Eq, PartialEq)]
617pub enum Packet {
618 /// Broadcast packets
619 Broadcast,
620 /// Multicast packets
621 Multicast,
622 /// Unicast packets
623 Unicast,
624}
625
626static mut TX_BUF: [u8; MTU] = [0; MTU];
627static mut RX_BUF: [u8; MTU] = [0; MTU];
628
629impl<S, O> embassy_net_driver::Driver for Enc28j60<S, O>
630where
631 S: SpiDevice,
632 O: OutputPin,
633{
634 type RxToken<'a> = RxToken<'a>
635 where
636 Self: 'a;
637
638 type TxToken<'a> = TxToken<'a, S, O>
639 where
640 Self: 'a;
641
642 fn receive(&mut self, cx: &mut core::task::Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
643 let rx_buf = unsafe { &mut RX_BUF };
644 let tx_buf = unsafe { &mut TX_BUF };
645 if let Some(pkt) = self.receive(rx_buf) {
646 let n = pkt.len();
647 Some((RxToken { buf: &mut pkt[..n] }, TxToken { buf: tx_buf, eth: self }))
648 } else {
649 cx.waker().wake_by_ref();
650 None
651 }
652 }
653
654 fn transmit(&mut self, _cx: &mut core::task::Context) -> Option<Self::TxToken<'_>> {
655 let tx_buf = unsafe { &mut TX_BUF };
656 Some(TxToken { buf: tx_buf, eth: self })
657 }
658
659 fn link_state(&mut self, cx: &mut core::task::Context) -> LinkState {
660 cx.waker().wake_by_ref();
661 match self.is_link_up() {
662 true => LinkState::Up,
663 false => LinkState::Down,
664 }
665 }
666
667 fn capabilities(&self) -> Capabilities {
668 let mut caps = Capabilities::default();
669 caps.max_transmission_unit = MTU;
670 caps.medium = Medium::Ethernet;
671 caps
672 }
673
674 fn hardware_address(&self) -> HardwareAddress {
675 HardwareAddress::Ethernet(self.mac_addr)
676 }
677}
678
679/// embassy-net RX token.
680pub struct RxToken<'a> {
681 buf: &'a mut [u8],
682}
683
684impl<'a> embassy_net_driver::RxToken for RxToken<'a> {
685 fn consume<R, F>(self, f: F) -> R
686 where
687 F: FnOnce(&mut [u8]) -> R,
688 {
689 f(self.buf)
690 }
691}
692
693/// embassy-net TX token.
694pub struct TxToken<'a, S, O>
695where
696 S: SpiDevice,
697 O: OutputPin,
698{
699 eth: &'a mut Enc28j60<S, O>,
700 buf: &'a mut [u8],
701}
702
703impl<'a, S, O> embassy_net_driver::TxToken for TxToken<'a, S, O>
704where
705 S: SpiDevice,
706 O: OutputPin,
707{
708 fn consume<R, F>(self, len: usize, f: F) -> R
709 where
710 F: FnOnce(&mut [u8]) -> R,
711 {
712 assert!(len <= self.buf.len());
713 let r = f(&mut self.buf[..len]);
714 self.eth.transmit(&self.buf[..len]);
715 r
716 }
717}
diff --git a/embassy-net-enc28j60/src/macros.rs b/embassy-net-enc28j60/src/macros.rs
new file mode 100644
index 000000000..8d0649572
--- /dev/null
+++ b/embassy-net-enc28j60/src/macros.rs
@@ -0,0 +1,89 @@
1macro_rules! register {
2 ($REGISTER:ident, $reset_value:expr, $uxx:ty, {
3 $(#[$($attr:tt)*] $bitfield:ident @ $range:expr,)+
4 }) => {
5 #[derive(Clone, Copy)]
6 pub(crate) struct $REGISTER<MODE> {
7 bits: $uxx,
8 _mode: ::core::marker::PhantomData<MODE>,
9 }
10
11 impl $REGISTER<super::traits::Mask> {
12 #[allow(dead_code)]
13 pub(crate) fn mask() -> $REGISTER<super::traits::Mask> {
14 $REGISTER { bits: 0, _mode: ::core::marker::PhantomData }
15 }
16
17 $(
18 #[allow(dead_code)]
19 pub(crate) fn $bitfield(&self) -> $uxx {
20 use super::traits::OffsetSize;
21
22 let size = $range.size();
23 let offset = $range.offset();
24 ((1 << size) - 1) << offset
25 }
26 )+
27 }
28
29 impl ::core::default::Default for $REGISTER<super::traits::W> {
30 fn default() -> Self {
31 $REGISTER { bits: $reset_value, _mode: ::core::marker::PhantomData }
32 }
33 }
34
35 #[allow(non_snake_case)]
36 #[allow(dead_code)]
37 pub(crate) fn $REGISTER(bits: $uxx) -> $REGISTER<super::traits::R> {
38 $REGISTER { bits, _mode: ::core::marker::PhantomData }
39 }
40
41 impl $REGISTER<super::traits::R> {
42 #[allow(dead_code)]
43 pub(crate) fn modify(self) -> $REGISTER<super::traits::W> {
44 $REGISTER { bits: self.bits, _mode: ::core::marker::PhantomData }
45 }
46
47 $(
48 #[$($attr)*]
49 #[allow(dead_code)]
50 pub(crate) fn $bitfield(&self) -> $uxx {
51 use super::traits::OffsetSize;
52
53 let offset = $range.offset();
54 let size = $range.size();
55 let mask = (1 << size) - 1;
56
57 (self.bits >> offset) & mask
58 }
59 )+
60 }
61
62 impl $REGISTER<super::traits::W> {
63 #[allow(dead_code)]
64 pub(crate) fn bits(self) -> $uxx {
65 self.bits
66 }
67
68 $(
69 #[$($attr)*]
70 #[allow(dead_code)]
71 pub(crate) fn $bitfield(&mut self, mut bits: $uxx) -> &mut Self {
72 use super::traits::OffsetSize;
73
74 let offset = $range.offset();
75 let size = $range.size();
76 let mask = (1 << size) - 1;
77
78 debug_assert!(bits <= mask);
79 bits &= mask;
80
81 self.bits &= !(mask << offset);
82 self.bits |= bits << offset;
83
84 self
85 }
86 )+
87 }
88 }
89}
diff --git a/embassy-net-enc28j60/src/phy.rs b/embassy-net-enc28j60/src/phy.rs
new file mode 100644
index 000000000..89144ada3
--- /dev/null
+++ b/embassy-net-enc28j60/src/phy.rs
@@ -0,0 +1,35 @@
1#[allow(dead_code)]
2#[derive(Clone, Copy)]
3pub enum Register {
4 PHCON1 = 0x00,
5 PHSTAT1 = 0x01,
6 PHID1 = 0x02,
7 PHID2 = 0x03,
8 PHCON2 = 0x10,
9 PHSTAT2 = 0x11,
10 PHIE = 0x12,
11 PHIR = 0x13,
12 PHLCON = 0x14,
13}
14
15impl Register {
16 pub(crate) fn addr(&self) -> u8 {
17 *self as u8
18 }
19}
20
21register!(PHCON2, 0, u16, {
22 #[doc = "PHY Half-Duplex Loopback Disable bit"]
23 hdldis @ 8,
24 #[doc = "Jabber Correction Disable bit"]
25 jabber @ 10,
26 #[doc = "Twisted-Pair Transmitter Disable bit"]
27 txdis @ 13,
28 #[doc = "PHY Force Linkup bit"]
29 frclnk @ 14,
30});
31
32register!(PHSTAT2, 0, u16, {
33 #[doc = "Link Status bit"]
34 lstat @ 10,
35});
diff --git a/embassy-net-enc28j60/src/traits.rs b/embassy-net-enc28j60/src/traits.rs
new file mode 100644
index 000000000..08f94045a
--- /dev/null
+++ b/embassy-net-enc28j60/src/traits.rs
@@ -0,0 +1,57 @@
1use core::ops::Range;
2
3pub(crate) trait OffsetSize {
4 fn offset(self) -> u8;
5 fn size(self) -> u8;
6}
7
8impl OffsetSize for u8 {
9 fn offset(self) -> u8 {
10 self
11 }
12
13 fn size(self) -> u8 {
14 1
15 }
16}
17
18impl OffsetSize for Range<u8> {
19 fn offset(self) -> u8 {
20 self.start
21 }
22
23 fn size(self) -> u8 {
24 self.end - self.start
25 }
26}
27
28pub(crate) trait U16Ext {
29 fn from_parts(low: u8, high: u8) -> Self;
30
31 fn low(self) -> u8;
32
33 fn high(self) -> u8;
34}
35
36impl U16Ext for u16 {
37 fn from_parts(low: u8, high: u8) -> u16 {
38 ((high as u16) << 8) + low as u16
39 }
40
41 fn low(self) -> u8 {
42 (self & 0xff) as u8
43 }
44
45 fn high(self) -> u8 {
46 (self >> 8) as u8
47 }
48}
49
50#[derive(Clone, Copy)]
51pub struct Mask;
52
53#[derive(Clone, Copy)]
54pub struct R;
55
56#[derive(Clone, Copy)]
57pub struct W;
diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml
index 0053c49a4..d334cf3fe 100644
--- a/embassy-net-esp-hosted/Cargo.toml
+++ b/embassy-net-esp-hosted/Cargo.toml
@@ -12,8 +12,8 @@ embassy-sync = { version = "0.2.0", path = "../embassy-sync"}
12embassy-futures = { version = "0.1.0", path = "../embassy-futures"} 12embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
13embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"} 13embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
14 14
15embedded-hal = { version = "1.0.0-alpha.11" } 15embedded-hal = { version = "1.0.0-rc.1" }
16embedded-hal-async = { version = "=0.2.0-alpha.2" } 16embedded-hal-async = { version = "=1.0.0-rc.1" }
17 17
18noproto = { git="https://github.com/embassy-rs/noproto", default-features = false, features = ["derive"] } 18noproto = { git="https://github.com/embassy-rs/noproto", default-features = false, features = ["derive"] }
19#noproto = { version = "0.1", path = "/home/dirbaio/noproto", default-features = false, features = ["derive"] } 19#noproto = { version = "0.1", path = "/home/dirbaio/noproto", default-features = false, features = ["derive"] }
diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs
index 37f220da0..b8026611b 100644
--- a/embassy-net-esp-hosted/src/control.rs
+++ b/embassy-net-esp-hosted/src/control.rs
@@ -5,9 +5,12 @@ use heapless::String;
5use crate::ioctl::Shared; 5use crate::ioctl::Shared;
6use crate::proto::{self, CtrlMsg}; 6use crate::proto::{self, CtrlMsg};
7 7
8#[derive(Debug)] 8#[derive(Copy, Clone, PartialEq, Eq, Debug)]
9pub struct Error { 9#[cfg_attr(feature = "defmt", derive(defmt::Format))]
10 pub status: u32, 10pub enum Error {
11 Failed(u32),
12 Timeout,
13 Internal,
11} 14}
12 15
13pub struct Control<'a> { 16pub struct Control<'a> {
@@ -23,58 +26,78 @@ enum WifiMode {
23 ApSta = 3, 26 ApSta = 3,
24} 27}
25 28
29macro_rules! ioctl {
30 ($self:ident, $req_variant:ident, $resp_variant:ident, $req:ident, $resp:ident) => {
31 let mut msg = proto::CtrlMsg {
32 msg_id: proto::CtrlMsgId::$req_variant as _,
33 msg_type: proto::CtrlMsgType::Req as _,
34 payload: Some(proto::CtrlMsgPayload::$req_variant($req)),
35 };
36 $self.ioctl(&mut msg).await?;
37 let Some(proto::CtrlMsgPayload::$resp_variant($resp)) = msg.payload else {
38 warn!("unexpected response variant");
39 return Err(Error::Internal);
40 };
41 if $resp.resp != 0 {
42 return Err(Error::Failed($resp.resp));
43 }
44 };
45}
46
26impl<'a> Control<'a> { 47impl<'a> Control<'a> {
27 pub(crate) fn new(state_ch: ch::StateRunner<'a>, shared: &'a Shared) -> Self { 48 pub(crate) fn new(state_ch: ch::StateRunner<'a>, shared: &'a Shared) -> Self {
28 Self { state_ch, shared } 49 Self { state_ch, shared }
29 } 50 }
30 51
31 pub async fn init(&mut self) { 52 pub async fn init(&mut self) -> Result<(), Error> {
32 debug!("wait for init event..."); 53 debug!("wait for init event...");
33 self.shared.init_wait().await; 54 self.shared.init_wait().await;
34 55
56 debug!("set heartbeat");
57 self.set_heartbeat(10).await?;
58
35 debug!("set wifi mode"); 59 debug!("set wifi mode");
36 self.set_wifi_mode(WifiMode::Sta as _).await; 60 self.set_wifi_mode(WifiMode::Sta as _).await?;
37 61
38 let mac_addr = self.get_mac_addr().await; 62 let mac_addr = self.get_mac_addr().await?;
39 debug!("mac addr: {:02x}", mac_addr); 63 debug!("mac addr: {:02x}", mac_addr);
40 self.state_ch.set_ethernet_address(mac_addr); 64 self.state_ch.set_ethernet_address(mac_addr);
65
66 Ok(())
41 } 67 }
42 68
43 pub async fn join(&mut self, ssid: &str, password: &str) { 69 pub async fn connect(&mut self, ssid: &str, password: &str) -> Result<(), Error> {
44 let req = proto::CtrlMsg { 70 let req = proto::CtrlMsgReqConnectAp {
45 msg_id: proto::CtrlMsgId::ReqConnectAp as _, 71 ssid: String::from(ssid),
46 msg_type: proto::CtrlMsgType::Req as _, 72 pwd: String::from(password),
47 payload: Some(proto::CtrlMsgPayload::ReqConnectAp(proto::CtrlMsgReqConnectAp { 73 bssid: String::new(),
48 ssid: String::from(ssid), 74 listen_interval: 3,
49 pwd: String::from(password), 75 is_wpa3_supported: false,
50 bssid: String::new(),
51 listen_interval: 3,
52 is_wpa3_supported: false,
53 })),
54 }; 76 };
55 let resp = self.ioctl(req).await; 77 ioctl!(self, ReqConnectAp, RespConnectAp, req, resp);
56 let proto::CtrlMsgPayload::RespConnectAp(resp) = resp.payload.unwrap() else {
57 panic!("unexpected resp")
58 };
59 assert_eq!(resp.resp, 0);
60 self.state_ch.set_link_state(LinkState::Up); 78 self.state_ch.set_link_state(LinkState::Up);
79 Ok(())
61 } 80 }
62 81
63 async fn get_mac_addr(&mut self) -> [u8; 6] { 82 pub async fn disconnect(&mut self) -> Result<(), Error> {
64 let req = proto::CtrlMsg { 83 let req = proto::CtrlMsgReqGetStatus {};
65 msg_id: proto::CtrlMsgId::ReqGetMacAddress as _, 84 ioctl!(self, ReqDisconnectAp, RespDisconnectAp, req, resp);
66 msg_type: proto::CtrlMsgType::Req as _, 85 self.state_ch.set_link_state(LinkState::Up);
67 payload: Some(proto::CtrlMsgPayload::ReqGetMacAddress( 86 Ok(())
68 proto::CtrlMsgReqGetMacAddress { 87 }
69 mode: WifiMode::Sta as _, 88
70 }, 89 /// duration in seconds, clamped to [10, 3600]
71 )), 90 async fn set_heartbeat(&mut self, duration: u32) -> Result<(), Error> {
72 }; 91 let req = proto::CtrlMsgReqConfigHeartbeat { enable: true, duration };
73 let resp = self.ioctl(req).await; 92 ioctl!(self, ReqConfigHeartbeat, RespConfigHeartbeat, req, resp);
74 let proto::CtrlMsgPayload::RespGetMacAddress(resp) = resp.payload.unwrap() else { 93 Ok(())
75 panic!("unexpected resp") 94 }
95
96 async fn get_mac_addr(&mut self) -> Result<[u8; 6], Error> {
97 let req = proto::CtrlMsgReqGetMacAddress {
98 mode: WifiMode::Sta as _,
76 }; 99 };
77 assert_eq!(resp.resp, 0); 100 ioctl!(self, ReqGetMacAddress, RespGetMacAddress, req, resp);
78 101
79 // WHY IS THIS A STRING? WHYYYY 102 // WHY IS THIS A STRING? WHYYYY
80 fn nibble_from_hex(b: u8) -> u8 { 103 fn nibble_from_hex(b: u8) -> u8 {
@@ -88,32 +111,32 @@ impl<'a> Control<'a> {
88 111
89 let mac = resp.mac.as_bytes(); 112 let mac = resp.mac.as_bytes();
90 let mut res = [0; 6]; 113 let mut res = [0; 6];
91 assert_eq!(mac.len(), 17); 114 if mac.len() != 17 {
115 warn!("unexpected MAC respnse length");
116 return Err(Error::Internal);
117 }
92 for (i, b) in res.iter_mut().enumerate() { 118 for (i, b) in res.iter_mut().enumerate() {
93 *b = (nibble_from_hex(mac[i * 3]) << 4) | nibble_from_hex(mac[i * 3 + 1]) 119 *b = (nibble_from_hex(mac[i * 3]) << 4) | nibble_from_hex(mac[i * 3 + 1])
94 } 120 }
95 res 121 Ok(res)
96 } 122 }
97 123
98 async fn set_wifi_mode(&mut self, mode: u32) { 124 async fn set_wifi_mode(&mut self, mode: u32) -> Result<(), Error> {
99 let req = proto::CtrlMsg { 125 let req = proto::CtrlMsgReqSetMode { mode };
100 msg_id: proto::CtrlMsgId::ReqSetWifiMode as _, 126 ioctl!(self, ReqSetWifiMode, RespSetWifiMode, req, resp);
101 msg_type: proto::CtrlMsgType::Req as _, 127
102 payload: Some(proto::CtrlMsgPayload::ReqSetWifiMode(proto::CtrlMsgReqSetMode { mode })), 128 Ok(())
103 };
104 let resp = self.ioctl(req).await;
105 let proto::CtrlMsgPayload::RespSetWifiMode(resp) = resp.payload.unwrap() else {
106 panic!("unexpected resp")
107 };
108 assert_eq!(resp.resp, 0);
109 } 129 }
110 130
111 async fn ioctl(&mut self, req: CtrlMsg) -> CtrlMsg { 131 async fn ioctl(&mut self, msg: &mut CtrlMsg) -> Result<(), Error> {
112 debug!("ioctl req: {:?}", &req); 132 debug!("ioctl req: {:?}", &msg);
113 133
114 let mut buf = [0u8; 128]; 134 let mut buf = [0u8; 128];
115 135
116 let req_len = noproto::write(&req, &mut buf).unwrap(); 136 let req_len = noproto::write(msg, &mut buf).map_err(|_| {
137 warn!("failed to serialize control request");
138 Error::Internal
139 })?;
117 140
118 struct CancelOnDrop<'a>(&'a Shared); 141 struct CancelOnDrop<'a>(&'a Shared);
119 142
@@ -135,9 +158,12 @@ impl<'a> Control<'a> {
135 158
136 ioctl.defuse(); 159 ioctl.defuse();
137 160
138 let res = noproto::read(&buf[..resp_len]).unwrap(); 161 *msg = noproto::read(&buf[..resp_len]).map_err(|_| {
139 debug!("ioctl resp: {:?}", &res); 162 warn!("failed to serialize control request");
163 Error::Internal
164 })?;
165 debug!("ioctl resp: {:?}", msg);
140 166
141 res 167 Ok(())
142 } 168 }
143} 169}
diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs
index 96fddce58..4a318b20d 100644
--- a/embassy-net-esp-hosted/src/lib.rs
+++ b/embassy-net-esp-hosted/src/lib.rs
@@ -1,17 +1,15 @@
1#![no_std] 1#![no_std]
2 2
3use control::Control; 3use embassy_futures::select::{select4, Either4};
4use embassy_futures::select::{select3, Either3};
5use embassy_net_driver_channel as ch; 4use embassy_net_driver_channel as ch;
5use embassy_net_driver_channel::driver::LinkState;
6use embassy_time::{Duration, Instant, Timer}; 6use embassy_time::{Duration, Instant, Timer};
7use embedded_hal::digital::{InputPin, OutputPin}; 7use embedded_hal::digital::{InputPin, OutputPin};
8use embedded_hal_async::digital::Wait; 8use embedded_hal_async::digital::Wait;
9use embedded_hal_async::spi::SpiDevice; 9use embedded_hal_async::spi::SpiDevice;
10use ioctl::Shared;
11use proto::CtrlMsg;
12 10
13use crate::ioctl::PendingIoctl; 11use crate::ioctl::{PendingIoctl, Shared};
14use crate::proto::CtrlMsgPayload; 12use crate::proto::{CtrlMsg, CtrlMsgPayload};
15 13
16mod proto; 14mod proto;
17 15
@@ -21,6 +19,8 @@ mod fmt;
21mod control; 19mod control;
22mod ioctl; 20mod ioctl;
23 21
22pub use control::*;
23
24const MTU: usize = 1514; 24const MTU: usize = 1514;
25 25
26macro_rules! impl_bytes { 26macro_rules! impl_bytes {
@@ -95,6 +95,7 @@ enum InterfaceType {
95} 95}
96 96
97const MAX_SPI_BUFFER_SIZE: usize = 1600; 97const MAX_SPI_BUFFER_SIZE: usize = 1600;
98const HEARTBEAT_MAX_GAP: Duration = Duration::from_secs(20);
98 99
99pub struct State { 100pub struct State {
100 shared: Shared, 101 shared: Shared,
@@ -129,12 +130,14 @@ where
129 130
130 let mut runner = Runner { 131 let mut runner = Runner {
131 ch: ch_runner, 132 ch: ch_runner,
133 state_ch,
132 shared: &state.shared, 134 shared: &state.shared,
133 next_seq: 1, 135 next_seq: 1,
134 handshake, 136 handshake,
135 ready, 137 ready,
136 reset, 138 reset,
137 spi, 139 spi,
140 heartbeat_deadline: Instant::now() + HEARTBEAT_MAX_GAP,
138 }; 141 };
139 runner.init().await; 142 runner.init().await;
140 143
@@ -143,9 +146,11 @@ where
143 146
144pub struct Runner<'a, SPI, IN, OUT> { 147pub struct Runner<'a, SPI, IN, OUT> {
145 ch: ch::Runner<'a, MTU>, 148 ch: ch::Runner<'a, MTU>,
149 state_ch: ch::StateRunner<'a>,
146 shared: &'a Shared, 150 shared: &'a Shared,
147 151
148 next_seq: u16, 152 next_seq: u16,
153 heartbeat_deadline: Instant,
149 154
150 spi: SPI, 155 spi: SPI,
151 handshake: IN, 156 handshake: IN,
@@ -177,9 +182,10 @@ where
177 let ioctl = self.shared.ioctl_wait_pending(); 182 let ioctl = self.shared.ioctl_wait_pending();
178 let tx = self.ch.tx_buf(); 183 let tx = self.ch.tx_buf();
179 let ev = async { self.ready.wait_for_high().await.unwrap() }; 184 let ev = async { self.ready.wait_for_high().await.unwrap() };
185 let hb = Timer::at(self.heartbeat_deadline);
180 186
181 match select3(ioctl, tx, ev).await { 187 match select4(ioctl, tx, ev, hb).await {
182 Either3::First(PendingIoctl { buf, req_len }) => { 188 Either4::First(PendingIoctl { buf, req_len }) => {
183 tx_buf[12..24].copy_from_slice(b"\x01\x08\x00ctrlResp\x02"); 189 tx_buf[12..24].copy_from_slice(b"\x01\x08\x00ctrlResp\x02");
184 tx_buf[24..26].copy_from_slice(&(req_len as u16).to_le_bytes()); 190 tx_buf[24..26].copy_from_slice(&(req_len as u16).to_le_bytes());
185 tx_buf[26..][..req_len].copy_from_slice(&unsafe { &*buf }[..req_len]); 191 tx_buf[26..][..req_len].copy_from_slice(&unsafe { &*buf }[..req_len]);
@@ -198,7 +204,7 @@ where
198 header.checksum = checksum(&tx_buf[..26 + req_len]); 204 header.checksum = checksum(&tx_buf[..26 + req_len]);
199 tx_buf[0..12].copy_from_slice(&header.to_bytes()); 205 tx_buf[0..12].copy_from_slice(&header.to_bytes());
200 } 206 }
201 Either3::Second(packet) => { 207 Either4::Second(packet) => {
202 tx_buf[12..][..packet.len()].copy_from_slice(packet); 208 tx_buf[12..][..packet.len()].copy_from_slice(packet);
203 209
204 let mut header = PayloadHeader { 210 let mut header = PayloadHeader {
@@ -217,9 +223,12 @@ where
217 223
218 self.ch.tx_done(); 224 self.ch.tx_done();
219 } 225 }
220 Either3::Third(()) => { 226 Either4::Third(()) => {
221 tx_buf[..PayloadHeader::SIZE].fill(0); 227 tx_buf[..PayloadHeader::SIZE].fill(0);
222 } 228 }
229 Either4::Fourth(()) => {
230 panic!("heartbeat from esp32 stopped")
231 }
223 } 232 }
224 233
225 if tx_buf[0] != 0 { 234 if tx_buf[0] != 0 {
@@ -308,7 +317,7 @@ where
308 } 317 }
309 } 318 }
310 319
311 fn handle_event(&self, data: &[u8]) { 320 fn handle_event(&mut self, data: &[u8]) {
312 let Ok(event) = noproto::read::<CtrlMsg>(data) else { 321 let Ok(event) = noproto::read::<CtrlMsg>(data) else {
313 warn!("failed to parse event"); 322 warn!("failed to parse event");
314 return; 323 return;
@@ -323,6 +332,11 @@ where
323 332
324 match payload { 333 match payload {
325 CtrlMsgPayload::EventEspInit(_) => self.shared.init_done(), 334 CtrlMsgPayload::EventEspInit(_) => self.shared.init_done(),
335 CtrlMsgPayload::EventHeartbeat(_) => self.heartbeat_deadline = Instant::now() + HEARTBEAT_MAX_GAP,
336 CtrlMsgPayload::EventStationDisconnectFromAp(e) => {
337 info!("disconnected, code {}", e.resp);
338 self.state_ch.set_link_state(LinkState::Down);
339 }
326 _ => {} 340 _ => {}
327 } 341 }
328 } 342 }
diff --git a/embassy-net-w5500/README.md b/embassy-net-w5500/README.md
deleted file mode 100644
index 9eaf4b700..000000000
--- a/embassy-net-w5500/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
1# WIZnet W5500 `embassy-net` integration
2
3[`embassy-net`](https://crates.io/crates/embassy-net) integration for the WIZnet W5500 SPI ethernet chip, operating in MACRAW mode.
4
5Supports any SPI driver implementing [`embedded-hal-async`](https://crates.io/crates/embedded-hal-async)
6
7See [`examples`](https://github.com/kalkyl/embassy-net-w5500/tree/main/examples) directory for usage examples with the rp2040 [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) module. \ No newline at end of file
diff --git a/embassy-net-w5500/src/device.rs b/embassy-net-w5500/src/device.rs
deleted file mode 100644
index 9874df0d6..000000000
--- a/embassy-net-w5500/src/device.rs
+++ /dev/null
@@ -1,131 +0,0 @@
1use embedded_hal_async::spi::SpiDevice;
2
3use crate::socket;
4use crate::spi::SpiInterface;
5
6pub const MODE: u16 = 0x00;
7pub const MAC: u16 = 0x09;
8pub const SOCKET_INTR: u16 = 0x18;
9pub const PHY_CFG: u16 = 0x2E;
10
11#[repr(u8)]
12pub enum RegisterBlock {
13 Common = 0x00,
14 Socket0 = 0x01,
15 TxBuf = 0x02,
16 RxBuf = 0x03,
17}
18
19/// W5500 in MACRAW mode
20#[derive(Debug)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22pub struct W5500<SPI> {
23 bus: SpiInterface<SPI>,
24}
25
26impl<SPI: SpiDevice> W5500<SPI> {
27 /// Create and initialize the W5500 driver
28 pub async fn new(spi: SPI, mac_addr: [u8; 6]) -> Result<W5500<SPI>, SPI::Error> {
29 let mut bus = SpiInterface(spi);
30 // Reset device
31 bus.write_frame(RegisterBlock::Common, MODE, &[0x80]).await?;
32
33 // Enable interrupt pin
34 bus.write_frame(RegisterBlock::Common, SOCKET_INTR, &[0x01]).await?;
35 // Enable receive interrupt
36 bus.write_frame(
37 RegisterBlock::Socket0,
38 socket::SOCKET_INTR_MASK,
39 &[socket::Interrupt::Receive as u8],
40 )
41 .await?;
42
43 // Set MAC address
44 bus.write_frame(RegisterBlock::Common, MAC, &mac_addr).await?;
45
46 // Set the raw socket RX/TX buffer sizes to 16KB
47 bus.write_frame(RegisterBlock::Socket0, socket::TXBUF_SIZE, &[16])
48 .await?;
49 bus.write_frame(RegisterBlock::Socket0, socket::RXBUF_SIZE, &[16])
50 .await?;
51
52 // MACRAW mode with MAC filtering.
53 let mode: u8 = (1 << 2) | (1 << 7);
54 bus.write_frame(RegisterBlock::Socket0, socket::MODE, &[mode]).await?;
55 socket::command(&mut bus, socket::Command::Open).await?;
56
57 Ok(Self { bus })
58 }
59
60 /// Read bytes from the RX buffer. Returns the number of bytes read.
61 async fn read_bytes(&mut self, buffer: &mut [u8], offset: u16) -> Result<usize, SPI::Error> {
62 let rx_size = socket::get_rx_size(&mut self.bus).await? as usize;
63
64 let read_buffer = if rx_size > buffer.len() + offset as usize {
65 buffer
66 } else {
67 &mut buffer[..rx_size - offset as usize]
68 };
69
70 let read_ptr = socket::get_rx_read_ptr(&mut self.bus).await?.wrapping_add(offset);
71 self.bus.read_frame(RegisterBlock::RxBuf, read_ptr, read_buffer).await?;
72 socket::set_rx_read_ptr(&mut self.bus, read_ptr.wrapping_add(read_buffer.len() as u16)).await?;
73
74 Ok(read_buffer.len())
75 }
76
77 /// Read an ethernet frame from the device. Returns the number of bytes read.
78 pub async fn read_frame(&mut self, frame: &mut [u8]) -> Result<usize, SPI::Error> {
79 let rx_size = socket::get_rx_size(&mut self.bus).await? as usize;
80 if rx_size == 0 {
81 return Ok(0);
82 }
83
84 socket::reset_interrupt(&mut self.bus, socket::Interrupt::Receive).await?;
85
86 // First two bytes gives the size of the received ethernet frame
87 let expected_frame_size: usize = {
88 let mut frame_bytes = [0u8; 2];
89 assert!(self.read_bytes(&mut frame_bytes[..], 0).await? == 2);
90 u16::from_be_bytes(frame_bytes) as usize - 2
91 };
92
93 // Read the ethernet frame
94 let read_buffer = if frame.len() > expected_frame_size {
95 &mut frame[..expected_frame_size]
96 } else {
97 frame
98 };
99
100 let recvd_frame_size = self.read_bytes(read_buffer, 2).await?;
101
102 // Register RX as completed
103 socket::command(&mut self.bus, socket::Command::Receive).await?;
104
105 // If the whole frame wasn't read, drop it
106 if recvd_frame_size < expected_frame_size {
107 Ok(0)
108 } else {
109 Ok(recvd_frame_size)
110 }
111 }
112
113 /// Write an ethernet frame to the device. Returns number of bytes written
114 pub async fn write_frame(&mut self, frame: &[u8]) -> Result<usize, SPI::Error> {
115 while socket::get_tx_free_size(&mut self.bus).await? < frame.len() as u16 {}
116 let write_ptr = socket::get_tx_write_ptr(&mut self.bus).await?;
117 self.bus.write_frame(RegisterBlock::TxBuf, write_ptr, frame).await?;
118 socket::set_tx_write_ptr(&mut self.bus, write_ptr.wrapping_add(frame.len() as u16)).await?;
119 socket::command(&mut self.bus, socket::Command::Send).await?;
120 Ok(frame.len())
121 }
122
123 pub async fn is_link_up(&mut self) -> bool {
124 let mut link = [0];
125 self.bus
126 .read_frame(RegisterBlock::Common, PHY_CFG, &mut link)
127 .await
128 .ok();
129 link[0] & 1 == 1
130 }
131}
diff --git a/embassy-net-w5500/src/socket.rs b/embassy-net-w5500/src/socket.rs
deleted file mode 100644
index 3d65583c1..000000000
--- a/embassy-net-w5500/src/socket.rs
+++ /dev/null
@@ -1,80 +0,0 @@
1use embedded_hal_async::spi::SpiDevice;
2
3use crate::device::RegisterBlock;
4use crate::spi::SpiInterface;
5
6pub const MODE: u16 = 0x00;
7pub const COMMAND: u16 = 0x01;
8pub const RXBUF_SIZE: u16 = 0x1E;
9pub const TXBUF_SIZE: u16 = 0x1F;
10pub const TX_FREE_SIZE: u16 = 0x20;
11pub const TX_DATA_WRITE_PTR: u16 = 0x24;
12pub const RECVD_SIZE: u16 = 0x26;
13pub const RX_DATA_READ_PTR: u16 = 0x28;
14pub const SOCKET_INTR_MASK: u16 = 0x2C;
15
16#[repr(u8)]
17pub enum Command {
18 Open = 0x01,
19 Send = 0x20,
20 Receive = 0x40,
21}
22
23pub const INTR: u16 = 0x02;
24#[repr(u8)]
25pub enum Interrupt {
26 Receive = 0b00100_u8,
27}
28
29pub async fn reset_interrupt<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>, code: Interrupt) -> Result<(), SPI::Error> {
30 let data = [code as u8];
31 bus.write_frame(RegisterBlock::Socket0, INTR, &data).await
32}
33
34pub async fn get_tx_write_ptr<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>) -> Result<u16, SPI::Error> {
35 let mut data = [0u8; 2];
36 bus.read_frame(RegisterBlock::Socket0, TX_DATA_WRITE_PTR, &mut data)
37 .await?;
38 Ok(u16::from_be_bytes(data))
39}
40
41pub async fn set_tx_write_ptr<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>, ptr: u16) -> Result<(), SPI::Error> {
42 let data = ptr.to_be_bytes();
43 bus.write_frame(RegisterBlock::Socket0, TX_DATA_WRITE_PTR, &data).await
44}
45
46pub async fn get_rx_read_ptr<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>) -> Result<u16, SPI::Error> {
47 let mut data = [0u8; 2];
48 bus.read_frame(RegisterBlock::Socket0, RX_DATA_READ_PTR, &mut data)
49 .await?;
50 Ok(u16::from_be_bytes(data))
51}
52
53pub async fn set_rx_read_ptr<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>, ptr: u16) -> Result<(), SPI::Error> {
54 let data = ptr.to_be_bytes();
55 bus.write_frame(RegisterBlock::Socket0, RX_DATA_READ_PTR, &data).await
56}
57
58pub async fn command<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>, command: Command) -> Result<(), SPI::Error> {
59 let data = [command as u8];
60 bus.write_frame(RegisterBlock::Socket0, COMMAND, &data).await
61}
62
63pub async fn get_rx_size<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>) -> Result<u16, SPI::Error> {
64 loop {
65 // Wait until two sequential reads are equal
66 let mut res0 = [0u8; 2];
67 bus.read_frame(RegisterBlock::Socket0, RECVD_SIZE, &mut res0).await?;
68 let mut res1 = [0u8; 2];
69 bus.read_frame(RegisterBlock::Socket0, RECVD_SIZE, &mut res1).await?;
70 if res0 == res1 {
71 break Ok(u16::from_be_bytes(res0));
72 }
73 }
74}
75
76pub async fn get_tx_free_size<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>) -> Result<u16, SPI::Error> {
77 let mut data = [0; 2];
78 bus.read_frame(RegisterBlock::Socket0, TX_FREE_SIZE, &mut data).await?;
79 Ok(u16::from_be_bytes(data))
80}
diff --git a/embassy-net-w5500/src/spi.rs b/embassy-net-w5500/src/spi.rs
deleted file mode 100644
index 07749d6be..000000000
--- a/embassy-net-w5500/src/spi.rs
+++ /dev/null
@@ -1,32 +0,0 @@
1use embedded_hal_async::spi::{Operation, SpiDevice};
2
3use crate::device::RegisterBlock;
4
5#[derive(Debug)]
6#[cfg_attr(feature = "defmt", derive(defmt::Format))]
7pub struct SpiInterface<SPI>(pub SPI);
8
9impl<SPI: SpiDevice> SpiInterface<SPI> {
10 pub async fn read_frame(&mut self, block: RegisterBlock, address: u16, data: &mut [u8]) -> Result<(), SPI::Error> {
11 let address_phase = address.to_be_bytes();
12 let control_phase = [(block as u8) << 3];
13 let operations = &mut [
14 Operation::Write(&address_phase),
15 Operation::Write(&control_phase),
16 Operation::TransferInPlace(data),
17 ];
18 self.0.transaction(operations).await
19 }
20
21 pub async fn write_frame(&mut self, block: RegisterBlock, address: u16, data: &[u8]) -> Result<(), SPI::Error> {
22 let address_phase = address.to_be_bytes();
23 let control_phase = [(block as u8) << 3 | 0b0000_0100];
24 let data_phase = data;
25 let operations = &mut [
26 Operation::Write(&address_phase[..]),
27 Operation::Write(&control_phase),
28 Operation::Write(&data_phase),
29 ];
30 self.0.transaction(operations).await
31 }
32}
diff --git a/embassy-net-w5500/Cargo.toml b/embassy-net-wiznet/Cargo.toml
index 8972b814a..adf0b45fc 100644
--- a/embassy-net-w5500/Cargo.toml
+++ b/embassy-net-wiznet/Cargo.toml
@@ -1,21 +1,22 @@
1[package] 1[package]
2name = "embassy-net-w5500" 2name = "embassy-net-wiznet"
3version = "0.1.0" 3version = "0.1.0"
4description = "embassy-net driver for the W5500 ethernet chip" 4description = "embassy-net driver for WIZnet SPI Ethernet chips"
5keywords = ["embedded", "w5500", "embassy-net", "embedded-hal-async", "ethernet", "async"] 5keywords = ["embedded", "wiznet", "embassy-net", "embedded-hal-async", "ethernet", "async"]
6categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] 6categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
7license = "MIT OR Apache-2.0" 7license = "MIT OR Apache-2.0"
8edition = "2021" 8edition = "2021"
9 9
10[dependencies] 10[dependencies]
11embedded-hal = { version = "1.0.0-alpha.11" } 11embedded-hal = { version = "1.0.0-rc.1" }
12embedded-hal-async = { version = "=0.2.0-alpha.2" } 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.2", 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
18[package.metadata.embassy_docs] 18[package.metadata.embassy_docs]
19src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-w5500-v$VERSION/embassy-net-w5500/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-w5500/src/" 20src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-wiznet/src/"
21target = "thumbv7em-none-eabi" \ No newline at end of file 21target = "thumbv7em-none-eabi"
22features = ["defmt"] \ No newline at end of file
diff --git a/embassy-net-wiznet/README.md b/embassy-net-wiznet/README.md
new file mode 100644
index 000000000..b8e4bdc8e
--- /dev/null
+++ b/embassy-net-wiznet/README.md
@@ -0,0 +1,27 @@
1# WIZnet `embassy-net` integration
2
3[`embassy-net`](https://crates.io/crates/embassy-net) integration for the WIZnet SPI ethernet chips, operating in MACRAW mode.
4
5See [`examples`](https://github.com/embassy-rs/embassy/tree/main/examples/rp) directory for usage examples with the rp2040 [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) module.
6
7## Supported chips
8
9- W5500
10- W5100S
11
12## Interoperability
13
14This crate can run on any executor.
15
16It supports any SPI driver implementing [`embedded-hal-async`](https://crates.io/crates/embedded-hal-async).
17
18
19## License
20
21This work is licensed under either of
22
23- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
24 http://www.apache.org/licenses/LICENSE-2.0)
25- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
26
27at your option.
diff --git a/embassy-net-wiznet/src/chip/mod.rs b/embassy-net-wiznet/src/chip/mod.rs
new file mode 100644
index 000000000..562db515a
--- /dev/null
+++ b/embassy-net-wiznet/src/chip/mod.rs
@@ -0,0 +1,48 @@
1mod w5500;
2pub use w5500::W5500;
3mod w5100s;
4pub use w5100s::W5100S;
5
6pub(crate) mod sealed {
7 use embedded_hal_async::spi::SpiDevice;
8
9 pub trait Chip {
10 type Address;
11
12 const COMMON_MODE: Self::Address;
13 const COMMON_MAC: Self::Address;
14 const COMMON_SOCKET_INTR: Self::Address;
15 const COMMON_PHY_CFG: Self::Address;
16 const SOCKET_MODE: Self::Address;
17 const SOCKET_COMMAND: Self::Address;
18 const SOCKET_RXBUF_SIZE: Self::Address;
19 const SOCKET_TXBUF_SIZE: Self::Address;
20 const SOCKET_TX_FREE_SIZE: Self::Address;
21 const SOCKET_TX_DATA_WRITE_PTR: Self::Address;
22 const SOCKET_RECVD_SIZE: Self::Address;
23 const SOCKET_RX_DATA_READ_PTR: Self::Address;
24 const SOCKET_INTR_MASK: Self::Address;
25 const SOCKET_INTR: Self::Address;
26
27 const SOCKET_MODE_VALUE: u8;
28
29 const BUF_SIZE: u16;
30 const AUTO_WRAP: bool;
31
32 fn rx_addr(addr: u16) -> Self::Address;
33 fn tx_addr(addr: u16) -> Self::Address;
34
35 async fn bus_read<SPI: SpiDevice>(
36 spi: &mut SPI,
37 address: Self::Address,
38 data: &mut [u8],
39 ) -> Result<(), SPI::Error>;
40 async fn bus_write<SPI: SpiDevice>(
41 spi: &mut SPI,
42 address: Self::Address,
43 data: &[u8],
44 ) -> Result<(), SPI::Error>;
45 }
46}
47
48pub trait Chip: sealed::Chip {}
diff --git a/embassy-net-wiznet/src/chip/w5100s.rs b/embassy-net-wiznet/src/chip/w5100s.rs
new file mode 100644
index 000000000..07a840370
--- /dev/null
+++ b/embassy-net-wiznet/src/chip/w5100s.rs
@@ -0,0 +1,61 @@
1use embedded_hal_async::spi::{Operation, SpiDevice};
2
3const SOCKET_BASE: u16 = 0x400;
4const TX_BASE: u16 = 0x4000;
5const RX_BASE: u16 = 0x6000;
6
7pub enum W5100S {}
8
9impl super::Chip for W5100S {}
10impl super::sealed::Chip for W5100S {
11 type Address = u16;
12
13 const COMMON_MODE: Self::Address = 0x00;
14 const COMMON_MAC: Self::Address = 0x09;
15 const COMMON_SOCKET_INTR: Self::Address = 0x16;
16 const COMMON_PHY_CFG: Self::Address = 0x3c;
17
18 const SOCKET_MODE: Self::Address = SOCKET_BASE + 0x00;
19 const SOCKET_COMMAND: Self::Address = SOCKET_BASE + 0x01;
20 const SOCKET_RXBUF_SIZE: Self::Address = SOCKET_BASE + 0x1E;
21 const SOCKET_TXBUF_SIZE: Self::Address = SOCKET_BASE + 0x1F;
22 const SOCKET_TX_FREE_SIZE: Self::Address = SOCKET_BASE + 0x20;
23 const SOCKET_TX_DATA_WRITE_PTR: Self::Address = SOCKET_BASE + 0x24;
24 const SOCKET_RECVD_SIZE: Self::Address = SOCKET_BASE + 0x26;
25 const SOCKET_RX_DATA_READ_PTR: Self::Address = SOCKET_BASE + 0x28;
26 const SOCKET_INTR_MASK: Self::Address = SOCKET_BASE + 0x2C;
27 const SOCKET_INTR: Self::Address = SOCKET_BASE + 0x02;
28
29 const SOCKET_MODE_VALUE: u8 = (1 << 2) | (1 << 6);
30
31 const BUF_SIZE: u16 = 0x2000;
32 const AUTO_WRAP: bool = false;
33
34 fn rx_addr(addr: u16) -> Self::Address {
35 RX_BASE + addr
36 }
37
38 fn tx_addr(addr: u16) -> Self::Address {
39 TX_BASE + addr
40 }
41
42 async fn bus_read<SPI: SpiDevice>(
43 spi: &mut SPI,
44 address: Self::Address,
45 data: &mut [u8],
46 ) -> Result<(), SPI::Error> {
47 spi.transaction(&mut [
48 Operation::Write(&[0x0F, (address >> 8) as u8, address as u8]),
49 Operation::Read(data),
50 ])
51 .await
52 }
53
54 async fn bus_write<SPI: SpiDevice>(spi: &mut SPI, address: Self::Address, data: &[u8]) -> Result<(), SPI::Error> {
55 spi.transaction(&mut [
56 Operation::Write(&[0xF0, (address >> 8) as u8, address as u8]),
57 Operation::Write(data),
58 ])
59 .await
60 }
61}
diff --git a/embassy-net-wiznet/src/chip/w5500.rs b/embassy-net-wiznet/src/chip/w5500.rs
new file mode 100644
index 000000000..61e512946
--- /dev/null
+++ b/embassy-net-wiznet/src/chip/w5500.rs
@@ -0,0 +1,72 @@
1use embedded_hal_async::spi::{Operation, SpiDevice};
2
3#[repr(u8)]
4pub enum RegisterBlock {
5 Common = 0x00,
6 Socket0 = 0x01,
7 TxBuf = 0x02,
8 RxBuf = 0x03,
9}
10
11pub enum W5500 {}
12
13impl super::Chip for W5500 {}
14impl super::sealed::Chip for W5500 {
15 type Address = (RegisterBlock, u16);
16
17 const COMMON_MODE: Self::Address = (RegisterBlock::Common, 0x00);
18 const COMMON_MAC: Self::Address = (RegisterBlock::Common, 0x09);
19 const COMMON_SOCKET_INTR: Self::Address = (RegisterBlock::Common, 0x18);
20 const COMMON_PHY_CFG: Self::Address = (RegisterBlock::Common, 0x2E);
21
22 const SOCKET_MODE: Self::Address = (RegisterBlock::Socket0, 0x00);
23 const SOCKET_COMMAND: Self::Address = (RegisterBlock::Socket0, 0x01);
24 const SOCKET_RXBUF_SIZE: Self::Address = (RegisterBlock::Socket0, 0x1E);
25 const SOCKET_TXBUF_SIZE: Self::Address = (RegisterBlock::Socket0, 0x1F);
26 const SOCKET_TX_FREE_SIZE: Self::Address = (RegisterBlock::Socket0, 0x20);
27 const SOCKET_TX_DATA_WRITE_PTR: Self::Address = (RegisterBlock::Socket0, 0x24);
28 const SOCKET_RECVD_SIZE: Self::Address = (RegisterBlock::Socket0, 0x26);
29 const SOCKET_RX_DATA_READ_PTR: Self::Address = (RegisterBlock::Socket0, 0x28);
30 const SOCKET_INTR_MASK: Self::Address = (RegisterBlock::Socket0, 0x2C);
31 const SOCKET_INTR: Self::Address = (RegisterBlock::Socket0, 0x02);
32
33 const SOCKET_MODE_VALUE: u8 = (1 << 2) | (1 << 7);
34
35 const BUF_SIZE: u16 = 0x4000;
36 const AUTO_WRAP: bool = true;
37
38 fn rx_addr(addr: u16) -> Self::Address {
39 (RegisterBlock::RxBuf, addr)
40 }
41
42 fn tx_addr(addr: u16) -> Self::Address {
43 (RegisterBlock::TxBuf, addr)
44 }
45
46 async fn bus_read<SPI: SpiDevice>(
47 spi: &mut SPI,
48 address: Self::Address,
49 data: &mut [u8],
50 ) -> Result<(), SPI::Error> {
51 let address_phase = address.1.to_be_bytes();
52 let control_phase = [(address.0 as u8) << 3];
53 let operations = &mut [
54 Operation::Write(&address_phase),
55 Operation::Write(&control_phase),
56 Operation::TransferInPlace(data),
57 ];
58 spi.transaction(operations).await
59 }
60
61 async fn bus_write<SPI: SpiDevice>(spi: &mut SPI, address: Self::Address, data: &[u8]) -> Result<(), SPI::Error> {
62 let address_phase = address.1.to_be_bytes();
63 let control_phase = [(address.0 as u8) << 3 | 0b0000_0100];
64 let data_phase = data;
65 let operations = &mut [
66 Operation::Write(&address_phase[..]),
67 Operation::Write(&control_phase),
68 Operation::Write(&data_phase),
69 ];
70 spi.transaction(operations).await
71 }
72}
diff --git a/embassy-net-wiznet/src/device.rs b/embassy-net-wiznet/src/device.rs
new file mode 100644
index 000000000..43f9512a3
--- /dev/null
+++ b/embassy-net-wiznet/src/device.rs
@@ -0,0 +1,195 @@
1use core::marker::PhantomData;
2
3use embedded_hal_async::spi::SpiDevice;
4
5use crate::chip::Chip;
6
7#[repr(u8)]
8enum Command {
9 Open = 0x01,
10 Send = 0x20,
11 Receive = 0x40,
12}
13
14#[repr(u8)]
15enum Interrupt {
16 Receive = 0b00100_u8,
17}
18
19/// Wiznet chip in MACRAW mode
20#[derive(Debug)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22pub(crate) struct WiznetDevice<C, SPI> {
23 spi: SPI,
24 _phantom: PhantomData<C>,
25}
26
27impl<C: Chip, SPI: SpiDevice> WiznetDevice<C, SPI> {
28 /// Create and initialize the driver
29 pub async fn new(spi: SPI, mac_addr: [u8; 6]) -> Result<Self, SPI::Error> {
30 let mut this = Self {
31 spi,
32 _phantom: PhantomData,
33 };
34
35 // Reset device
36 this.bus_write(C::COMMON_MODE, &[0x80]).await?;
37
38 // Enable interrupt pin
39 this.bus_write(C::COMMON_SOCKET_INTR, &[0x01]).await?;
40 // Enable receive interrupt
41 this.bus_write(C::SOCKET_INTR_MASK, &[Interrupt::Receive as u8]).await?;
42
43 // Set MAC address
44 this.bus_write(C::COMMON_MAC, &mac_addr).await?;
45
46 // Set the raw socket RX/TX buffer sizes.
47 let buf_kbs = (C::BUF_SIZE / 1024) as u8;
48 this.bus_write(C::SOCKET_TXBUF_SIZE, &[buf_kbs]).await?;
49 this.bus_write(C::SOCKET_RXBUF_SIZE, &[buf_kbs]).await?;
50
51 // MACRAW mode with MAC filtering.
52 this.bus_write(C::SOCKET_MODE, &[C::SOCKET_MODE_VALUE]).await?;
53 this.command(Command::Open).await?;
54
55 Ok(this)
56 }
57
58 async fn bus_read(&mut self, address: C::Address, data: &mut [u8]) -> Result<(), SPI::Error> {
59 C::bus_read(&mut self.spi, address, data).await
60 }
61
62 async fn bus_write(&mut self, address: C::Address, data: &[u8]) -> Result<(), SPI::Error> {
63 C::bus_write(&mut self.spi, address, data).await
64 }
65
66 async fn reset_interrupt(&mut self, code: Interrupt) -> Result<(), SPI::Error> {
67 let data = [code as u8];
68 self.bus_write(C::SOCKET_INTR, &data).await
69 }
70
71 async fn get_tx_write_ptr(&mut self) -> Result<u16, SPI::Error> {
72 let mut data = [0u8; 2];
73 self.bus_read(C::SOCKET_TX_DATA_WRITE_PTR, &mut data).await?;
74 Ok(u16::from_be_bytes(data))
75 }
76
77 async fn set_tx_write_ptr(&mut self, ptr: u16) -> Result<(), SPI::Error> {
78 let data = ptr.to_be_bytes();
79 self.bus_write(C::SOCKET_TX_DATA_WRITE_PTR, &data).await
80 }
81
82 async fn get_rx_read_ptr(&mut self) -> Result<u16, SPI::Error> {
83 let mut data = [0u8; 2];
84 self.bus_read(C::SOCKET_RX_DATA_READ_PTR, &mut data).await?;
85 Ok(u16::from_be_bytes(data))
86 }
87
88 async fn set_rx_read_ptr(&mut self, ptr: u16) -> Result<(), SPI::Error> {
89 let data = ptr.to_be_bytes();
90 self.bus_write(C::SOCKET_RX_DATA_READ_PTR, &data).await
91 }
92
93 async fn command(&mut self, command: Command) -> Result<(), SPI::Error> {
94 let data = [command as u8];
95 self.bus_write(C::SOCKET_COMMAND, &data).await
96 }
97
98 async fn get_rx_size(&mut self) -> Result<u16, SPI::Error> {
99 loop {
100 // Wait until two sequential reads are equal
101 let mut res0 = [0u8; 2];
102 self.bus_read(C::SOCKET_RECVD_SIZE, &mut res0).await?;
103 let mut res1 = [0u8; 2];
104 self.bus_read(C::SOCKET_RECVD_SIZE, &mut res1).await?;
105 if res0 == res1 {
106 break Ok(u16::from_be_bytes(res0));
107 }
108 }
109 }
110
111 async fn get_tx_free_size(&mut self) -> Result<u16, SPI::Error> {
112 let mut data = [0; 2];
113 self.bus_read(C::SOCKET_TX_FREE_SIZE, &mut data).await?;
114 Ok(u16::from_be_bytes(data))
115 }
116
117 /// Read bytes from the RX buffer.
118 async fn read_bytes(&mut self, read_ptr: &mut u16, buffer: &mut [u8]) -> Result<(), SPI::Error> {
119 if C::AUTO_WRAP {
120 self.bus_read(C::rx_addr(*read_ptr), buffer).await?;
121 } else {
122 let addr = *read_ptr % C::BUF_SIZE;
123 if addr as usize + buffer.len() <= C::BUF_SIZE as usize {
124 self.bus_read(C::rx_addr(addr), buffer).await?;
125 } else {
126 let n = C::BUF_SIZE - addr;
127 self.bus_read(C::rx_addr(addr), &mut buffer[..n as usize]).await?;
128 self.bus_read(C::rx_addr(0), &mut buffer[n as usize..]).await?;
129 }
130 }
131
132 *read_ptr = (*read_ptr).wrapping_add(buffer.len() as u16);
133
134 Ok(())
135 }
136
137 /// Read an ethernet frame from the device. Returns the number of bytes read.
138 pub async fn read_frame(&mut self, frame: &mut [u8]) -> Result<usize, SPI::Error> {
139 let rx_size = self.get_rx_size().await? as usize;
140 if rx_size == 0 {
141 return Ok(0);
142 }
143
144 self.reset_interrupt(Interrupt::Receive).await?;
145
146 let mut read_ptr = self.get_rx_read_ptr().await?;
147
148 // First two bytes gives the size of the received ethernet frame
149 let expected_frame_size: usize = {
150 let mut frame_bytes = [0u8; 2];
151 self.read_bytes(&mut read_ptr, &mut frame_bytes).await?;
152 u16::from_be_bytes(frame_bytes) as usize - 2
153 };
154
155 // Read the ethernet frame
156 self.read_bytes(&mut read_ptr, &mut frame[..expected_frame_size])
157 .await?;
158
159 // Register RX as completed
160 self.set_rx_read_ptr(read_ptr).await?;
161 self.command(Command::Receive).await?;
162
163 Ok(expected_frame_size)
164 }
165
166 /// Write an ethernet frame to the device. Returns number of bytes written
167 pub async fn write_frame(&mut self, frame: &[u8]) -> Result<usize, SPI::Error> {
168 while self.get_tx_free_size().await? < frame.len() as u16 {}
169 let write_ptr = self.get_tx_write_ptr().await?;
170
171 if C::AUTO_WRAP {
172 self.bus_write(C::tx_addr(write_ptr), frame).await?;
173 } else {
174 let addr = write_ptr % C::BUF_SIZE;
175 if addr as usize + frame.len() <= C::BUF_SIZE as usize {
176 self.bus_write(C::tx_addr(addr), frame).await?;
177 } else {
178 let n = C::BUF_SIZE - addr;
179 self.bus_write(C::tx_addr(addr), &frame[..n as usize]).await?;
180 self.bus_write(C::tx_addr(0), &frame[n as usize..]).await?;
181 }
182 }
183
184 self.set_tx_write_ptr(write_ptr.wrapping_add(frame.len() as u16))
185 .await?;
186 self.command(Command::Send).await?;
187 Ok(frame.len())
188 }
189
190 pub async fn is_link_up(&mut self) -> bool {
191 let mut link = [0];
192 self.bus_read(C::COMMON_PHY_CFG, &mut link).await.ok();
193 link[0] & 1 == 1
194 }
195}
diff --git a/embassy-net-w5500/src/lib.rs b/embassy-net-wiznet/src/lib.rs
index 52494b443..3030dfb90 100644
--- a/embassy-net-w5500/src/lib.rs
+++ b/embassy-net-wiznet/src/lib.rs
@@ -1,9 +1,9 @@
1//! [`embassy-net`](https://crates.io/crates/embassy-net) driver for the WIZnet W5500 ethernet chip. 1//! [`embassy-net`](https://crates.io/crates/embassy-net) driver for WIZnet ethernet chips.
2#![no_std] 2#![no_std]
3#![feature(async_fn_in_trait)]
3 4
5pub mod chip;
4mod device; 6mod device;
5mod socket;
6mod spi;
7 7
8use embassy_futures::select::{select, Either}; 8use embassy_futures::select::{select, Either};
9use embassy_net_driver_channel as ch; 9use embassy_net_driver_channel as ch;
@@ -13,10 +13,12 @@ use embedded_hal::digital::OutputPin;
13use embedded_hal_async::digital::Wait; 13use embedded_hal_async::digital::Wait;
14use embedded_hal_async::spi::SpiDevice; 14use embedded_hal_async::spi::SpiDevice;
15 15
16use crate::device::W5500; 16use crate::chip::Chip;
17use crate::device::WiznetDevice;
18
17const MTU: usize = 1514; 19const MTU: usize = 1514;
18 20
19/// Type alias for the embassy-net driver for W5500 21/// Type alias for the embassy-net driver.
20pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>; 22pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>;
21 23
22/// Internal state for the embassy-net integration. 24/// Internal state for the embassy-net integration.
@@ -33,18 +35,18 @@ impl<const N_RX: usize, const N_TX: usize> State<N_RX, N_TX> {
33 } 35 }
34} 36}
35 37
36/// Background runner for the W5500. 38/// Background runner for the driver.
37/// 39///
38/// You must call `.run()` in a background task for the W5500 to operate. 40/// You must call `.run()` in a background task for the driver to operate.
39pub struct Runner<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> { 41pub struct Runner<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> {
40 mac: W5500<SPI>, 42 mac: WiznetDevice<C, SPI>,
41 ch: ch::Runner<'d, MTU>, 43 ch: ch::Runner<'d, MTU>,
42 int: INT, 44 int: INT,
43 _reset: RST, 45 _reset: RST,
44} 46}
45 47
46/// You must call this in a background task for the W5500 to operate. 48/// You must call this in a background task for the driver to operate.
47impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { 49impl<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, C, SPI, INT, RST> {
48 pub async fn run(mut self) -> ! { 50 pub async fn run(mut self) -> ! {
49 let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); 51 let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split();
50 loop { 52 loop {
@@ -78,23 +80,29 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> {
78 } 80 }
79} 81}
80 82
81/// Obtain a driver for using the W5500 with [`embassy-net`](https://crates.io/crates/embassy-net). 83/// Create a Wiznet ethernet chip driver for [`embassy-net`](https://crates.io/crates/embassy-net).
82pub async fn new<'a, const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait, RST: OutputPin>( 84///
85/// This returns two structs:
86/// - a `Device` that you must pass to the `embassy-net` stack.
87/// - a `Runner`. You must call `.run()` on it in a background task.
88pub async fn new<'a, const N_RX: usize, const N_TX: usize, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin>(
83 mac_addr: [u8; 6], 89 mac_addr: [u8; 6],
84 state: &'a mut State<N_RX, N_TX>, 90 state: &'a mut State<N_RX, N_TX>,
85 spi_dev: SPI, 91 spi_dev: SPI,
86 int: INT, 92 int: INT,
87 mut reset: RST, 93 mut reset: RST,
88) -> (Device<'a>, Runner<'a, SPI, INT, RST>) { 94) -> (Device<'a>, Runner<'a, C, SPI, INT, RST>) {
89 // Reset the W5500. 95 // Reset the chip.
90 reset.set_low().ok(); 96 reset.set_low().ok();
91 // Ensure the reset is registered. 97 // Ensure the reset is registered.
92 Timer::after(Duration::from_millis(1)).await; 98 Timer::after(Duration::from_millis(1)).await;
93 reset.set_high().ok(); 99 reset.set_high().ok();
94 // Wait for the W5500 to achieve PLL lock.
95 Timer::after(Duration::from_millis(2)).await;
96 100
97 let mac = W5500::new(spi_dev, mac_addr).await.unwrap(); 101 // Wait for PLL lock. Some chips are slower than others.
102 // Slowest is w5100s which is 100ms, so let's just wait that.
103 Timer::after(Duration::from_millis(100)).await;
104
105 let mac = WiznetDevice::new(spi_dev, mac_addr).await.unwrap();
98 106
99 let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ethernet(mac_addr)); 107 let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ethernet(mac_addr));
100 ( 108 (
diff --git a/embassy-net/README.md b/embassy-net/README.md
index 811321ca4..7bb2283c4 100644
--- a/embassy-net/README.md
+++ b/embassy-net/README.md
@@ -22,7 +22,7 @@ unimplemented features of the network protocols.
22- [`cyw43`](https://github.com/embassy-rs/embassy/tree/main/cyw43) for WiFi on CYW43xx chips, used in the Raspberry Pi Pico W 22- [`cyw43`](https://github.com/embassy-rs/embassy/tree/main/cyw43) for WiFi on CYW43xx chips, used in the Raspberry Pi Pico W
23- [`embassy-usb`](https://github.com/embassy-rs/embassy/tree/main/embassy-usb) for Ethernet-over-USB (CDC NCM) support. 23- [`embassy-usb`](https://github.com/embassy-rs/embassy/tree/main/embassy-usb) for Ethernet-over-USB (CDC NCM) support.
24- [`embassy-stm32`](https://github.com/embassy-rs/embassy/tree/main/embassy-stm32) for the builtin Ethernet MAC in all STM32 chips (STM32F1, STM32F2, STM32F4, STM32F7, STM32H7, STM32H5). 24- [`embassy-stm32`](https://github.com/embassy-rs/embassy/tree/main/embassy-stm32) for the builtin Ethernet MAC in all STM32 chips (STM32F1, STM32F2, STM32F4, STM32F7, STM32H7, STM32H5).
25- [`embassy-net-w5500`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-w5500) for Wiznet W5500 SPI Ethernet MAC+PHY chip. 25- [`embassy-net-wiznet`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-wiznet) for Wiznet SPI Ethernet MAC+PHY chips (W5100S, W5500)
26- [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU. 26- [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU.
27 27
28## Examples 28## Examples
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs
index c903fb245..c92ad2d2e 100644
--- a/embassy-net/src/tcp.rs
+++ b/embassy-net/src/tcp.rs
@@ -82,6 +82,22 @@ impl<'a> TcpReader<'a> {
82 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { 82 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
83 self.io.read(buf).await 83 self.io.read(buf).await
84 } 84 }
85
86 /// Call `f` with the largest contiguous slice of octets in the receive buffer,
87 /// and dequeue the amount of elements returned by `f`.
88 ///
89 /// If no data is available, it waits until there is at least one byte available.
90 pub async fn read_with<F, R>(&mut self, f: F) -> Result<R, Error>
91 where
92 F: FnOnce(&mut [u8]) -> (usize, R),
93 {
94 self.io.read_with(f).await
95 }
96
97 /// Return the maximum number of bytes inside the transmit buffer.
98 pub fn recv_capacity(&self) -> usize {
99 self.io.recv_capacity()
100 }
85} 101}
86 102
87impl<'a> TcpWriter<'a> { 103impl<'a> TcpWriter<'a> {
@@ -100,6 +116,22 @@ impl<'a> TcpWriter<'a> {
100 pub async fn flush(&mut self) -> Result<(), Error> { 116 pub async fn flush(&mut self) -> Result<(), Error> {
101 self.io.flush().await 117 self.io.flush().await
102 } 118 }
119
120 /// Call `f` with the largest contiguous slice of octets in the transmit buffer,
121 /// and enqueue the amount of elements returned by `f`.
122 ///
123 /// If the socket is not ready to accept data, it waits until it is.
124 pub async fn write_with<F, R>(&mut self, f: F) -> Result<R, Error>
125 where
126 F: FnOnce(&mut [u8]) -> (usize, R),
127 {
128 self.io.write_with(f).await
129 }
130
131 /// Return the maximum number of bytes inside the transmit buffer.
132 pub fn send_capacity(&self) -> usize {
133 self.io.send_capacity()
134 }
103} 135}
104 136
105impl<'a> TcpSocket<'a> { 137impl<'a> TcpSocket<'a> {
@@ -121,6 +153,38 @@ impl<'a> TcpSocket<'a> {
121 } 153 }
122 } 154 }
123 155
156 /// Return the maximum number of bytes inside the recv buffer.
157 pub fn recv_capacity(&self) -> usize {
158 self.io.recv_capacity()
159 }
160
161 /// Return the maximum number of bytes inside the transmit buffer.
162 pub fn send_capacity(&self) -> usize {
163 self.io.send_capacity()
164 }
165
166 /// Call `f` with the largest contiguous slice of octets in the transmit buffer,
167 /// and enqueue the amount of elements returned by `f`.
168 ///
169 /// If the socket is not ready to accept data, it waits until it is.
170 pub async fn write_with<F, R>(&mut self, f: F) -> Result<R, Error>
171 where
172 F: FnOnce(&mut [u8]) -> (usize, R),
173 {
174 self.io.write_with(f).await
175 }
176
177 /// Call `f` with the largest contiguous slice of octets in the receive buffer,
178 /// and dequeue the amount of elements returned by `f`.
179 ///
180 /// If no data is available, it waits until there is at least one byte available.
181 pub async fn read_with<F, R>(&mut self, f: F) -> Result<R, Error>
182 where
183 F: FnOnce(&mut [u8]) -> (usize, R),
184 {
185 self.io.read_with(f).await
186 }
187
124 /// Split the socket into reader and a writer halves. 188 /// Split the socket into reader and a writer halves.
125 pub fn split(&mut self) -> (TcpReader<'_>, TcpWriter<'_>) { 189 pub fn split(&mut self) -> (TcpReader<'_>, TcpWriter<'_>) {
126 (TcpReader { io: self.io }, TcpWriter { io: self.io }) 190 (TcpReader { io: self.io }, TcpWriter { io: self.io })
@@ -359,6 +423,64 @@ impl<'d> TcpIo<'d> {
359 .await 423 .await
360 } 424 }
361 425
426 async fn write_with<F, R>(&mut self, f: F) -> Result<R, Error>
427 where
428 F: FnOnce(&mut [u8]) -> (usize, R),
429 {
430 let mut f = Some(f);
431 poll_fn(move |cx| {
432 self.with_mut(|s, _| {
433 if !s.can_send() {
434 if s.may_send() {
435 // socket buffer is full wait until it has atleast one byte free
436 s.register_send_waker(cx.waker());
437 Poll::Pending
438 } else {
439 // if we can't transmit because the transmit half of the duplex connection is closed then return an error
440 Poll::Ready(Err(Error::ConnectionReset))
441 }
442 } else {
443 Poll::Ready(match s.send(f.take().unwrap()) {
444 // Connection reset. TODO: this can also be timeouts etc, investigate.
445 Err(tcp::SendError::InvalidState) => Err(Error::ConnectionReset),
446 Ok(r) => Ok(r),
447 })
448 }
449 })
450 })
451 .await
452 }
453
454 async fn read_with<F, R>(&mut self, f: F) -> Result<R, Error>
455 where
456 F: FnOnce(&mut [u8]) -> (usize, R),
457 {
458 let mut f = Some(f);
459 poll_fn(move |cx| {
460 self.with_mut(|s, _| {
461 if !s.can_recv() {
462 if s.may_recv() {
463 // socket buffer is empty wait until it has atleast one byte has arrived
464 s.register_recv_waker(cx.waker());
465 Poll::Pending
466 } else {
467 // if we can't receive because the recieve half of the duplex connection is closed then return an error
468 Poll::Ready(Err(Error::ConnectionReset))
469 }
470 } else {
471 Poll::Ready(match s.recv(f.take().unwrap()) {
472 // Connection reset. TODO: this can also be timeouts etc, investigate.
473 Err(tcp::RecvError::Finished) | Err(tcp::RecvError::InvalidState) => {
474 Err(Error::ConnectionReset)
475 }
476 Ok(r) => Ok(r),
477 })
478 }
479 })
480 })
481 .await
482 }
483
362 async fn flush(&mut self) -> Result<(), Error> { 484 async fn flush(&mut self) -> Result<(), Error> {
363 poll_fn(move |cx| { 485 poll_fn(move |cx| {
364 self.with_mut(|s, _| { 486 self.with_mut(|s, _| {
@@ -376,6 +498,14 @@ impl<'d> TcpIo<'d> {
376 }) 498 })
377 .await 499 .await
378 } 500 }
501
502 fn recv_capacity(&self) -> usize {
503 self.with(|s, _| s.recv_capacity())
504 }
505
506 fn send_capacity(&self) -> usize {
507 self.with(|s, _| s.send_capacity())
508 }
379} 509}
380 510
381#[cfg(feature = "nightly")] 511#[cfg(feature = "nightly")]
@@ -384,13 +514,20 @@ mod embedded_io_impls {
384 514
385 impl embedded_io_async::Error for ConnectError { 515 impl embedded_io_async::Error for ConnectError {
386 fn kind(&self) -> embedded_io_async::ErrorKind { 516 fn kind(&self) -> embedded_io_async::ErrorKind {
387 embedded_io_async::ErrorKind::Other 517 match self {
518 ConnectError::ConnectionReset => embedded_io_async::ErrorKind::ConnectionReset,
519 ConnectError::TimedOut => embedded_io_async::ErrorKind::TimedOut,
520 ConnectError::NoRoute => embedded_io_async::ErrorKind::NotConnected,
521 ConnectError::InvalidState => embedded_io_async::ErrorKind::Other,
522 }
388 } 523 }
389 } 524 }
390 525
391 impl embedded_io_async::Error for Error { 526 impl embedded_io_async::Error for Error {
392 fn kind(&self) -> embedded_io_async::ErrorKind { 527 fn kind(&self) -> embedded_io_async::ErrorKind {
393 embedded_io_async::ErrorKind::Other 528 match self {
529 Error::ConnectionReset => embedded_io_async::ErrorKind::ConnectionReset,
530 }
394 } 531 }
395 } 532 }
396 533
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs
index 0d97b6db1..0a5a7b8f6 100644
--- a/embassy-net/src/udp.rs
+++ b/embassy-net/src/udp.rs
@@ -184,6 +184,26 @@ impl<'a> UdpSocket<'a> {
184 pub fn may_recv(&self) -> bool { 184 pub fn may_recv(&self) -> bool {
185 self.with(|s, _| s.can_recv()) 185 self.with(|s, _| s.can_recv())
186 } 186 }
187
188 /// Return the maximum number packets the socket can receive.
189 pub fn packet_recv_capacity(&self) -> usize {
190 self.with(|s, _| s.packet_recv_capacity())
191 }
192
193 /// Return the maximum number packets the socket can receive.
194 pub fn packet_send_capacity(&self) -> usize {
195 self.with(|s, _| s.packet_send_capacity())
196 }
197
198 /// Return the maximum number of bytes inside the recv buffer.
199 pub fn payload_recv_capacity(&self) -> usize {
200 self.with(|s, _| s.payload_recv_capacity())
201 }
202
203 /// Return the maximum number of bytes inside the transmit buffer.
204 pub fn payload_send_capacity(&self) -> usize {
205 self.with(|s, _| s.payload_send_capacity())
206 }
187} 207}
188 208
189impl Drop for UdpSocket<'_> { 209impl Drop for UdpSocket<'_> {
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index da1cd38e1..67ec4eb93 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -32,7 +32,7 @@ rt = [
32 32
33time = ["dep:embassy-time"] 33time = ["dep:embassy-time"]
34 34
35defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-usb-driver?/defmt", "embassy-embedded-hal/defmt"] 35defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "embassy-usb-driver?/defmt", "embassy-embedded-hal/defmt"]
36 36
37# Enable nightly-only features 37# Enable nightly-only features
38nightly = ["embedded-hal-1", "embedded-hal-async", "dep:embassy-usb-driver", "embedded-storage-async", "dep:embedded-io-async", "embassy-embedded-hal/nightly"] 38nightly = ["embedded-hal-1", "embedded-hal-async", "dep:embassy-usb-driver", "embedded-storage-async", "dep:embedded-io-async", "embassy-embedded-hal/nightly"]
@@ -98,8 +98,8 @@ embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
98embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true } 98embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true }
99 99
100embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 100embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
101embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11", optional = true} 101embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true}
102embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true} 102embedded-hal-async = { version = "=1.0.0-rc.1", optional = true}
103embedded-io = { version = "0.5.0" } 103embedded-io = { version = "0.5.0" }
104embedded-io-async = { version = "0.5.0", optional = true } 104embedded-io-async = { version = "0.5.0", optional = true }
105 105
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index 4673a0175..d131a43dd 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -378,6 +378,9 @@ impl<'d, T: Instance> Drop for Spim<'d, T> {
378 gpio::deconfigure_pin(r.psel.miso.read().bits()); 378 gpio::deconfigure_pin(r.psel.miso.read().bits());
379 gpio::deconfigure_pin(r.psel.mosi.read().bits()); 379 gpio::deconfigure_pin(r.psel.mosi.read().bits());
380 380
381 // Disable all events interrupts
382 T::Interrupt::disable();
383
381 trace!("spim drop: done"); 384 trace!("spim drop: done");
382 } 385 }
383} 386}
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index e79df3561..95434e7a7 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -949,51 +949,3 @@ mod eh02 {
949 } 949 }
950 } 950 }
951} 951}
952
953#[cfg(feature = "unstable-traits")]
954mod eh1 {
955 use super::*;
956
957 impl embedded_hal_1::serial::Error for Error {
958 fn kind(&self) -> embedded_hal_1::serial::ErrorKind {
959 match *self {
960 Self::BufferTooLong => embedded_hal_1::serial::ErrorKind::Other,
961 Self::BufferNotInRAM => embedded_hal_1::serial::ErrorKind::Other,
962 }
963 }
964 }
965
966 // =====================
967
968 impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for Uarte<'d, T> {
969 type Error = Error;
970 }
971
972 impl<'d, T: Instance> embedded_hal_1::serial::Write for Uarte<'d, T> {
973 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
974 self.blocking_write(buffer)
975 }
976
977 fn flush(&mut self) -> Result<(), Self::Error> {
978 Ok(())
979 }
980 }
981
982 impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteTx<'d, T> {
983 type Error = Error;
984 }
985
986 impl<'d, T: Instance> embedded_hal_1::serial::Write for UarteTx<'d, T> {
987 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
988 self.blocking_write(buffer)
989 }
990
991 fn flush(&mut self) -> Result<(), Self::Error> {
992 Ok(())
993 }
994 }
995
996 impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteRx<'d, T> {
997 type Error = Error;
998 }
999}
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index b1680d487..b9ebcc866 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -85,9 +85,9 @@ fixed = "1.23.1"
85rp-pac = { version = "6" } 85rp-pac = { version = "6" }
86 86
87embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 87embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
88embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11", optional = true} 88embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true}
89embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true} 89embedded-hal-async = { version = "=1.0.0-rc.1", optional = true}
90embedded-hal-nb = { version = "=1.0.0-alpha.3", optional = true} 90embedded-hal-nb = { version = "=1.0.0-rc.1", optional = true}
91 91
92paste = "1.0" 92paste = "1.0"
93pio-proc = {version= "0.2" } 93pio-proc = {version= "0.2" }
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs
index c8f741804..45ca21a75 100644
--- a/embassy-rp/src/dma.rs
+++ b/embassy-rp/src/dma.rs
@@ -76,7 +76,8 @@ pub unsafe fn write<'a, C: Channel, W: Word>(
76 ) 76 )
77} 77}
78 78
79static DUMMY: u32 = 0; 79// static mut so that this is allocated in RAM.
80static mut DUMMY: u32 = 0;
80 81
81pub unsafe fn write_repeated<'a, C: Channel, W: Word>( 82pub unsafe fn write_repeated<'a, C: Channel, W: Word>(
82 ch: impl Peripheral<P = C> + 'a, 83 ch: impl Peripheral<P = C> + 'a,
@@ -86,7 +87,7 @@ pub unsafe fn write_repeated<'a, C: Channel, W: Word>(
86) -> Transfer<'a, C> { 87) -> Transfer<'a, C> {
87 copy_inner( 88 copy_inner(
88 ch, 89 ch,
89 &DUMMY as *const u32, 90 &mut DUMMY as *const u32,
90 to as *mut u32, 91 to as *mut u32,
91 len, 92 len,
92 W::size(), 93 W::size(),
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs
index 70d867319..1c1c2449e 100644
--- a/embassy-rp/src/flash.rs
+++ b/embassy-rp/src/flash.rs
@@ -102,7 +102,7 @@ pub struct Flash<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> {
102} 102}
103 103
104impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SIZE> { 104impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SIZE> {
105 pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 105 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
106 trace!( 106 trace!(
107 "Reading from 0x{:x} to 0x{:x}", 107 "Reading from 0x{:x} to 0x{:x}",
108 FLASH_BASE as u32 + offset, 108 FLASH_BASE as u32 + offset,
@@ -120,7 +120,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI
120 FLASH_SIZE 120 FLASH_SIZE
121 } 121 }
122 122
123 pub fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { 123 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
124 check_erase(self, from, to)?; 124 check_erase(self, from, to)?;
125 125
126 trace!( 126 trace!(
@@ -136,7 +136,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI
136 Ok(()) 136 Ok(())
137 } 137 }
138 138
139 pub fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { 139 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
140 check_write(self, offset, bytes.len())?; 140 check_write(self, offset, bytes.len())?;
141 141
142 trace!("Writing {:?} bytes to 0x{:x}", bytes.len(), FLASH_BASE as u32 + offset); 142 trace!("Writing {:?} bytes to 0x{:x}", bytes.len(), FLASH_BASE as u32 + offset);
@@ -233,13 +233,13 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI
233 } 233 }
234 234
235 /// Read SPI flash unique ID 235 /// Read SPI flash unique ID
236 pub fn unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> { 236 pub fn blocking_unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> {
237 unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid))? }; 237 unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid))? };
238 Ok(()) 238 Ok(())
239 } 239 }
240 240
241 /// Read SPI flash JEDEC ID 241 /// Read SPI flash JEDEC ID
242 pub fn jedec_id(&mut self) -> Result<u32, Error> { 242 pub fn blocking_jedec_id(&mut self) -> Result<u32, Error> {
243 let mut jedec = None; 243 let mut jedec = None;
244 unsafe { 244 unsafe {
245 self.in_ram(|| { 245 self.in_ram(|| {
@@ -251,7 +251,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI
251} 251}
252 252
253impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Blocking, FLASH_SIZE> { 253impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Blocking, FLASH_SIZE> {
254 pub fn new(_flash: impl Peripheral<P = T> + 'd) -> Self { 254 pub fn new_blocking(_flash: impl Peripheral<P = T> + 'd) -> Self {
255 Self { 255 Self {
256 dma: None, 256 dma: None,
257 phantom: PhantomData, 257 phantom: PhantomData,
@@ -310,47 +310,8 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> {
310 transfer, 310 transfer,
311 }) 311 })
312 } 312 }
313}
314
315impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> ErrorType for Flash<'d, T, M, FLASH_SIZE> {
316 type Error = Error;
317}
318
319impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> ReadNorFlash for Flash<'d, T, M, FLASH_SIZE> {
320 const READ_SIZE: usize = READ_SIZE;
321
322 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
323 self.read(offset, bytes)
324 }
325
326 fn capacity(&self) -> usize {
327 self.capacity()
328 }
329}
330
331impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<'d, T, M, FLASH_SIZE> {}
332
333impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, M, FLASH_SIZE> {
334 const WRITE_SIZE: usize = WRITE_SIZE;
335
336 const ERASE_SIZE: usize = ERASE_SIZE;
337
338 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
339 self.erase(from, to)
340 }
341 313
342 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { 314 pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
343 self.write(offset, bytes)
344 }
345}
346
347#[cfg(feature = "nightly")]
348impl<'d, T: Instance, const FLASH_SIZE: usize> embedded_storage_async::nor_flash::ReadNorFlash
349 for Flash<'d, T, Async, FLASH_SIZE>
350{
351 const READ_SIZE: usize = ASYNC_READ_SIZE;
352
353 async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
354 use core::mem::MaybeUninit; 315 use core::mem::MaybeUninit;
355 316
356 // Checked early to simplify address validity checks 317 // Checked early to simplify address validity checks
@@ -389,6 +350,49 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> embedded_storage_async::nor_flash
389 350
390 Ok(()) 351 Ok(())
391 } 352 }
353}
354
355impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> ErrorType for Flash<'d, T, M, FLASH_SIZE> {
356 type Error = Error;
357}
358
359impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> ReadNorFlash for Flash<'d, T, M, FLASH_SIZE> {
360 const READ_SIZE: usize = READ_SIZE;
361
362 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
363 self.blocking_read(offset, bytes)
364 }
365
366 fn capacity(&self) -> usize {
367 self.capacity()
368 }
369}
370
371impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<'d, T, M, FLASH_SIZE> {}
372
373impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, M, FLASH_SIZE> {
374 const WRITE_SIZE: usize = WRITE_SIZE;
375
376 const ERASE_SIZE: usize = ERASE_SIZE;
377
378 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
379 self.blocking_erase(from, to)
380 }
381
382 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
383 self.blocking_write(offset, bytes)
384 }
385}
386
387#[cfg(feature = "nightly")]
388impl<'d, T: Instance, const FLASH_SIZE: usize> embedded_storage_async::nor_flash::ReadNorFlash
389 for Flash<'d, T, Async, FLASH_SIZE>
390{
391 const READ_SIZE: usize = ASYNC_READ_SIZE;
392
393 async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
394 self.read(offset, bytes).await
395 }
392 396
393 fn capacity(&self) -> usize { 397 fn capacity(&self) -> usize {
394 self.capacity() 398 self.capacity()
@@ -404,11 +408,11 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> embedded_storage_async::nor_flash
404 const ERASE_SIZE: usize = ERASE_SIZE; 408 const ERASE_SIZE: usize = ERASE_SIZE;
405 409
406 async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { 410 async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
407 self.erase(from, to) 411 self.blocking_erase(from, to)
408 } 412 }
409 413
410 async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { 414 async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
411 self.write(offset, bytes) 415 self.blocking_write(offset, bytes)
412 } 416 }
413} 417}
414 418
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index 58dc0bf1a..e57b72599 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -749,15 +749,15 @@ mod eh02 {
749mod eh1 { 749mod eh1 {
750 use super::*; 750 use super::*;
751 751
752 impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for BufferedUart<'d, T> { 752 impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUartRx<'d, T> {
753 type Error = Error; 753 type Error = Error;
754 } 754 }
755 755
756 impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for BufferedUartTx<'d, T> { 756 impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUartTx<'d, T> {
757 type Error = Error; 757 type Error = Error;
758 } 758 }
759 759
760 impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for BufferedUartRx<'d, T> { 760 impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUart<'d, T> {
761 type Error = Error; 761 type Error = Error;
762 } 762 }
763 763
@@ -767,16 +767,6 @@ mod eh1 {
767 } 767 }
768 } 768 }
769 769
770 impl<'d, T: Instance> embedded_hal_1::serial::Write for BufferedUartTx<'d, T> {
771 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
772 self.blocking_write(buffer).map(drop)
773 }
774
775 fn flush(&mut self) -> Result<(), Self::Error> {
776 self.blocking_flush()
777 }
778 }
779
780 impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> { 770 impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> {
781 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 771 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
782 self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) 772 self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
@@ -793,16 +783,6 @@ mod eh1 {
793 } 783 }
794 } 784 }
795 785
796 impl<'d, T: Instance> embedded_hal_1::serial::Write for BufferedUart<'d, T> {
797 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
798 self.blocking_write(buffer).map(drop)
799 }
800
801 fn flush(&mut self) -> Result<(), Self::Error> {
802 self.blocking_flush()
803 }
804 }
805
806 impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> { 786 impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> {
807 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 787 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
808 self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) 788 self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index 00070b80a..202b0883e 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -807,26 +807,26 @@ mod eh02 {
807mod eh1 { 807mod eh1 {
808 use super::*; 808 use super::*;
809 809
810 impl embedded_hal_1::serial::Error for Error { 810 impl embedded_hal_nb::serial::Error for Error {
811 fn kind(&self) -> embedded_hal_1::serial::ErrorKind { 811 fn kind(&self) -> embedded_hal_nb::serial::ErrorKind {
812 match *self { 812 match *self {
813 Self::Framing => embedded_hal_1::serial::ErrorKind::FrameFormat, 813 Self::Framing => embedded_hal_nb::serial::ErrorKind::FrameFormat,
814 Self::Break => embedded_hal_1::serial::ErrorKind::Other, 814 Self::Break => embedded_hal_nb::serial::ErrorKind::Other,
815 Self::Overrun => embedded_hal_1::serial::ErrorKind::Overrun, 815 Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun,
816 Self::Parity => embedded_hal_1::serial::ErrorKind::Parity, 816 Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity,
817 } 817 }
818 } 818 }
819 } 819 }
820 820
821 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for Uart<'d, T, M> { 821 impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, M> {
822 type Error = Error; 822 type Error = Error;
823 } 823 }
824 824
825 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartTx<'d, T, M> { 825 impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, M> {
826 type Error = Error; 826 type Error = Error;
827 } 827 }
828 828
829 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, T, M> { 829 impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, T, M> {
830 type Error = Error; 830 type Error = Error;
831 } 831 }
832 832
@@ -851,16 +851,6 @@ mod eh1 {
851 } 851 }
852 } 852 }
853 853
854 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::Write for UartTx<'d, T, M> {
855 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
856 self.blocking_write(buffer)
857 }
858
859 fn flush(&mut self) -> Result<(), Self::Error> {
860 self.blocking_flush()
861 }
862 }
863
864 impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, M> { 854 impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, M> {
865 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 855 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
866 self.blocking_write(&[char]).map_err(nb::Error::Other) 856 self.blocking_write(&[char]).map_err(nb::Error::Other)
@@ -877,16 +867,6 @@ mod eh1 {
877 } 867 }
878 } 868 }
879 869
880 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::Write for Uart<'d, T, M> {
881 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
882 self.blocking_write(buffer)
883 }
884
885 fn flush(&mut self) -> Result<(), Self::Error> {
886 self.blocking_flush()
887 }
888 }
889
890 impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> { 870 impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> {
891 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 871 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
892 self.blocking_write(&[char]).map_err(nb::Error::Other) 872 self.blocking_write(&[char]).map_err(nb::Error::Other)
diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs
index f8e3a2b08..bfc4f1ee8 100644
--- a/embassy-stm32-wpan/src/mac/driver.rs
+++ b/embassy-stm32-wpan/src/mac/driver.rs
@@ -28,7 +28,9 @@ impl<'d> embassy_net_driver::Driver for Driver<'d> {
28 type TxToken<'a> = TxToken<'d> where Self: 'a; 28 type TxToken<'a> = TxToken<'d> where Self: 'a;
29 29
30 fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { 30 fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
31 if self.runner.rx_channel.poll_ready_to_receive(cx) && self.runner.tx_buf_channel.poll_ready_to_receive(cx) { 31 if self.runner.rx_channel.poll_ready_to_receive(cx).is_ready()
32 && self.runner.tx_buf_channel.poll_ready_to_receive(cx).is_ready()
33 {
32 Some(( 34 Some((
33 RxToken { 35 RxToken {
34 rx: &self.runner.rx_channel, 36 rx: &self.runner.rx_channel,
@@ -44,7 +46,7 @@ impl<'d> embassy_net_driver::Driver for Driver<'d> {
44 } 46 }
45 47
46 fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> { 48 fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> {
47 if self.runner.tx_buf_channel.poll_ready_to_receive(cx) { 49 if self.runner.tx_buf_channel.poll_ready_to_receive(cx).is_ready() {
48 Some(TxToken { 50 Some(TxToken {
49 tx: &self.runner.tx_channel, 51 tx: &self.runner.tx_channel,
50 tx_buf: &self.runner.tx_buf_channel, 52 tx_buf: &self.runner.tx_buf_channel,
@@ -91,7 +93,7 @@ impl<'d> embassy_net_driver::RxToken for RxToken<'d> {
91 { 93 {
92 // Only valid data events should be put into the queue 94 // Only valid data events should be put into the queue
93 95
94 let data_event = match self.rx.try_recv().unwrap() { 96 let data_event = match self.rx.try_receive().unwrap() {
95 MacEvent::McpsDataInd(data_event) => data_event, 97 MacEvent::McpsDataInd(data_event) => data_event,
96 _ => unreachable!(), 98 _ => unreachable!(),
97 }; 99 };
@@ -111,7 +113,7 @@ impl<'d> embassy_net_driver::TxToken for TxToken<'d> {
111 F: FnOnce(&mut [u8]) -> R, 113 F: FnOnce(&mut [u8]) -> R,
112 { 114 {
113 // Only valid tx buffers should be put into the queue 115 // Only valid tx buffers should be put into the queue
114 let buf = self.tx_buf.try_recv().unwrap(); 116 let buf = self.tx_buf.try_receive().unwrap();
115 let r = f(&mut buf[..len]); 117 let r = f(&mut buf[..len]);
116 118
117 // The tx channel should always be of equal capacity to the tx_buf channel 119 // The tx channel should always be of equal capacity to the tx_buf channel
diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs
index 1be6df8a4..d3099b6b7 100644
--- a/embassy-stm32-wpan/src/mac/runner.rs
+++ b/embassy-stm32-wpan/src/mac/runner.rs
@@ -73,7 +73,7 @@ impl<'a> Runner<'a> {
73 let mut msdu_handle = 0x02; 73 let mut msdu_handle = 0x02;
74 74
75 loop { 75 loop {
76 let (buf, len) = self.tx_channel.recv().await; 76 let (buf, len) = self.tx_channel.receive().await;
77 let _wm = self.write_mutex.lock().await; 77 let _wm = self.write_mutex.lock().await;
78 78
79 // The mutex should be dropped on the next loop iteration 79 // The mutex should be dropped on the next loop iteration
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 0d713f60d..fe5dc443a 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -40,9 +40,9 @@ embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
40embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } 40embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
41 41
42embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 42embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
43embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11", optional = true} 43embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true}
44embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true} 44embedded-hal-async = { version = "=1.0.0-rc.1", optional = true}
45embedded-hal-nb = { version = "=1.0.0-alpha.3", optional = true} 45embedded-hal-nb = { version = "=1.0.0-rc.1", optional = true}
46 46
47embedded-storage = "0.3.0" 47embedded-storage = "0.3.0"
48embedded-storage-async = { version = "0.4.0", optional = true } 48embedded-storage-async = { version = "0.4.0", optional = true }
@@ -57,7 +57,7 @@ sdio-host = "0.5.0"
57embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } 57embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
58critical-section = "1.1" 58critical-section = "1.1"
59atomic-polyfill = "1.0.1" 59atomic-polyfill = "1.0.1"
60stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-82a24863823a3daf0ca664c7fdf008379d0a0d42" } 60stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2b87e34c661e19ff6dc603fabfe7fe99ab7261f7" }
61vcell = "0.1.3" 61vcell = "0.1.3"
62bxcan = "0.7.0" 62bxcan = "0.7.0"
63nb = "1.0.0" 63nb = "1.0.0"
@@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] }
76[build-dependencies] 76[build-dependencies]
77proc-macro2 = "1.0.36" 77proc-macro2 = "1.0.36"
78quote = "1.0.15" 78quote = "1.0.15"
79stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-82a24863823a3daf0ca664c7fdf008379d0a0d42", default-features = false, features = ["metadata"]} 79stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2b87e34c661e19ff6dc603fabfe7fe99ab7261f7", default-features = false, features = ["metadata"]}
80 80
81[features] 81[features]
82default = ["rt"] 82default = ["rt"]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 30e25aefd..8a731620f 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -310,7 +310,11 @@ fn main() {
310 310
311 for p in METADATA.peripherals { 311 for p in METADATA.peripherals {
312 // generating RccPeripheral impl for H7 ADC3 would result in bad frequency 312 // generating RccPeripheral impl for H7 ADC3 would result in bad frequency
313 if !singletons.contains(&p.name.to_string()) || (p.name == "ADC3" && METADATA.line.starts_with("STM32H7")) { 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 {
314 continue; 318 continue;
315 } 319 }
316 320
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 94a8538bf..e57889aa6 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -1,6 +1,6 @@
1#![macro_use] 1#![macro_use]
2 2
3#[cfg(not(adc_f3))] 3#[cfg(not(any(adc_f3, adc_f3_v2)))]
4#[cfg_attr(adc_f1, path = "f1.rs")] 4#[cfg_attr(adc_f1, path = "f1.rs")]
5#[cfg_attr(adc_v1, path = "v1.rs")] 5#[cfg_attr(adc_v1, path = "v1.rs")]
6#[cfg_attr(adc_v2, path = "v2.rs")] 6#[cfg_attr(adc_v2, path = "v2.rs")]
@@ -8,16 +8,16 @@
8#[cfg_attr(adc_v4, path = "v4.rs")] 8#[cfg_attr(adc_v4, path = "v4.rs")]
9mod _version; 9mod _version;
10 10
11#[cfg(not(any(adc_f1, adc_f3)))] 11#[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))]
12mod resolution; 12mod resolution;
13mod sample_time; 13mod sample_time;
14 14
15#[cfg(not(adc_f3))] 15#[cfg(not(any(adc_f3, adc_f3_v2)))]
16#[allow(unused)] 16#[allow(unused)]
17pub use _version::*; 17pub use _version::*;
18#[cfg(not(any(adc_f1, adc_f3)))] 18#[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))]
19pub use resolution::Resolution; 19pub use resolution::Resolution;
20#[cfg(not(adc_f3))] 20#[cfg(not(any(adc_f3, adc_f3_v2)))]
21pub use sample_time::SampleTime; 21pub use sample_time::SampleTime;
22 22
23use crate::peripherals; 23use crate::peripherals;
@@ -25,14 +25,14 @@ use crate::peripherals;
25pub struct Adc<'d, T: Instance> { 25pub struct Adc<'d, T: Instance> {
26 #[allow(unused)] 26 #[allow(unused)]
27 adc: crate::PeripheralRef<'d, T>, 27 adc: crate::PeripheralRef<'d, T>,
28 #[cfg(not(adc_f3))] 28 #[cfg(not(any(adc_f3, adc_f3_v2)))]
29 sample_time: SampleTime, 29 sample_time: SampleTime,
30} 30}
31 31
32pub(crate) mod sealed { 32pub(crate) mod sealed {
33 pub trait Instance { 33 pub trait Instance {
34 fn regs() -> crate::pac::adc::Adc; 34 fn regs() -> crate::pac::adc::Adc;
35 #[cfg(not(any(adc_f1, adc_v1, adc_f3)))] 35 #[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))]
36 fn common_regs() -> crate::pac::adccommon::AdcCommon; 36 fn common_regs() -> crate::pac::adccommon::AdcCommon;
37 } 37 }
38 38
@@ -60,7 +60,7 @@ foreach_peripheral!(
60 fn regs() -> crate::pac::adc::Adc { 60 fn regs() -> crate::pac::adc::Adc {
61 crate::pac::$inst 61 crate::pac::$inst
62 } 62 }
63 #[cfg(not(any(adc_f1, adc_v1, adc_f3)))] 63 #[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))]
64 fn common_regs() -> crate::pac::adccommon::AdcCommon { 64 fn common_regs() -> crate::pac::adccommon::AdcCommon {
65 foreach_peripheral!{ 65 foreach_peripheral!{
66 (adccommon, $common_inst:ident) => { 66 (adccommon, $common_inst:ident) => {
diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs
index df0525560..5480e7a77 100644
--- a/embassy-stm32/src/adc/sample_time.rs
+++ b/embassy-stm32/src/adc/sample_time.rs
@@ -1,4 +1,4 @@
1#[cfg(not(adc_f3))] 1#[cfg(not(any(adc_f3, 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.")]
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index fb223e4a9..7ad13cece 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -478,7 +478,7 @@ impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> {
478 pub async fn read(&mut self) -> Result<Envelope, BusError> { 478 pub async fn read(&mut self) -> Result<Envelope, BusError> {
479 poll_fn(|cx| { 479 poll_fn(|cx| {
480 T::state().err_waker.register(cx.waker()); 480 T::state().err_waker.register(cx.waker());
481 if let Poll::Ready(envelope) = T::state().rx_queue.recv().poll_unpin(cx) { 481 if let Poll::Ready(envelope) = T::state().rx_queue.receive().poll_unpin(cx) {
482 return Poll::Ready(Ok(envelope)); 482 return Poll::Ready(Ok(envelope));
483 } else if let Some(err) = self.curr_error() { 483 } else if let Some(err) = self.curr_error() {
484 return Poll::Ready(Err(err)); 484 return Poll::Ready(Err(err));
@@ -493,7 +493,7 @@ impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> {
493 /// 493 ///
494 /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. 494 /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
495 pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { 495 pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
496 if let Ok(envelope) = T::state().rx_queue.try_recv() { 496 if let Ok(envelope) = T::state().rx_queue.try_receive() {
497 return Ok(envelope); 497 return Ok(envelope);
498 } 498 }
499 499
@@ -506,14 +506,7 @@ impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> {
506 506
507 /// Waits while receive queue is empty. 507 /// Waits while receive queue is empty.
508 pub async fn wait_not_empty(&mut self) { 508 pub async fn wait_not_empty(&mut self) {
509 poll_fn(|cx| { 509 poll_fn(|cx| T::state().rx_queue.poll_ready_to_receive(cx)).await
510 if T::state().rx_queue.poll_ready_to_receive(cx) {
511 Poll::Ready(())
512 } else {
513 Poll::Pending
514 }
515 })
516 .await
517 } 510 }
518 511
519 fn curr_error(&self) -> Option<BusError> { 512 fn curr_error(&self) -> Option<BusError> {
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index 60f4fbd09..20ff29bef 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -393,6 +393,10 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
393 fn reset_complete_count(&mut self) -> usize { 393 fn reset_complete_count(&mut self) -> usize {
394 STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel) 394 STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel)
395 } 395 }
396
397 fn set_waker(&mut self, waker: &Waker) {
398 STATE.ch_wakers[self.0.index()].register(waker);
399 }
396} 400}
397 401
398pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { 402pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
@@ -463,7 +467,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
463 } 467 }
464 468
465 pub fn clear(&mut self) { 469 pub fn clear(&mut self) {
466 self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow())); 470 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
467 } 471 }
468 472
469 /// Read elements from the ring buffer 473 /// Read elements from the ring buffer
@@ -472,7 +476,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
472 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read 476 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
473 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. 477 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
474 pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { 478 pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
475 self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf) 479 self.ringbuf.read(&mut DmaCtrlImpl(self.channel.reborrow()), buf)
476 } 480 }
477 481
478 /// Read an exact number of elements from the ringbuffer. 482 /// Read an exact number of elements from the ringbuffer.
@@ -487,39 +491,18 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
487 /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source. 491 /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source.
488 /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. 492 /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning.
489 pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> { 493 pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> {
490 use core::future::poll_fn; 494 self.ringbuf
491 use core::sync::atomic::compiler_fence; 495 .read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
492 496 .await
493 let mut read_data = 0;
494 let buffer_len = buffer.len();
495
496 poll_fn(|cx| {
497 self.set_waker(cx.waker());
498
499 compiler_fence(Ordering::SeqCst);
500
501 match self.read(&mut buffer[read_data..buffer_len]) {
502 Ok((len, remaining)) => {
503 read_data += len;
504 if read_data == buffer_len {
505 Poll::Ready(Ok(remaining))
506 } else {
507 Poll::Pending
508 }
509 }
510 Err(e) => Poll::Ready(Err(e)),
511 }
512 })
513 .await
514 } 497 }
515 498
516 /// The capacity of the ringbuffer. 499 /// The capacity of the ringbuffer.
517 pub fn cap(&self) -> usize { 500 pub const fn cap(&self) -> usize {
518 self.ringbuf.cap() 501 self.ringbuf.cap()
519 } 502 }
520 503
521 pub fn set_waker(&mut self, waker: &Waker) { 504 pub fn set_waker(&mut self, waker: &Waker) {
522 STATE.ch_wakers[self.channel.index()].register(waker); 505 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
523 } 506 }
524 507
525 fn clear_irqs(&mut self) { 508 fn clear_irqs(&mut self) {
@@ -628,50 +611,29 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
628 } 611 }
629 612
630 pub fn clear(&mut self) { 613 pub fn clear(&mut self) {
631 self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow())); 614 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
632 } 615 }
633 616
634 /// Write elements to the ring buffer 617 /// Write elements to the ring buffer
635 /// Return a tuple of the length written and the length remaining in the buffer 618 /// Return a tuple of the length written and the length remaining in the buffer
636 pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { 619 pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
637 self.ringbuf.write(DmaCtrlImpl(self.channel.reborrow()), buf) 620 self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf)
638 } 621 }
639 622
640 /// Write an exact number of elements to the ringbuffer. 623 /// Write an exact number of elements to the ringbuffer.
641 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> { 624 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> {
642 use core::future::poll_fn; 625 self.ringbuf
643 use core::sync::atomic::compiler_fence; 626 .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
644 627 .await
645 let mut written_data = 0;
646 let buffer_len = buffer.len();
647
648 poll_fn(|cx| {
649 self.set_waker(cx.waker());
650
651 compiler_fence(Ordering::SeqCst);
652
653 match self.write(&buffer[written_data..buffer_len]) {
654 Ok((len, remaining)) => {
655 written_data += len;
656 if written_data == buffer_len {
657 Poll::Ready(Ok(remaining))
658 } else {
659 Poll::Pending
660 }
661 }
662 Err(e) => Poll::Ready(Err(e)),
663 }
664 })
665 .await
666 } 628 }
667 629
668 /// The capacity of the ringbuffer. 630 /// The capacity of the ringbuffer.
669 pub fn cap(&self) -> usize { 631 pub const fn cap(&self) -> usize {
670 self.ringbuf.cap() 632 self.ringbuf.cap()
671 } 633 }
672 634
673 pub fn set_waker(&mut self, waker: &Waker) { 635 pub fn set_waker(&mut self, waker: &Waker) {
674 STATE.ch_wakers[self.channel.index()].register(waker); 636 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
675 } 637 }
676 638
677 fn clear_irqs(&mut self) { 639 fn clear_irqs(&mut self) {
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index 9cd7aa8d5..5033ae477 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -623,6 +623,10 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
623 fn reset_complete_count(&mut self) -> usize { 623 fn reset_complete_count(&mut self) -> usize {
624 STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel) 624 STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel)
625 } 625 }
626
627 fn set_waker(&mut self, waker: &Waker) {
628 STATE.ch_wakers[self.0.index()].register(waker);
629 }
626} 630}
627 631
628pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { 632pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
@@ -708,7 +712,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
708 } 712 }
709 713
710 pub fn clear(&mut self) { 714 pub fn clear(&mut self) {
711 self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow())); 715 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
712 } 716 }
713 717
714 /// Read elements from the ring buffer 718 /// Read elements from the ring buffer
@@ -717,7 +721,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
717 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read 721 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
718 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. 722 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
719 pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { 723 pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
720 self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf) 724 self.ringbuf.read(&mut DmaCtrlImpl(self.channel.reborrow()), buf)
721 } 725 }
722 726
723 /// Read an exact number of elements from the ringbuffer. 727 /// Read an exact number of elements from the ringbuffer.
@@ -732,39 +736,18 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
732 /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source. 736 /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source.
733 /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. 737 /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning.
734 pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> { 738 pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> {
735 use core::future::poll_fn; 739 self.ringbuf
736 use core::sync::atomic::compiler_fence; 740 .read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
737 741 .await
738 let mut read_data = 0;
739 let buffer_len = buffer.len();
740
741 poll_fn(|cx| {
742 self.set_waker(cx.waker());
743
744 compiler_fence(Ordering::SeqCst);
745
746 match self.read(&mut buffer[read_data..buffer_len]) {
747 Ok((len, remaining)) => {
748 read_data += len;
749 if read_data == buffer_len {
750 Poll::Ready(Ok(remaining))
751 } else {
752 Poll::Pending
753 }
754 }
755 Err(e) => Poll::Ready(Err(e)),
756 }
757 })
758 .await
759 } 742 }
760 743
761 // The capacity of the ringbuffer 744 // The capacity of the ringbuffer
762 pub fn cap(&self) -> usize { 745 pub const fn cap(&self) -> usize {
763 self.ringbuf.cap() 746 self.ringbuf.cap()
764 } 747 }
765 748
766 pub fn set_waker(&mut self, waker: &Waker) { 749 pub fn set_waker(&mut self, waker: &Waker) {
767 STATE.ch_wakers[self.channel.index()].register(waker); 750 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
768 } 751 }
769 752
770 fn clear_irqs(&mut self) { 753 fn clear_irqs(&mut self) {
@@ -890,50 +873,29 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
890 } 873 }
891 874
892 pub fn clear(&mut self) { 875 pub fn clear(&mut self) {
893 self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow())); 876 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
894 } 877 }
895 878
896 /// Write elements from the ring buffer 879 /// Write elements from the ring buffer
897 /// Return a tuple of the length written and the length remaining in the buffer 880 /// Return a tuple of the length written and the length remaining in the buffer
898 pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { 881 pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
899 self.ringbuf.write(DmaCtrlImpl(self.channel.reborrow()), buf) 882 self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf)
900 } 883 }
901 884
902 /// Write an exact number of elements to the ringbuffer. 885 /// Write an exact number of elements to the ringbuffer.
903 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> { 886 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> {
904 use core::future::poll_fn; 887 self.ringbuf
905 use core::sync::atomic::compiler_fence; 888 .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
906 889 .await
907 let mut written_data = 0;
908 let buffer_len = buffer.len();
909
910 poll_fn(|cx| {
911 self.set_waker(cx.waker());
912
913 compiler_fence(Ordering::SeqCst);
914
915 match self.write(&buffer[written_data..buffer_len]) {
916 Ok((len, remaining)) => {
917 written_data += len;
918 if written_data == buffer_len {
919 Poll::Ready(Ok(remaining))
920 } else {
921 Poll::Pending
922 }
923 }
924 Err(e) => Poll::Ready(Err(e)),
925 }
926 })
927 .await
928 } 890 }
929 891
930 // The capacity of the ringbuffer 892 // The capacity of the ringbuffer
931 pub fn cap(&self) -> usize { 893 pub const fn cap(&self) -> usize {
932 self.ringbuf.cap() 894 self.ringbuf.cap()
933 } 895 }
934 896
935 pub fn set_waker(&mut self, waker: &Waker) { 897 pub fn set_waker(&mut self, waker: &Waker) {
936 STATE.ch_wakers[self.channel.index()].register(waker); 898 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
937 } 899 }
938 900
939 fn clear_irqs(&mut self) { 901 fn clear_irqs(&mut self) {
diff --git a/embassy-stm32/src/dma/ringbuffer.rs b/embassy-stm32/src/dma/ringbuffer.rs
index 6ce59e455..c9f7a3026 100644
--- a/embassy-stm32/src/dma/ringbuffer.rs
+++ b/embassy-stm32/src/dma/ringbuffer.rs
@@ -1,7 +1,9 @@
1#![cfg_attr(gpdma, allow(unused))] 1#![cfg_attr(gpdma, allow(unused))]
2 2
3use core::future::poll_fn;
3use core::ops::Range; 4use core::ops::Range;
4use core::sync::atomic::{compiler_fence, Ordering}; 5use core::sync::atomic::{compiler_fence, Ordering};
6use core::task::{Poll, Waker};
5 7
6use super::word::Word; 8use super::word::Word;
7 9
@@ -49,6 +51,9 @@ pub trait DmaCtrl {
49 51
50 /// Reset the transfer completed counter to 0 and return the value just prior to the reset. 52 /// Reset the transfer completed counter to 0 and return the value just prior to the reset.
51 fn reset_complete_count(&mut self) -> usize; 53 fn reset_complete_count(&mut self) -> usize;
54
55 /// Set the waker for a running poll_fn
56 fn set_waker(&mut self, waker: &Waker);
52} 57}
53 58
54impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { 59impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
@@ -57,7 +62,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
57 } 62 }
58 63
59 /// Reset the ring buffer to its initial state 64 /// Reset the ring buffer to its initial state
60 pub fn clear(&mut self, mut dma: impl DmaCtrl) { 65 pub fn clear(&mut self, dma: &mut impl DmaCtrl) {
61 self.start = 0; 66 self.start = 0;
62 dma.reset_complete_count(); 67 dma.reset_complete_count();
63 } 68 }
@@ -68,8 +73,43 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
68 } 73 }
69 74
70 /// The current position of the ringbuffer 75 /// The current position of the ringbuffer
71 fn pos(&self, remaining_transfers: usize) -> usize { 76 fn pos(&self, dma: &mut impl DmaCtrl) -> usize {
72 self.cap() - remaining_transfers 77 self.cap() - dma.get_remaining_transfers()
78 }
79
80 /// Read an exact number of elements from the ringbuffer.
81 ///
82 /// Returns the remaining number of elements available for immediate reading.
83 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
84 ///
85 /// Async/Wake Behavior:
86 /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point,
87 /// and when it wraps around. This means that when called with a buffer of length 'M', when this
88 /// ring buffer was created with a buffer of size 'N':
89 /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source.
90 /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning.
91 pub async fn read_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &mut [W]) -> Result<usize, OverrunError> {
92 let mut read_data = 0;
93 let buffer_len = buffer.len();
94
95 poll_fn(|cx| {
96 dma.set_waker(cx.waker());
97
98 compiler_fence(Ordering::SeqCst);
99
100 match self.read(dma, &mut buffer[read_data..buffer_len]) {
101 Ok((len, remaining)) => {
102 read_data += len;
103 if read_data == buffer_len {
104 Poll::Ready(Ok(remaining))
105 } else {
106 Poll::Pending
107 }
108 }
109 Err(e) => Poll::Ready(Err(e)),
110 }
111 })
112 .await
73 } 113 }
74 114
75 /// Read elements from the ring buffer 115 /// Read elements from the ring buffer
@@ -77,7 +117,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
77 /// If not all of the elements were read, then there will be some elements in the buffer remaining 117 /// If not all of the elements were read, then there will be some elements in the buffer remaining
78 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read 118 /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
79 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. 119 /// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
80 pub fn read(&mut self, mut dma: impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { 120 pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
81 /* 121 /*
82 This algorithm is optimistic: we assume we haven't overrun more than a full buffer and then check 122 This algorithm is optimistic: we assume we haven't overrun more than a full buffer and then check
83 after we've done our work to see we have. This is because on stm32, an interrupt is not guaranteed 123 after we've done our work to see we have. This is because on stm32, an interrupt is not guaranteed
@@ -93,7 +133,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
93 rather than the data we actually copied because it costs nothing and confirms an error condition 133 rather than the data we actually copied because it costs nothing and confirms an error condition
94 earlier. 134 earlier.
95 */ 135 */
96 let end = self.pos(dma.get_remaining_transfers()); 136 let end = self.pos(dma);
97 if self.start == end && dma.get_complete_count() == 0 { 137 if self.start == end && dma.get_complete_count() == 0 {
98 // No elements are available in the buffer 138 // No elements are available in the buffer
99 Ok((0, self.cap())) 139 Ok((0, self.cap()))
@@ -114,8 +154,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
114 then, get the current position of of the dma write and check 154 then, get the current position of of the dma write and check
115 if it's inside data we could have copied 155 if it's inside data we could have copied
116 */ 156 */
117 let (pos, complete_count) = 157 let (pos, complete_count) = critical_section::with(|_| (self.pos(dma), dma.get_complete_count()));
118 critical_section::with(|_| (self.pos(dma.get_remaining_transfers()), dma.get_complete_count()));
119 if (pos >= self.start && pos < end) || (complete_count > 0 && pos >= end) || complete_count > 1 { 158 if (pos >= self.start && pos < end) || (complete_count > 0 && pos >= end) || complete_count > 1 {
120 Err(OverrunError) 159 Err(OverrunError)
121 } else { 160 } else {
@@ -141,7 +180,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
141 then, get the current position of of the dma write and check 180 then, get the current position of of the dma write and check
142 if it's inside data we could have copied 181 if it's inside data we could have copied
143 */ 182 */
144 let pos = self.pos(dma.get_remaining_transfers()); 183 let pos = self.pos(dma);
145 if pos > self.start || pos < end || dma.get_complete_count() > 1 { 184 if pos > self.start || pos < end || dma.get_complete_count() > 1 {
146 Err(OverrunError) 185 Err(OverrunError)
147 } else { 186 } else {
@@ -169,7 +208,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
169 then, get the current position of of the dma write and check 208 then, get the current position of of the dma write and check
170 if it's inside data we could have copied 209 if it's inside data we could have copied
171 */ 210 */
172 let pos = self.pos(dma.get_remaining_transfers()); 211 let pos = self.pos(dma);
173 if pos > self.start || pos < end || dma.reset_complete_count() > 1 { 212 if pos > self.start || pos < end || dma.reset_complete_count() > 1 {
174 Err(OverrunError) 213 Err(OverrunError)
175 } else { 214 } else {
@@ -209,7 +248,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
209 } 248 }
210 249
211 /// Reset the ring buffer to its initial state 250 /// Reset the ring buffer to its initial state
212 pub fn clear(&mut self, mut dma: impl DmaCtrl) { 251 pub fn clear(&mut self, dma: &mut impl DmaCtrl) {
213 self.end = 0; 252 self.end = 0;
214 dma.reset_complete_count(); 253 dma.reset_complete_count();
215 } 254 }
@@ -220,14 +259,39 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
220 } 259 }
221 260
222 /// The current position of the ringbuffer 261 /// The current position of the ringbuffer
223 fn pos(&self, remaining_transfers: usize) -> usize { 262 fn pos(&self, dma: &mut impl DmaCtrl) -> usize {
224 self.cap() - remaining_transfers 263 self.cap() - dma.get_remaining_transfers()
264 }
265
266 /// Write an exact number of elements to the ringbuffer.
267 pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<usize, OverrunError> {
268 let mut written_data = 0;
269 let buffer_len = buffer.len();
270
271 poll_fn(|cx| {
272 dma.set_waker(cx.waker());
273
274 compiler_fence(Ordering::SeqCst);
275
276 match self.write(dma, &buffer[written_data..buffer_len]) {
277 Ok((len, remaining)) => {
278 written_data += len;
279 if written_data == buffer_len {
280 Poll::Ready(Ok(remaining))
281 } else {
282 Poll::Pending
283 }
284 }
285 Err(e) => Poll::Ready(Err(e)),
286 }
287 })
288 .await
225 } 289 }
226 290
227 /// Write elements from the ring buffer 291 /// Write elements from the ring buffer
228 /// Return a tuple of the length written and the capacity remaining to be written in the buffer 292 /// Return a tuple of the length written and the capacity remaining to be written in the buffer
229 pub fn write(&mut self, mut dma: impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { 293 pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> {
230 let start = self.pos(dma.get_remaining_transfers()); 294 let start = self.pos(dma);
231 if start > self.end { 295 if start > self.end {
232 // The occupied portion in the ring buffer DOES wrap 296 // The occupied portion in the ring buffer DOES wrap
233 let len = self.copy_from(buf, self.end..start); 297 let len = self.copy_from(buf, self.end..start);
@@ -235,8 +299,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
235 compiler_fence(Ordering::SeqCst); 299 compiler_fence(Ordering::SeqCst);
236 300
237 // Confirm that the DMA is not inside data we could have written 301 // Confirm that the DMA is not inside data we could have written
238 let (pos, complete_count) = 302 let (pos, complete_count) = critical_section::with(|_| (self.pos(dma), dma.get_complete_count()));
239 critical_section::with(|_| (self.pos(dma.get_remaining_transfers()), dma.get_complete_count()));
240 if (pos >= self.end && pos < start) || (complete_count > 0 && pos >= start) || complete_count > 1 { 303 if (pos >= self.end && pos < start) || (complete_count > 0 && pos >= start) || complete_count > 1 {
241 Err(OverrunError) 304 Err(OverrunError)
242 } else { 305 } else {
@@ -256,7 +319,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
256 compiler_fence(Ordering::SeqCst); 319 compiler_fence(Ordering::SeqCst);
257 320
258 // Confirm that the DMA is not inside data we could have written 321 // Confirm that the DMA is not inside data we could have written
259 let pos = self.pos(dma.get_remaining_transfers()); 322 let pos = self.pos(dma);
260 if pos > self.end || pos < start || dma.get_complete_count() > 1 { 323 if pos > self.end || pos < start || dma.get_complete_count() > 1 {
261 Err(OverrunError) 324 Err(OverrunError)
262 } else { 325 } else {
@@ -274,7 +337,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
274 compiler_fence(Ordering::SeqCst); 337 compiler_fence(Ordering::SeqCst);
275 338
276 // Confirm that the DMA is not inside data we could have written 339 // Confirm that the DMA is not inside data we could have written
277 let pos = self.pos(dma.get_remaining_transfers()); 340 let pos = self.pos(dma);
278 if pos > self.end || pos < start || dma.reset_complete_count() > 1 { 341 if pos > self.end || pos < start || dma.reset_complete_count() > 1 {
279 Err(OverrunError) 342 Err(OverrunError)
280 } else { 343 } else {
@@ -323,7 +386,7 @@ mod tests {
323 requests: cell::RefCell<vec::Vec<TestCircularTransferRequest>>, 386 requests: cell::RefCell<vec::Vec<TestCircularTransferRequest>>,
324 } 387 }
325 388
326 impl DmaCtrl for &mut TestCircularTransfer { 389 impl DmaCtrl for TestCircularTransfer {
327 fn get_remaining_transfers(&self) -> usize { 390 fn get_remaining_transfers(&self) -> usize {
328 match self.requests.borrow_mut().pop().unwrap() { 391 match self.requests.borrow_mut().pop().unwrap() {
329 TestCircularTransferRequest::PositionRequest(pos) => { 392 TestCircularTransferRequest::PositionRequest(pos) => {
@@ -350,6 +413,8 @@ mod tests {
350 _ => unreachable!(), 413 _ => unreachable!(),
351 } 414 }
352 } 415 }
416
417 fn set_waker(&mut self, waker: &Waker) {}
353 } 418 }
354 419
355 impl TestCircularTransfer { 420 impl TestCircularTransfer {
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index bb429d773..625bf13fc 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -11,7 +11,7 @@ pub const fn is_default_layout() -> bool {
11} 11}
12 12
13const fn is_dual_bank() -> bool { 13const fn is_dual_bank() -> bool {
14 FLASH_REGIONS.len() == 2 14 FLASH_REGIONS.len() >= 2
15} 15}
16 16
17pub fn get_flash_regions() -> &'static [&'static FlashRegion] { 17pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
@@ -49,6 +49,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
49 }; 49 };
50 bank.cr().write(|w| { 50 bank.cr().write(|w| {
51 w.set_pg(true); 51 w.set_pg(true);
52 #[cfg(flash_h7)]
52 w.set_psize(2); // 32 bits at once 53 w.set_psize(2); // 32 bits at once
53 }); 54 });
54 cortex_m::asm::isb(); 55 cortex_m::asm::isb();
@@ -85,7 +86,10 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
85 let bank = pac::FLASH.bank(sector.bank as usize); 86 let bank = pac::FLASH.bank(sector.bank as usize);
86 bank.cr().modify(|w| { 87 bank.cr().modify(|w| {
87 w.set_ser(true); 88 w.set_ser(true);
88 w.set_snb(sector.index_in_bank) 89 #[cfg(flash_h7)]
90 w.set_snb(sector.index_in_bank);
91 #[cfg(flash_h7ab)]
92 w.set_ssn(sector.index_in_bank);
89 }); 93 });
90 94
91 bank.cr().modify(|w| { 95 bank.cr().modify(|w| {
@@ -126,6 +130,10 @@ unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> {
126 error!("incerr"); 130 error!("incerr");
127 return Err(Error::Seq); 131 return Err(Error::Seq);
128 } 132 }
133 if sr.crcrderr() {
134 error!("crcrderr");
135 return Err(Error::Seq);
136 }
129 if sr.operr() { 137 if sr.operr() {
130 return Err(Error::Prog); 138 return Err(Error::Prog);
131 } 139 }
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index 4308037f2..fb20dcd38 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -65,9 +65,11 @@ impl FlashRegion {
65#[cfg_attr(flash_f7, path = "f7.rs")] 65#[cfg_attr(flash_f7, path = "f7.rs")]
66#[cfg_attr(flash_g0, path = "g0.rs")] 66#[cfg_attr(flash_g0, path = "g0.rs")]
67#[cfg_attr(flash_h7, path = "h7.rs")] 67#[cfg_attr(flash_h7, path = "h7.rs")]
68#[cfg_attr(flash_h7ab, path = "h7.rs")]
68#[cfg_attr( 69#[cfg_attr(
69 not(any( 70 not(any(
70 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f3, flash_f4, flash_f7, flash_g0, flash_h7 71 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f3, flash_f4, flash_f7, flash_g0, flash_h7,
72 flash_h7ab
71 )), 73 )),
72 path = "other.rs" 74 path = "other.rs"
73)] 75)]
diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs
index d016d1dea..ec4ed99b8 100644
--- a/embassy-stm32/src/rcc/f2.rs
+++ b/embassy-stm32/src/rcc/f2.rs
@@ -378,22 +378,6 @@ pub(crate) unsafe fn init(config: Config) {
378 // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions 378 // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions
379 assert!(ahb_freq <= Hertz(120_000_000)); 379 assert!(ahb_freq <= Hertz(120_000_000));
380 380
381 let flash_ws = unwrap!(config.voltage.wait_states(ahb_freq));
382 FLASH.acr().modify(|w| w.set_latency(flash_ws));
383
384 RCC.cfgr().modify(|w| {
385 w.set_sw(sw.into());
386 w.set_hpre(config.ahb_pre.into());
387 w.set_ppre1(config.apb1_pre.into());
388 w.set_ppre2(config.apb2_pre.into());
389 });
390 while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
391
392 // Turn off HSI to save power if we don't need it
393 if !config.hsi {
394 RCC.cr().modify(|w| w.set_hsion(false));
395 }
396
397 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { 381 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
398 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 382 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
399 pre => { 383 pre => {
@@ -414,6 +398,22 @@ pub(crate) unsafe fn init(config: Config) {
414 // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions 398 // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions
415 assert!(apb2_freq <= Hertz(60_000_000)); 399 assert!(apb2_freq <= Hertz(60_000_000));
416 400
401 let flash_ws = unwrap!(config.voltage.wait_states(ahb_freq));
402 FLASH.acr().modify(|w| w.set_latency(flash_ws));
403
404 RCC.cfgr().modify(|w| {
405 w.set_sw(sw.into());
406 w.set_hpre(config.ahb_pre.into());
407 w.set_ppre1(config.apb1_pre.into());
408 w.set_ppre2(config.apb2_pre.into());
409 });
410 while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
411
412 // Turn off HSI to save power if we don't need it
413 if !config.hsi {
414 RCC.cr().modify(|w| w.set_hsion(false));
415 }
416
417 set_freqs(Clocks { 417 set_freqs(Clocks {
418 sys: sys_clk, 418 sys: sys_clk,
419 ahb1: ahb_freq, 419 ahb1: ahb_freq,
diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs
index 0788b0640..7fb4fb95b 100644
--- a/embassy-stm32/src/rcc/h7.rs
+++ b/embassy-stm32/src/rcc/h7.rs
@@ -200,6 +200,7 @@ fn flash_setup(rcc_aclk: u32, vos: VoltageScale) {
200 200
201 // See RM0433 Rev 7 Table 17. FLASH recommended number of wait 201 // See RM0433 Rev 7 Table 17. FLASH recommended number of wait
202 // states and programming delay 202 // states and programming delay
203 #[cfg(flash_h7)]
203 let (wait_states, progr_delay) = match vos { 204 let (wait_states, progr_delay) = match vos {
204 // VOS 0 range VCORE 1.26V - 1.40V 205 // VOS 0 range VCORE 1.26V - 1.40V
205 VoltageScale::Scale0 => match rcc_aclk_mhz { 206 VoltageScale::Scale0 => match rcc_aclk_mhz {
@@ -239,6 +240,50 @@ fn flash_setup(rcc_aclk: u32, vos: VoltageScale) {
239 }, 240 },
240 }; 241 };
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
242 FLASH.acr().write(|w| { 287 FLASH.acr().write(|w| {
243 w.set_wrhighfreq(progr_delay); 288 w.set_wrhighfreq(progr_delay);
244 w.set_latency(wait_states) 289 w.set_latency(wait_states)
@@ -538,8 +583,6 @@ pub(crate) unsafe fn init(mut config: Config) {
538 let requested_pclk4 = config.pclk4.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); 583 let requested_pclk4 = config.pclk4.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
539 let (rcc_pclk4, ppre4_bits, ppre4, _) = ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None); 584 let (rcc_pclk4, ppre4_bits, ppre4, _) = ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None);
540 585
541 flash_setup(rcc_aclk, pwr_vos);
542
543 // Start switching clocks ------------------- 586 // Start switching clocks -------------------
544 587
545 // Ensure CSI is on and stable 588 // Ensure CSI is on and stable
@@ -595,6 +638,8 @@ pub(crate) unsafe fn init(mut config: Config) {
595 // core voltage 638 // core voltage
596 while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {} 639 while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {}
597 640
641 flash_setup(rcc_aclk, pwr_vos);
642
598 // APB1 / APB2 Prescaler 643 // APB1 / APB2 Prescaler
599 RCC.d2cfgr().modify(|w| { 644 RCC.d2cfgr().modify(|w| {
600 w.set_d2ppre1(Dppre::from_bits(ppre1_bits)); 645 w.set_d2ppre1(Dppre::from_bits(ppre1_bits));
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs
index b2828e58e..b34b8caab 100644
--- a/embassy-stm32/src/rcc/l4.rs
+++ b/embassy-stm32/src/rcc/l4.rs
@@ -410,10 +410,11 @@ pub(crate) unsafe fn init(config: Config) {
410 while RCC.cfgr().read().sws() != Sw::MSI {} 410 while RCC.cfgr().read().sws() != Sw::MSI {}
411 } 411 }
412 412
413 RCC.apb1enr1().modify(|w| w.set_pwren(true));
414
413 match config.rtc_mux { 415 match config.rtc_mux {
414 RtcClockSource::LSE32 => { 416 RtcClockSource::LSE32 => {
415 // 1. Unlock the backup domain 417 // 1. Unlock the backup domain
416 RCC.apb1enr1().modify(|w| w.set_pwren(true));
417 PWR.cr1().modify(|w| w.set_dbp(true)); 418 PWR.cr1().modify(|w| w.set_dbp(true));
418 419
419 // 2. Setup the LSE 420 // 2. Setup the LSE
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 4d4c6b610..ac9ae9c6a 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -9,7 +9,7 @@ use crate::time::Hertz;
9#[cfg_attr(rcc_f0, path = "f0.rs")] 9#[cfg_attr(rcc_f0, path = "f0.rs")]
10#[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")] 10#[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")]
11#[cfg_attr(rcc_f2, path = "f2.rs")] 11#[cfg_attr(rcc_f2, path = "f2.rs")]
12#[cfg_attr(rcc_f3, path = "f3.rs")] 12#[cfg_attr(any(rcc_f3, rcc_f3_v2), path = "f3.rs")]
13#[cfg_attr(any(rcc_f4, rcc_f410), path = "f4.rs")] 13#[cfg_attr(any(rcc_f4, rcc_f410), path = "f4.rs")]
14#[cfg_attr(rcc_f7, path = "f7.rs")] 14#[cfg_attr(rcc_f7, path = "f7.rs")]
15#[cfg_attr(rcc_c0, path = "c0.rs")] 15#[cfg_attr(rcc_c0, path = "c0.rs")]
diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs
index ea6e8dde6..f1dd2bd7e 100644
--- a/embassy-stm32/src/rcc/wl.rs
+++ b/embassy-stm32/src/rcc/wl.rs
@@ -2,6 +2,7 @@ pub use super::common::{AHBPrescaler, APBPrescaler, VoltageScale};
2use crate::pac::pwr::vals::Dbp; 2use crate::pac::pwr::vals::Dbp;
3use crate::pac::{FLASH, PWR, RCC}; 3use crate::pac::{FLASH, PWR, RCC};
4use crate::rcc::{set_freqs, Clocks}; 4use crate::rcc::{set_freqs, Clocks};
5use crate::rtc::{Rtc, RtcClockSource as RCS};
5use crate::time::Hertz; 6use crate::time::Hertz;
6 7
7/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, 8/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
@@ -229,6 +230,8 @@ pub(crate) unsafe fn init(config: Config) {
229 230
230 // Wait until LSE is running 231 // Wait until LSE is running
231 while !RCC.bdcr().read().lserdy() {} 232 while !RCC.bdcr().read().lserdy() {}
233
234 Rtc::set_clock_source(RCS::LSE);
232 } 235 }
233 RtcClockSource::LSI32 => { 236 RtcClockSource::LSI32 => {
234 // Turn on the internal 32 kHz LSI oscillator 237 // Turn on the internal 32 kHz LSI oscillator
@@ -236,6 +239,8 @@ pub(crate) unsafe fn init(config: Config) {
236 239
237 // Wait until LSI is running 240 // Wait until LSI is running
238 while !RCC.csr().read().lsirdy() {} 241 while !RCC.csr().read().lsirdy() {}
242
243 Rtc::set_clock_source(RCS::LSI);
239 } 244 }
240 } 245 }
241 246
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index 2a4978ec5..30816e436 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -73,15 +73,20 @@ impl<'d, T: Instance> Rng<'d, T> {
73 #[cfg(not(rng_v1))] 73 #[cfg(not(rng_v1))]
74 pub fn reset(&mut self) { 74 pub fn reset(&mut self) {
75 T::regs().cr().write(|reg| { 75 T::regs().cr().write(|reg| {
76 reg.set_rngen(false);
77 reg.set_condrst(true); 76 reg.set_condrst(true);
77 reg.set_nistc(pac::rng::vals::Nistc::CUSTOM);
78 // set RNG config "A" according to reference manual 78 // set RNG config "A" according to reference manual
79 // this has to be written within the same write access as setting the CONDRST bit 79 // this has to be written within the same write access as setting the CONDRST bit
80 reg.set_nistc(pac::rng::vals::Nistc::DEFAULT);
81 reg.set_rng_config1(pac::rng::vals::RngConfig1::CONFIGA); 80 reg.set_rng_config1(pac::rng::vals::RngConfig1::CONFIGA);
81 reg.set_clkdiv(pac::rng::vals::Clkdiv::NODIV);
82 reg.set_rng_config2(pac::rng::vals::RngConfig2::CONFIGA_B); 82 reg.set_rng_config2(pac::rng::vals::RngConfig2::CONFIGA_B);
83 reg.set_rng_config3(pac::rng::vals::RngConfig3::CONFIGA); 83 reg.set_rng_config3(pac::rng::vals::RngConfig3::CONFIGA);
84 reg.set_clkdiv(pac::rng::vals::Clkdiv::NODIV); 84 reg.set_ced(true);
85 reg.set_ie(false);
86 reg.set_rngen(true);
87 });
88 T::regs().cr().write(|reg| {
89 reg.set_ced(false);
85 }); 90 });
86 // wait for CONDRST to be set 91 // wait for CONDRST to be set
87 while !T::regs().cr().read().condrst() {} 92 while !T::regs().cr().read().condrst() {}
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index 4a166e195..744e9a114 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -72,6 +72,7 @@ impl core::ops::Sub for RtcInstant {
72 } 72 }
73} 73}
74 74
75#[allow(dead_code)]
75#[derive(Clone, Copy)] 76#[derive(Clone, Copy)]
76pub(crate) enum WakeupPrescaler { 77pub(crate) enum WakeupPrescaler {
77 Div2, 78 Div2,
@@ -120,6 +121,7 @@ impl From<WakeupPrescaler> for u32 {
120 } 121 }
121} 122}
122 123
124#[allow(dead_code)]
123impl WakeupPrescaler { 125impl WakeupPrescaler {
124 pub fn compute_min(val: u32) -> Self { 126 pub fn compute_min(val: u32) -> Self {
125 *[ 127 *[
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index acd67048d..4f033e3a2 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -100,14 +100,19 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
100 } 100 }
101 101
102 pub fn get_max_duty(&self) -> u16 { 102 pub fn get_max_duty(&self) -> u16 {
103 self.inner.get_max_compare_value() 103 self.inner.get_max_compare_value() + 1
104 } 104 }
105 105
106 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 106 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
107 assert!(duty < self.get_max_duty()); 107 assert!(duty <= self.get_max_duty());
108 self.inner.set_compare_value(channel, duty) 108 self.inner.set_compare_value(channel, duty)
109 } 109 }
110 110
111 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
112 self.inner.set_output_polarity(channel, polarity);
113 self.inner.set_complementary_output_polarity(channel, polarity);
114 }
115
111 /// Set the dead time as a proportion of max_duty 116 /// Set the dead time as a proportion of max_duty
112 pub fn set_dead_time(&mut self, value: u16) { 117 pub fn set_dead_time(&mut self, value: u16) {
113 let (ckd, value) = compute_dead_time_value(value); 118 let (ckd, value) = compute_dead_time_value(value);
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 6c2d6d827..4ffb2a289 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -53,6 +53,8 @@ pub(crate) mod sealed {
53 53
54 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); 54 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
55 55
56 fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity);
57
56 fn enable_channel(&mut self, channel: Channel, enable: bool); 58 fn enable_channel(&mut self, channel: Channel, enable: bool);
57 59
58 fn set_compare_value(&mut self, channel: Channel, value: u16); 60 fn set_compare_value(&mut self, channel: Channel, value: u16);
@@ -61,6 +63,8 @@ pub(crate) mod sealed {
61 } 63 }
62 64
63 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance { 65 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance {
66 fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity);
67
64 fn set_dead_time_clock_division(&mut self, value: vals::Ckd); 68 fn set_dead_time_clock_division(&mut self, value: vals::Ckd);
65 69
66 fn set_dead_time_value(&mut self, value: u8); 70 fn set_dead_time_value(&mut self, value: u8);
@@ -71,6 +75,8 @@ pub(crate) mod sealed {
71 pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance { 75 pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance {
72 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); 76 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
73 77
78 fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity);
79
74 fn enable_channel(&mut self, channel: Channel, enable: bool); 80 fn enable_channel(&mut self, channel: Channel, enable: bool);
75 81
76 fn set_compare_value(&mut self, channel: Channel, value: u32); 82 fn set_compare_value(&mut self, channel: Channel, value: u32);
@@ -125,6 +131,21 @@ impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
125 } 131 }
126} 132}
127 133
134#[derive(Clone, Copy)]
135pub enum OutputPolarity {
136 ActiveHigh,
137 ActiveLow,
138}
139
140impl From<OutputPolarity> for bool {
141 fn from(mode: OutputPolarity) -> Self {
142 match mode {
143 OutputPolarity::ActiveHigh => false,
144 OutputPolarity::ActiveLow => true,
145 }
146 }
147}
148
128pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} 149pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
129 150
130pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} 151pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {}
@@ -265,6 +286,13 @@ macro_rules! impl_compare_capable_16bit {
265 .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); 286 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
266 } 287 }
267 288
289 fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
290 use sealed::GeneralPurpose16bitInstance;
291 Self::regs_gp16()
292 .ccer()
293 .modify(|w| w.set_ccp(channel.raw(), polarity.into()));
294 }
295
268 fn enable_channel(&mut self, channel: Channel, enable: bool) { 296 fn enable_channel(&mut self, channel: Channel, enable: bool) {
269 use sealed::GeneralPurpose16bitInstance; 297 use sealed::GeneralPurpose16bitInstance;
270 Self::regs_gp16() 298 Self::regs_gp16()
@@ -325,6 +353,13 @@ foreach_interrupt! {
325 Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into())); 353 Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
326 } 354 }
327 355
356 fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
357 use crate::timer::sealed::GeneralPurpose32bitInstance;
358 Self::regs_gp32()
359 .ccer()
360 .modify(|w| w.set_ccp(channel.raw(), polarity.into()));
361 }
362
328 fn enable_channel(&mut self, channel: Channel, enable: bool) { 363 fn enable_channel(&mut self, channel: Channel, enable: bool) {
329 use crate::timer::sealed::GeneralPurpose32bitInstance; 364 use crate::timer::sealed::GeneralPurpose32bitInstance;
330 Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable)); 365 Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable));
@@ -388,6 +423,13 @@ foreach_interrupt! {
388 .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); 423 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
389 } 424 }
390 425
426 fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
427 use crate::timer::sealed::AdvancedControlInstance;
428 Self::regs_advanced()
429 .ccer()
430 .modify(|w| w.set_ccp(channel.raw(), polarity.into()));
431 }
432
391 fn enable_channel(&mut self, channel: Channel, enable: bool) { 433 fn enable_channel(&mut self, channel: Channel, enable: bool) {
392 use crate::timer::sealed::AdvancedControlInstance; 434 use crate::timer::sealed::AdvancedControlInstance;
393 Self::regs_advanced() 435 Self::regs_advanced()
@@ -409,6 +451,13 @@ foreach_interrupt! {
409 } 451 }
410 452
411 impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { 453 impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {
454 fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
455 use crate::timer::sealed::AdvancedControlInstance;
456 Self::regs_advanced()
457 .ccer()
458 .modify(|w| w.set_ccnp(channel.raw(), polarity.into()));
459 }
460
412 fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { 461 fn set_dead_time_clock_division(&mut self, value: vals::Ckd) {
413 use crate::timer::sealed::AdvancedControlInstance; 462 use crate::timer::sealed::AdvancedControlInstance;
414 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); 463 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index e0a817929..9e28878b1 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -97,11 +97,15 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
97 } 97 }
98 98
99 pub fn get_max_duty(&self) -> u16 { 99 pub fn get_max_duty(&self) -> u16 {
100 self.inner.get_max_compare_value() 100 self.inner.get_max_compare_value() + 1
101 } 101 }
102 102
103 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 103 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
104 assert!(duty < self.get_max_duty()); 104 assert!(duty <= self.get_max_duty());
105 self.inner.set_compare_value(channel, duty) 105 self.inner.set_compare_value(channel, duty)
106 } 106 }
107
108 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
109 self.inner.set_output_polarity(channel, polarity);
110 }
107} 111}
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 329fc7da6..596d40bf9 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -584,15 +584,15 @@ mod eh02 {
584mod eh1 { 584mod eh1 {
585 use super::*; 585 use super::*;
586 586
587 impl<'d, T: BasicInstance> embedded_hal_1::serial::ErrorType for BufferedUart<'d, T> { 587 impl<'d, T: BasicInstance> embedded_hal_nb::serial::ErrorType for BufferedUart<'d, T> {
588 type Error = Error; 588 type Error = Error;
589 } 589 }
590 590
591 impl<'d, T: BasicInstance> embedded_hal_1::serial::ErrorType for BufferedUartTx<'d, T> { 591 impl<'d, T: BasicInstance> embedded_hal_nb::serial::ErrorType for BufferedUartTx<'d, T> {
592 type Error = Error; 592 type Error = Error;
593 } 593 }
594 594
595 impl<'d, T: BasicInstance> embedded_hal_1::serial::ErrorType for BufferedUartRx<'d, T> { 595 impl<'d, T: BasicInstance> embedded_hal_nb::serial::ErrorType for BufferedUartRx<'d, T> {
596 type Error = Error; 596 type Error = Error;
597 } 597 }
598 598
@@ -602,16 +602,6 @@ mod eh1 {
602 } 602 }
603 } 603 }
604 604
605 impl<'d, T: BasicInstance> embedded_hal_1::serial::Write for BufferedUartTx<'d, T> {
606 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
607 self.blocking_write(buffer).map(drop)
608 }
609
610 fn flush(&mut self) -> Result<(), Self::Error> {
611 self.blocking_flush()
612 }
613 }
614
615 impl<'d, T: BasicInstance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> { 605 impl<'d, T: BasicInstance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> {
616 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 606 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
617 self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) 607 self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
@@ -628,16 +618,6 @@ mod eh1 {
628 } 618 }
629 } 619 }
630 620
631 impl<'d, T: BasicInstance> embedded_hal_1::serial::Write for BufferedUart<'d, T> {
632 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
633 self.tx.blocking_write(buffer).map(drop)
634 }
635
636 fn flush(&mut self) -> Result<(), Self::Error> {
637 self.tx.blocking_flush()
638 }
639 }
640
641 impl<'d, T: BasicInstance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> { 621 impl<'d, T: BasicInstance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> {
642 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 622 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
643 self.tx.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) 623 self.tx.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 0c69a4882..255ddfd4b 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -809,45 +809,57 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
809 Kind::Uart => (1, 0x10, 0x1_0000), 809 Kind::Uart => (1, 0x10, 0x1_0000),
810 }; 810 };
811 811
812 fn calculate_brr(baud: u32, pclk: u32, presc: u32, mul: u32) -> u32 {
813 // The calculation to be done to get the BRR is `mul * pclk / presc / baud`
814 // To do this in 32-bit only we can't multiply `mul` and `pclk`
815 let clock = pclk / presc;
816
817 // The mul is applied as the last operation to prevent overflow
818 let brr = clock / baud * mul;
819
820 // The BRR calculation will be a bit off because of integer rounding.
821 // Because we multiplied our inaccuracy with mul, our rounding now needs to be in proportion to mul.
822 let rounding = ((clock % baud) * mul + (baud / 2)) / baud;
823
824 brr + rounding
825 }
826
812 #[cfg(not(usart_v1))] 827 #[cfg(not(usart_v1))]
813 let mut over8 = false; 828 let mut over8 = false;
814 let mut found = None; 829 let mut found_brr = None;
815 for &(presc, _presc_val) in &DIVS { 830 for &(presc, _presc_val) in &DIVS {
816 let denom = (config.baudrate * presc as u32) as u64; 831 let brr = calculate_brr(config.baudrate, pclk_freq.0, presc as u32, mul);
817 let div = (pclk_freq.0 as u64 * mul + (denom / 2)) / denom;
818 trace!( 832 trace!(
819 "USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})", 833 "USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})",
820 presc, 834 presc,
821 div, 835 brr,
822 div >> 4, 836 brr >> 4,
823 div & 0x0F 837 brr & 0x0F
824 ); 838 );
825 839
826 if div < brr_min { 840 if brr < brr_min {
827 #[cfg(not(usart_v1))] 841 #[cfg(not(usart_v1))]
828 if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) { 842 if brr * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) {
829 over8 = true; 843 over8 = true;
830 let div = div as u32; 844 r.brr().write_value(regs::Brr(((brr << 1) & !0xF) | (brr & 0x07)));
831 r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07)));
832 #[cfg(usart_v4)] 845 #[cfg(usart_v4)]
833 r.presc().write(|w| w.set_prescaler(_presc_val)); 846 r.presc().write(|w| w.set_prescaler(_presc_val));
834 found = Some(div); 847 found_brr = Some(brr);
835 break; 848 break;
836 } 849 }
837 panic!("USART: baudrate too high"); 850 panic!("USART: baudrate too high");
838 } 851 }
839 852
840 if div < brr_max { 853 if brr < brr_max {
841 let div = div as u32; 854 r.brr().write_value(regs::Brr(brr));
842 r.brr().write_value(regs::Brr(div));
843 #[cfg(usart_v4)] 855 #[cfg(usart_v4)]
844 r.presc().write(|w| w.set_prescaler(_presc_val)); 856 r.presc().write(|w| w.set_prescaler(_presc_val));
845 found = Some(div); 857 found_brr = Some(brr);
846 break; 858 break;
847 } 859 }
848 } 860 }
849 861
850 let div = found.expect("USART: baudrate too low"); 862 let brr = found_brr.expect("USART: baudrate too low");
851 863
852 #[cfg(not(usart_v1))] 864 #[cfg(not(usart_v1))]
853 let oversampling = if over8 { "8 bit" } else { "16 bit" }; 865 let oversampling = if over8 { "8 bit" } else { "16 bit" };
@@ -857,7 +869,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
857 "Using {} oversampling, desired baudrate: {}, actual baudrate: {}", 869 "Using {} oversampling, desired baudrate: {}, actual baudrate: {}",
858 oversampling, 870 oversampling,
859 config.baudrate, 871 config.baudrate,
860 (pclk_freq.0 * mul as u32) / div 872 pclk_freq.0 / brr * mul
861 ); 873 );
862 874
863 r.cr2().write(|w| { 875 r.cr2().write(|w| {
@@ -943,27 +955,27 @@ mod eh02 {
943mod eh1 { 955mod eh1 {
944 use super::*; 956 use super::*;
945 957
946 impl embedded_hal_1::serial::Error for Error { 958 impl embedded_hal_nb::serial::Error for Error {
947 fn kind(&self) -> embedded_hal_1::serial::ErrorKind { 959 fn kind(&self) -> embedded_hal_nb::serial::ErrorKind {
948 match *self { 960 match *self {
949 Self::Framing => embedded_hal_1::serial::ErrorKind::FrameFormat, 961 Self::Framing => embedded_hal_nb::serial::ErrorKind::FrameFormat,
950 Self::Noise => embedded_hal_1::serial::ErrorKind::Noise, 962 Self::Noise => embedded_hal_nb::serial::ErrorKind::Noise,
951 Self::Overrun => embedded_hal_1::serial::ErrorKind::Overrun, 963 Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun,
952 Self::Parity => embedded_hal_1::serial::ErrorKind::Parity, 964 Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity,
953 Self::BufferTooLong => embedded_hal_1::serial::ErrorKind::Other, 965 Self::BufferTooLong => embedded_hal_nb::serial::ErrorKind::Other,
954 } 966 }
955 } 967 }
956 } 968 }
957 969
958 impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_1::serial::ErrorType for Uart<'d, T, TxDma, RxDma> { 970 impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::ErrorType for Uart<'d, T, TxDma, RxDma> {
959 type Error = Error; 971 type Error = Error;
960 } 972 }
961 973
962 impl<'d, T: BasicInstance, TxDma> embedded_hal_1::serial::ErrorType for UartTx<'d, T, TxDma> { 974 impl<'d, T: BasicInstance, TxDma> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, TxDma> {
963 type Error = Error; 975 type Error = Error;
964 } 976 }
965 977
966 impl<'d, T: BasicInstance, RxDma> embedded_hal_1::serial::ErrorType for UartRx<'d, T, RxDma> { 978 impl<'d, T: BasicInstance, RxDma> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, RxDma> {
967 type Error = Error; 979 type Error = Error;
968 } 980 }
969 981
@@ -973,16 +985,6 @@ mod eh1 {
973 } 985 }
974 } 986 }
975 987
976 impl<'d, T: BasicInstance, TxDma> embedded_hal_1::serial::Write for UartTx<'d, T, TxDma> {
977 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
978 self.blocking_write(buffer)
979 }
980
981 fn flush(&mut self) -> Result<(), Self::Error> {
982 self.blocking_flush()
983 }
984 }
985
986 impl<'d, T: BasicInstance, TxDma> embedded_hal_nb::serial::Write for UartTx<'d, T, TxDma> { 988 impl<'d, T: BasicInstance, TxDma> embedded_hal_nb::serial::Write for UartTx<'d, T, TxDma> {
987 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 989 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
988 self.blocking_write(&[char]).map_err(nb::Error::Other) 990 self.blocking_write(&[char]).map_err(nb::Error::Other)
@@ -999,16 +1001,6 @@ mod eh1 {
999 } 1001 }
1000 } 1002 }
1001 1003
1002 impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_1::serial::Write for Uart<'d, T, TxDma, RxDma> {
1003 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
1004 self.blocking_write(buffer)
1005 }
1006
1007 fn flush(&mut self) -> Result<(), Self::Error> {
1008 self.blocking_flush()
1009 }
1010 }
1011
1012 impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::Write for Uart<'d, T, TxDma, RxDma> { 1004 impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::Write for Uart<'d, T, TxDma, RxDma> {
1013 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 1005 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
1014 self.blocking_write(&[char]).map_err(nb::Error::Other) 1006 self.blocking_write(&[char]).map_err(nb::Error::Other)
diff --git a/embassy-sync/src/blocking_mutex/raw.rs b/embassy-sync/src/blocking_mutex/raw.rs
index 15796f1b2..a8afcad34 100644
--- a/embassy-sync/src/blocking_mutex/raw.rs
+++ b/embassy-sync/src/blocking_mutex/raw.rs
@@ -11,7 +11,7 @@ use core::marker::PhantomData;
11/// 11///
12/// Note that, unlike other mutexes, implementations only guarantee no 12/// Note that, unlike other mutexes, implementations only guarantee no
13/// concurrent access from other threads: concurrent access from the current 13/// concurrent access from other threads: concurrent access from the current
14/// thread is allwed. For example, it's possible to lock the same mutex multiple times reentrantly. 14/// thread is allowed. For example, it's possible to lock the same mutex multiple times reentrantly.
15/// 15///
16/// Therefore, locking a `RawMutex` is only enough to guarantee safe shared (`&`) access 16/// Therefore, locking a `RawMutex` is only enough to guarantee safe shared (`&`) access
17/// to the data, it is not enough to guarantee exclusive (`&mut`) access. 17/// to the data, it is not enough to guarantee exclusive (`&mut`) access.
diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs
index d6f36f53d..62ea1307d 100644
--- a/embassy-sync/src/channel.rs
+++ b/embassy-sync/src/channel.rs
@@ -65,6 +65,13 @@ where
65 pub fn try_send(&self, message: T) -> Result<(), TrySendError<T>> { 65 pub fn try_send(&self, message: T) -> Result<(), TrySendError<T>> {
66 self.channel.try_send(message) 66 self.channel.try_send(message)
67 } 67 }
68
69 /// Allows a poll_fn to poll until the channel is ready to send
70 ///
71 /// See [`Channel::poll_ready_to_send()`]
72 pub fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()> {
73 self.channel.poll_ready_to_send(cx)
74 }
68} 75}
69 76
70/// Send-only access to a [`Channel`] without knowing channel size. 77/// Send-only access to a [`Channel`] without knowing channel size.
@@ -106,6 +113,13 @@ impl<'ch, T> DynamicSender<'ch, T> {
106 pub fn try_send(&self, message: T) -> Result<(), TrySendError<T>> { 113 pub fn try_send(&self, message: T) -> Result<(), TrySendError<T>> {
107 self.channel.try_send_with_context(message, None) 114 self.channel.try_send_with_context(message, None)
108 } 115 }
116
117 /// Allows a poll_fn to poll until the channel is ready to send
118 ///
119 /// See [`Channel::poll_ready_to_send()`]
120 pub fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()> {
121 self.channel.poll_ready_to_send(cx)
122 }
109} 123}
110 124
111/// Receive-only access to a [`Channel`]. 125/// Receive-only access to a [`Channel`].
@@ -133,16 +147,30 @@ where
133{ 147{
134 /// Receive the next value. 148 /// Receive the next value.
135 /// 149 ///
136 /// See [`Channel::recv()`]. 150 /// See [`Channel::receive()`].
137 pub fn recv(&self) -> RecvFuture<'_, M, T, N> { 151 pub fn receive(&self) -> ReceiveFuture<'_, M, T, N> {
138 self.channel.recv() 152 self.channel.receive()
139 } 153 }
140 154
141 /// Attempt to immediately receive the next value. 155 /// Attempt to immediately receive the next value.
142 /// 156 ///
143 /// See [`Channel::try_recv()`] 157 /// See [`Channel::try_receive()`]
144 pub fn try_recv(&self) -> Result<T, TryRecvError> { 158 pub fn try_receive(&self) -> Result<T, TryReceiveError> {
145 self.channel.try_recv() 159 self.channel.try_receive()
160 }
161
162 /// Allows a poll_fn to poll until the channel is ready to receive
163 ///
164 /// See [`Channel::poll_ready_to_receive()`]
165 pub fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> Poll<()> {
166 self.channel.poll_ready_to_receive(cx)
167 }
168
169 /// Poll the channel for the next item
170 ///
171 /// See [`Channel::poll_receive()`]
172 pub fn poll_receive(&self, cx: &mut Context<'_>) -> Poll<T> {
173 self.channel.poll_receive(cx)
146 } 174 }
147} 175}
148 176
@@ -162,16 +190,30 @@ impl<'ch, T> Copy for DynamicReceiver<'ch, T> {}
162impl<'ch, T> DynamicReceiver<'ch, T> { 190impl<'ch, T> DynamicReceiver<'ch, T> {
163 /// Receive the next value. 191 /// Receive the next value.
164 /// 192 ///
165 /// See [`Channel::recv()`]. 193 /// See [`Channel::receive()`].
166 pub fn recv(&self) -> DynamicRecvFuture<'_, T> { 194 pub fn receive(&self) -> DynamicReceiveFuture<'_, T> {
167 DynamicRecvFuture { channel: self.channel } 195 DynamicReceiveFuture { channel: self.channel }
168 } 196 }
169 197
170 /// Attempt to immediately receive the next value. 198 /// Attempt to immediately receive the next value.
171 /// 199 ///
172 /// See [`Channel::try_recv()`] 200 /// See [`Channel::try_receive()`]
173 pub fn try_recv(&self) -> Result<T, TryRecvError> { 201 pub fn try_receive(&self) -> Result<T, TryReceiveError> {
174 self.channel.try_recv_with_context(None) 202 self.channel.try_receive_with_context(None)
203 }
204
205 /// Allows a poll_fn to poll until the channel is ready to receive
206 ///
207 /// See [`Channel::poll_ready_to_receive()`]
208 pub fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> Poll<()> {
209 self.channel.poll_ready_to_receive(cx)
210 }
211
212 /// Poll the channel for the next item
213 ///
214 /// See [`Channel::poll_receive()`]
215 pub fn poll_receive(&self, cx: &mut Context<'_>) -> Poll<T> {
216 self.channel.poll_receive(cx)
175 } 217 }
176} 218}
177 219
@@ -184,42 +226,39 @@ where
184 } 226 }
185} 227}
186 228
187/// Future returned by [`Channel::recv`] and [`Receiver::recv`]. 229/// Future returned by [`Channel::receive`] and [`Receiver::receive`].
188#[must_use = "futures do nothing unless you `.await` or poll them"] 230#[must_use = "futures do nothing unless you `.await` or poll them"]
189pub struct RecvFuture<'ch, M, T, const N: usize> 231pub struct ReceiveFuture<'ch, M, T, const N: usize>
190where 232where
191 M: RawMutex, 233 M: RawMutex,
192{ 234{
193 channel: &'ch Channel<M, T, N>, 235 channel: &'ch Channel<M, T, N>,
194} 236}
195 237
196impl<'ch, M, T, const N: usize> Future for RecvFuture<'ch, M, T, N> 238impl<'ch, M, T, const N: usize> Future for ReceiveFuture<'ch, M, T, N>
197where 239where
198 M: RawMutex, 240 M: RawMutex,
199{ 241{
200 type Output = T; 242 type Output = T;
201 243
202 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> { 244 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
203 match self.channel.try_recv_with_context(Some(cx)) { 245 self.channel.poll_receive(cx)
204 Ok(v) => Poll::Ready(v),
205 Err(TryRecvError::Empty) => Poll::Pending,
206 }
207 } 246 }
208} 247}
209 248
210/// Future returned by [`DynamicReceiver::recv`]. 249/// Future returned by [`DynamicReceiver::receive`].
211#[must_use = "futures do nothing unless you `.await` or poll them"] 250#[must_use = "futures do nothing unless you `.await` or poll them"]
212pub struct DynamicRecvFuture<'ch, T> { 251pub struct DynamicReceiveFuture<'ch, T> {
213 channel: &'ch dyn DynamicChannel<T>, 252 channel: &'ch dyn DynamicChannel<T>,
214} 253}
215 254
216impl<'ch, T> Future for DynamicRecvFuture<'ch, T> { 255impl<'ch, T> Future for DynamicReceiveFuture<'ch, T> {
217 type Output = T; 256 type Output = T;
218 257
219 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> { 258 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
220 match self.channel.try_recv_with_context(Some(cx)) { 259 match self.channel.try_receive_with_context(Some(cx)) {
221 Ok(v) => Poll::Ready(v), 260 Ok(v) => Poll::Ready(v),
222 Err(TryRecvError::Empty) => Poll::Pending, 261 Err(TryReceiveError::Empty) => Poll::Pending,
223 } 262 }
224 } 263 }
225} 264}
@@ -285,13 +324,18 @@ impl<'ch, T> Unpin for DynamicSendFuture<'ch, T> {}
285trait DynamicChannel<T> { 324trait DynamicChannel<T> {
286 fn try_send_with_context(&self, message: T, cx: Option<&mut Context<'_>>) -> Result<(), TrySendError<T>>; 325 fn try_send_with_context(&self, message: T, cx: Option<&mut Context<'_>>) -> Result<(), TrySendError<T>>;
287 326
288 fn try_recv_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<T, TryRecvError>; 327 fn try_receive_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<T, TryReceiveError>;
328
329 fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()>;
330 fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> Poll<()>;
331
332 fn poll_receive(&self, cx: &mut Context<'_>) -> Poll<T>;
289} 333}
290 334
291/// Error returned by [`try_recv`](Channel::try_recv). 335/// Error returned by [`try_receive`](Channel::try_receive).
292#[derive(PartialEq, Eq, Clone, Copy, Debug)] 336#[derive(PartialEq, Eq, Clone, Copy, Debug)]
293#[cfg_attr(feature = "defmt", derive(defmt::Format))] 337#[cfg_attr(feature = "defmt", derive(defmt::Format))]
294pub enum TryRecvError { 338pub enum TryReceiveError {
295 /// A message could not be received because the channel is empty. 339 /// A message could not be received because the channel is empty.
296 Empty, 340 Empty,
297} 341}
@@ -320,11 +364,11 @@ impl<T, const N: usize> ChannelState<T, N> {
320 } 364 }
321 } 365 }
322 366
323 fn try_recv(&mut self) -> Result<T, TryRecvError> { 367 fn try_receive(&mut self) -> Result<T, TryReceiveError> {
324 self.try_recv_with_context(None) 368 self.try_receive_with_context(None)
325 } 369 }
326 370
327 fn try_recv_with_context(&mut self, cx: Option<&mut Context<'_>>) -> Result<T, TryRecvError> { 371 fn try_receive_with_context(&mut self, cx: Option<&mut Context<'_>>) -> Result<T, TryReceiveError> {
328 if self.queue.is_full() { 372 if self.queue.is_full() {
329 self.senders_waker.wake(); 373 self.senders_waker.wake();
330 } 374 }
@@ -335,14 +379,31 @@ impl<T, const N: usize> ChannelState<T, N> {
335 if let Some(cx) = cx { 379 if let Some(cx) = cx {
336 self.receiver_waker.register(cx.waker()); 380 self.receiver_waker.register(cx.waker());
337 } 381 }
338 Err(TryRecvError::Empty) 382 Err(TryReceiveError::Empty)
383 }
384 }
385
386 fn poll_receive(&mut self, cx: &mut Context<'_>) -> Poll<T> {
387 if self.queue.is_full() {
388 self.senders_waker.wake();
389 }
390
391 if let Some(message) = self.queue.pop_front() {
392 Poll::Ready(message)
393 } else {
394 self.receiver_waker.register(cx.waker());
395 Poll::Pending
339 } 396 }
340 } 397 }
341 398
342 fn poll_ready_to_receive(&mut self, cx: &mut Context<'_>) -> bool { 399 fn poll_ready_to_receive(&mut self, cx: &mut Context<'_>) -> Poll<()> {
343 self.receiver_waker.register(cx.waker()); 400 self.receiver_waker.register(cx.waker());
344 401
345 !self.queue.is_empty() 402 if !self.queue.is_empty() {
403 Poll::Ready(())
404 } else {
405 Poll::Pending
406 }
346 } 407 }
347 408
348 fn try_send(&mut self, message: T) -> Result<(), TrySendError<T>> { 409 fn try_send(&mut self, message: T) -> Result<(), TrySendError<T>> {
@@ -364,10 +425,14 @@ impl<T, const N: usize> ChannelState<T, N> {
364 } 425 }
365 } 426 }
366 427
367 fn poll_ready_to_send(&mut self, cx: &mut Context<'_>) -> bool { 428 fn poll_ready_to_send(&mut self, cx: &mut Context<'_>) -> Poll<()> {
368 self.senders_waker.register(cx.waker()); 429 self.senders_waker.register(cx.waker());
369 430
370 !self.queue.is_full() 431 if !self.queue.is_full() {
432 Poll::Ready(())
433 } else {
434 Poll::Pending
435 }
371 } 436 }
372} 437}
373 438
@@ -409,8 +474,13 @@ where
409 self.inner.lock(|rc| f(&mut *rc.borrow_mut())) 474 self.inner.lock(|rc| f(&mut *rc.borrow_mut()))
410 } 475 }
411 476
412 fn try_recv_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<T, TryRecvError> { 477 fn try_receive_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<T, TryReceiveError> {
413 self.lock(|c| c.try_recv_with_context(cx)) 478 self.lock(|c| c.try_receive_with_context(cx))
479 }
480
481 /// Poll the channel for the next message
482 pub fn poll_receive(&self, cx: &mut Context<'_>) -> Poll<T> {
483 self.lock(|c| c.poll_receive(cx))
414 } 484 }
415 485
416 fn try_send_with_context(&self, m: T, cx: Option<&mut Context<'_>>) -> Result<(), TrySendError<T>> { 486 fn try_send_with_context(&self, m: T, cx: Option<&mut Context<'_>>) -> Result<(), TrySendError<T>> {
@@ -418,12 +488,12 @@ where
418 } 488 }
419 489
420 /// Allows a poll_fn to poll until the channel is ready to receive 490 /// Allows a poll_fn to poll until the channel is ready to receive
421 pub fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> bool { 491 pub fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> Poll<()> {
422 self.lock(|c| c.poll_ready_to_receive(cx)) 492 self.lock(|c| c.poll_ready_to_receive(cx))
423 } 493 }
424 494
425 /// Allows a poll_fn to poll until the channel is ready to send 495 /// Allows a poll_fn to poll until the channel is ready to send
426 pub fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> bool { 496 pub fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()> {
427 self.lock(|c| c.poll_ready_to_send(cx)) 497 self.lock(|c| c.poll_ready_to_send(cx))
428 } 498 }
429 499
@@ -466,16 +536,16 @@ where
466 /// 536 ///
467 /// If there are no messages in the channel's buffer, this method will 537 /// If there are no messages in the channel's buffer, this method will
468 /// wait until a message is sent. 538 /// wait until a message is sent.
469 pub fn recv(&self) -> RecvFuture<'_, M, T, N> { 539 pub fn receive(&self) -> ReceiveFuture<'_, M, T, N> {
470 RecvFuture { channel: self } 540 ReceiveFuture { channel: self }
471 } 541 }
472 542
473 /// Attempt to immediately receive a message. 543 /// Attempt to immediately receive a message.
474 /// 544 ///
475 /// This method will either receive a message from the channel immediately or return an error 545 /// This method will either receive a message from the channel immediately or return an error
476 /// if the channel is empty. 546 /// if the channel is empty.
477 pub fn try_recv(&self) -> Result<T, TryRecvError> { 547 pub fn try_receive(&self) -> Result<T, TryReceiveError> {
478 self.lock(|c| c.try_recv()) 548 self.lock(|c| c.try_receive())
479 } 549 }
480} 550}
481 551
@@ -489,8 +559,20 @@ where
489 Channel::try_send_with_context(self, m, cx) 559 Channel::try_send_with_context(self, m, cx)
490 } 560 }
491 561
492 fn try_recv_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<T, TryRecvError> { 562 fn try_receive_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<T, TryReceiveError> {
493 Channel::try_recv_with_context(self, cx) 563 Channel::try_receive_with_context(self, cx)
564 }
565
566 fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()> {
567 Channel::poll_ready_to_send(self, cx)
568 }
569
570 fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> Poll<()> {
571 Channel::poll_ready_to_receive(self, cx)
572 }
573
574 fn poll_receive(&self, cx: &mut Context<'_>) -> Poll<T> {
575 Channel::poll_receive(self, cx)
494 } 576 }
495} 577}
496 578
@@ -534,15 +616,15 @@ mod tests {
534 fn receiving_once_with_one_send() { 616 fn receiving_once_with_one_send() {
535 let mut c = ChannelState::<u32, 3>::new(); 617 let mut c = ChannelState::<u32, 3>::new();
536 assert!(c.try_send(1).is_ok()); 618 assert!(c.try_send(1).is_ok());
537 assert_eq!(c.try_recv().unwrap(), 1); 619 assert_eq!(c.try_receive().unwrap(), 1);
538 assert_eq!(capacity(&c), 3); 620 assert_eq!(capacity(&c), 3);
539 } 621 }
540 622
541 #[test] 623 #[test]
542 fn receiving_when_empty() { 624 fn receiving_when_empty() {
543 let mut c = ChannelState::<u32, 3>::new(); 625 let mut c = ChannelState::<u32, 3>::new();
544 match c.try_recv() { 626 match c.try_receive() {
545 Err(TryRecvError::Empty) => assert!(true), 627 Err(TryReceiveError::Empty) => assert!(true),
546 _ => assert!(false), 628 _ => assert!(false),
547 } 629 }
548 assert_eq!(capacity(&c), 3); 630 assert_eq!(capacity(&c), 3);
@@ -552,7 +634,7 @@ mod tests {
552 fn simple_send_and_receive() { 634 fn simple_send_and_receive() {
553 let c = Channel::<NoopRawMutex, u32, 3>::new(); 635 let c = Channel::<NoopRawMutex, u32, 3>::new();
554 assert!(c.try_send(1).is_ok()); 636 assert!(c.try_send(1).is_ok());
555 assert_eq!(c.try_recv().unwrap(), 1); 637 assert_eq!(c.try_receive().unwrap(), 1);
556 } 638 }
557 639
558 #[test] 640 #[test]
@@ -572,7 +654,7 @@ mod tests {
572 let r: DynamicReceiver<'_, u32> = c.receiver().into(); 654 let r: DynamicReceiver<'_, u32> = c.receiver().into();
573 655
574 assert!(s.try_send(1).is_ok()); 656 assert!(s.try_send(1).is_ok());
575 assert_eq!(r.try_recv().unwrap(), 1); 657 assert_eq!(r.try_receive().unwrap(), 1);
576 } 658 }
577 659
578 #[futures_test::test] 660 #[futures_test::test]
@@ -587,14 +669,14 @@ mod tests {
587 assert!(c2.try_send(1).is_ok()); 669 assert!(c2.try_send(1).is_ok());
588 }) 670 })
589 .is_ok()); 671 .is_ok());
590 assert_eq!(c.recv().await, 1); 672 assert_eq!(c.receive().await, 1);
591 } 673 }
592 674
593 #[futures_test::test] 675 #[futures_test::test]
594 async fn sender_send_completes_if_capacity() { 676 async fn sender_send_completes_if_capacity() {
595 let c = Channel::<CriticalSectionRawMutex, u32, 1>::new(); 677 let c = Channel::<CriticalSectionRawMutex, u32, 1>::new();
596 c.send(1).await; 678 c.send(1).await;
597 assert_eq!(c.recv().await, 1); 679 assert_eq!(c.receive().await, 1);
598 } 680 }
599 681
600 #[futures_test::test] 682 #[futures_test::test]
@@ -612,11 +694,11 @@ mod tests {
612 // Wish I could think of a means of determining that the async send is waiting instead. 694 // Wish I could think of a means of determining that the async send is waiting instead.
613 // However, I've used the debugger to observe that the send does indeed wait. 695 // However, I've used the debugger to observe that the send does indeed wait.
614 Delay::new(Duration::from_millis(500)).await; 696 Delay::new(Duration::from_millis(500)).await;
615 assert_eq!(c.recv().await, 1); 697 assert_eq!(c.receive().await, 1);
616 assert!(executor 698 assert!(executor
617 .spawn(async move { 699 .spawn(async move {
618 loop { 700 loop {
619 c.recv().await; 701 c.receive().await;
620 } 702 }
621 }) 703 })
622 .is_ok()); 704 .is_ok());
diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml
index 0afb1103d..ec1f2ec3f 100644
--- a/embassy-time/Cargo.toml
+++ b/embassy-time/Cargo.toml
@@ -152,8 +152,8 @@ defmt = { version = "0.3", optional = true }
152log = { version = "0.4.14", optional = true } 152log = { version = "0.4.14", optional = true }
153 153
154embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } 154embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" }
155embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11", optional = true} 155embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true}
156embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true} 156embedded-hal-async = { version = "=1.0.0-rc.1", optional = true}
157 157
158futures-util = { version = "0.3.17", default-features = false } 158futures-util = { version = "0.3.17", default-features = false }
159atomic-polyfill = "1.0.1" 159atomic-polyfill = "1.0.1"
diff --git a/embassy-usb/src/class/cdc_ncm/mod.rs b/embassy-usb/src/class/cdc_ncm/mod.rs
index fcfa0bfcd..830e9b768 100644
--- a/embassy-usb/src/class/cdc_ncm/mod.rs
+++ b/embassy-usb/src/class/cdc_ncm/mod.rs
@@ -248,6 +248,8 @@ pub struct CdcNcmClass<'d, D: Driver<'d>> {
248 write_ep: D::EndpointIn, 248 write_ep: D::EndpointIn,
249 249
250 _control: &'d ControlShared, 250 _control: &'d ControlShared,
251
252 max_packet_size: usize,
251} 253}
252 254
253impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> { 255impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
@@ -338,6 +340,7 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
338 read_ep, 340 read_ep,
339 write_ep, 341 write_ep,
340 _control: &state.shared, 342 _control: &state.shared,
343 max_packet_size: max_packet_size as usize,
341 } 344 }
342 } 345 }
343 346
@@ -349,6 +352,7 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
349 Sender { 352 Sender {
350 write_ep: self.write_ep, 353 write_ep: self.write_ep,
351 seq: 0, 354 seq: 0,
355 max_packet_size: self.max_packet_size,
352 }, 356 },
353 Receiver { 357 Receiver {
354 data_if: self.data_if, 358 data_if: self.data_if,
@@ -365,6 +369,7 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
365pub struct Sender<'d, D: Driver<'d>> { 369pub struct Sender<'d, D: Driver<'d>> {
366 write_ep: D::EndpointIn, 370 write_ep: D::EndpointIn,
367 seq: u16, 371 seq: u16,
372 max_packet_size: usize,
368} 373}
369 374
370impl<'d, D: Driver<'d>> Sender<'d, D> { 375impl<'d, D: Driver<'d>> Sender<'d, D> {
@@ -375,8 +380,8 @@ impl<'d, D: Driver<'d>> Sender<'d, D> {
375 let seq = self.seq; 380 let seq = self.seq;
376 self.seq = self.seq.wrapping_add(1); 381 self.seq = self.seq.wrapping_add(1);
377 382
378 const MAX_PACKET_SIZE: usize = 64; // TODO unhardcode
379 const OUT_HEADER_LEN: usize = 28; 383 const OUT_HEADER_LEN: usize = 28;
384 const ABS_MAX_PACKET_SIZE: usize = 512;
380 385
381 let header = NtbOutHeader { 386 let header = NtbOutHeader {
382 nth_sig: SIG_NTH, 387 nth_sig: SIG_NTH,
@@ -395,27 +400,27 @@ impl<'d, D: Driver<'d>> Sender<'d, D> {
395 }; 400 };
396 401
397 // Build first packet on a buffer, send next packets straight from `data`. 402 // Build first packet on a buffer, send next packets straight from `data`.
398 let mut buf = [0; MAX_PACKET_SIZE]; 403 let mut buf = [0; ABS_MAX_PACKET_SIZE];
399 let n = byteify(&mut buf, header); 404 let n = byteify(&mut buf, header);
400 assert_eq!(n.len(), OUT_HEADER_LEN); 405 assert_eq!(n.len(), OUT_HEADER_LEN);
401 406
402 if OUT_HEADER_LEN + data.len() < MAX_PACKET_SIZE { 407 if OUT_HEADER_LEN + data.len() < self.max_packet_size {
403 // First packet is not full, just send it. 408 // First packet is not full, just send it.
404 // No need to send ZLP because it's short for sure. 409 // No need to send ZLP because it's short for sure.
405 buf[OUT_HEADER_LEN..][..data.len()].copy_from_slice(data); 410 buf[OUT_HEADER_LEN..][..data.len()].copy_from_slice(data);
406 self.write_ep.write(&buf[..OUT_HEADER_LEN + data.len()]).await?; 411 self.write_ep.write(&buf[..OUT_HEADER_LEN + data.len()]).await?;
407 } else { 412 } else {
408 let (d1, d2) = data.split_at(MAX_PACKET_SIZE - OUT_HEADER_LEN); 413 let (d1, d2) = data.split_at(self.max_packet_size - OUT_HEADER_LEN);
409 414
410 buf[OUT_HEADER_LEN..].copy_from_slice(d1); 415 buf[OUT_HEADER_LEN..self.max_packet_size].copy_from_slice(d1);
411 self.write_ep.write(&buf).await?; 416 self.write_ep.write(&buf[..self.max_packet_size]).await?;
412 417
413 for chunk in d2.chunks(MAX_PACKET_SIZE) { 418 for chunk in d2.chunks(self.max_packet_size) {
414 self.write_ep.write(&chunk).await?; 419 self.write_ep.write(&chunk).await?;
415 } 420 }
416 421
417 // Send ZLP if needed. 422 // Send ZLP if needed.
418 if d2.len() % MAX_PACKET_SIZE == 0 { 423 if d2.len() % self.max_packet_size == 0 {
419 self.write_ep.write(&[]).await?; 424 self.write_ep.write(&[]).await?;
420 } 425 }
421 } 426 }
diff --git a/embassy-usb/src/msos.rs b/embassy-usb/src/msos.rs
index 187b2ff8e..847338e5f 100644
--- a/embassy-usb/src/msos.rs
+++ b/embassy-usb/src/msos.rs
@@ -526,7 +526,7 @@ impl<'a> PropertyData<'a> {
526 PropertyData::Binary(val) => val.len(), 526 PropertyData::Binary(val) => val.len(),
527 PropertyData::DwordLittleEndian(val) | PropertyData::DwordBigEndian(val) => core::mem::size_of_val(val), 527 PropertyData::DwordLittleEndian(val) | PropertyData::DwordBigEndian(val) => core::mem::size_of_val(val),
528 PropertyData::RegMultiSz(val) => { 528 PropertyData::RegMultiSz(val) => {
529 core::mem::size_of::<u16>() * val.iter().map(|x| x.encode_utf16().count() + 1).sum::<usize>() + 1 529 core::mem::size_of::<u16>() * (val.iter().map(|x| x.encode_utf16().count() + 1).sum::<usize>() + 1)
530 } 530 }
531 } 531 }
532 } 532 }
diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs
index f0dda39d0..15fdaca82 100644
--- a/examples/boot/application/rp/src/bin/a.rs
+++ b/examples/boot/application/rp/src/bin/a.rs
@@ -7,7 +7,7 @@ use core::cell::RefCell;
7use defmt_rtt as _; 7use defmt_rtt as _;
8use embassy_boot_rp::*; 8use embassy_boot_rp::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::flash::{self, Flash}; 10use embassy_rp::flash::Flash;
11use embassy_rp::gpio::{Level, Output}; 11use embassy_rp::gpio::{Level, Output};
12use embassy_rp::watchdog::Watchdog; 12use embassy_rp::watchdog::Watchdog;
13use embassy_sync::blocking_mutex::Mutex; 13use embassy_sync::blocking_mutex::Mutex;
@@ -34,7 +34,7 @@ async fn main(_s: Spawner) {
34 let mut watchdog = Watchdog::new(p.WATCHDOG); 34 let mut watchdog = Watchdog::new(p.WATCHDOG);
35 watchdog.start(Duration::from_secs(8)); 35 watchdog.start(Duration::from_secs(8));
36 36
37 let flash = Flash::<_, flash::Blocking, FLASH_SIZE>::new(p.FLASH); 37 let flash = Flash::<_, _, FLASH_SIZE>::new_blocking(p.FLASH);
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);
diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs
index 72c95c02a..74e2e293f 100644
--- a/examples/boot/bootloader/nrf/src/main.rs
+++ b/examples/boot/bootloader/nrf/src/main.rs
@@ -33,9 +33,7 @@ fn main() -> ! {
33 33
34 let config = BootLoaderConfig::from_linkerfile_blocking(&flash); 34 let config = BootLoaderConfig::from_linkerfile_blocking(&flash);
35 let active_offset = config.active.offset(); 35 let active_offset = config.active.offset();
36 let mut bl: BootLoader<_, _, _> = BootLoader::new(config); 36 let bl: BootLoader = BootLoader::prepare(config);
37
38 bl.prepare();
39 37
40 unsafe { bl.load(active_offset) } 38 unsafe { bl.load(active_offset) }
41} 39}
diff --git a/examples/boot/bootloader/rp/src/main.rs b/examples/boot/bootloader/rp/src/main.rs
index 6a81db804..c0e75d1ea 100644
--- a/examples/boot/bootloader/rp/src/main.rs
+++ b/examples/boot/bootloader/rp/src/main.rs
@@ -29,9 +29,7 @@ fn main() -> ! {
29 29
30 let config = BootLoaderConfig::from_linkerfile_blocking(&flash); 30 let config = BootLoaderConfig::from_linkerfile_blocking(&flash);
31 let active_offset = config.active.offset(); 31 let active_offset = config.active.offset();
32 let mut bl: BootLoader<_, _, _> = BootLoader::new(config); 32 let bl: BootLoader = BootLoader::prepare(config);
33
34 bl.prepare();
35 33
36 unsafe { bl.load(embassy_rp::flash::FLASH_BASE as u32 + active_offset) } 34 unsafe { bl.load(embassy_rp::flash::FLASH_BASE as u32 + active_offset) }
37} 35}
diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs
index 262eed200..5fd9ea588 100644
--- a/examples/boot/bootloader/stm32/src/main.rs
+++ b/examples/boot/bootloader/stm32/src/main.rs
@@ -27,9 +27,7 @@ fn main() -> ! {
27 27
28 let config = BootLoaderConfig::from_linkerfile_blocking(&flash); 28 let config = BootLoaderConfig::from_linkerfile_blocking(&flash);
29 let active_offset = config.active.offset(); 29 let active_offset = config.active.offset();
30 let mut bl: BootLoader<_, _, _, 2048> = BootLoader::new(config); 30 let bl = BootLoader::prepare::<_, _, _, 2048>(config);
31
32 bl.prepare();
33 31
34 unsafe { bl.load(BANK1_REGION.base + active_offset) } 32 unsafe { bl.load(BANK1_REGION.base + active_offset) }
35} 33}
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index 15fe22d3a..2ce44b516 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -12,12 +12,14 @@ nightly = [
12 "embassy-nrf/nightly", 12 "embassy-nrf/nightly",
13 "embassy-net/nightly", 13 "embassy-net/nightly",
14 "embassy-net-esp-hosted", 14 "embassy-net-esp-hosted",
15 "embassy-net-enc28j60",
15 "embassy-nrf/unstable-traits", 16 "embassy-nrf/unstable-traits",
16 "embassy-time/nightly", 17 "embassy-time/nightly",
17 "embassy-time/unstable-traits", 18 "embassy-time/unstable-traits",
18 "static_cell/nightly", 19 "static_cell/nightly",
19 "embassy-usb", 20 "embassy-usb",
20 "embedded-io-async", 21 "embedded-io-async",
22 "embedded-hal-bus/async",
21 "embassy-net", 23 "embassy-net",
22 "embassy-lora", 24 "embassy-lora",
23 "lora-phy", 25 "lora-phy",
@@ -40,6 +42,7 @@ lora-phy = { version = "1", optional = true }
40lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } 42lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true }
41lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true } 43lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true }
42embassy-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 }
43 46
44defmt = "0.3" 47defmt = "0.3"
45defmt-rtt = "0.4" 48defmt-rtt = "0.4"
@@ -54,9 +57,14 @@ rand = { version = "0.8.4", default-features = false }
54embedded-storage = "0.3.0" 57embedded-storage = "0.3.0"
55usbd-hid = "0.6.0" 58usbd-hid = "0.6.0"
56serde = { version = "1.0.136", default-features = false } 59serde = { version = "1.0.136", default-features = false }
57embedded-hal-async = { version = "0.2.0-alpha.2", optional = true } 60embedded-hal = { version = "1.0.0-rc.1" }
61embedded-hal-async = { version = "1.0.0-rc.1", optional = true }
62embedded-hal-bus = { version = "0.1.0-rc.1" }
58num-integer = { version = "0.1.45", default-features = false } 63num-integer = { version = "0.1.45", default-features = false }
59microfft = "0.5.0" 64microfft = "0.5.0"
60 65
61[profile.release] 66[profile.release]
62debug = 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/channel.rs b/examples/nrf52840/src/bin/channel.rs
index d782a79e7..bd9c909da 100644
--- a/examples/nrf52840/src/bin/channel.rs
+++ b/examples/nrf52840/src/bin/channel.rs
@@ -35,7 +35,7 @@ async fn main(spawner: Spawner) {
35 unwrap!(spawner.spawn(my_task())); 35 unwrap!(spawner.spawn(my_task()));
36 36
37 loop { 37 loop {
38 match CHANNEL.recv().await { 38 match CHANNEL.receive().await {
39 LedState::On => led.set_high(), 39 LedState::On => led.set_high(),
40 LedState::Off => led.set_low(), 40 LedState::Off => led.set_low(),
41 } 41 }
diff --git a/examples/nrf52840/src/bin/channel_sender_receiver.rs b/examples/nrf52840/src/bin/channel_sender_receiver.rs
index fcccdaed5..ec4f1d800 100644
--- a/examples/nrf52840/src/bin/channel_sender_receiver.rs
+++ b/examples/nrf52840/src/bin/channel_sender_receiver.rs
@@ -33,7 +33,7 @@ async fn recv_task(led: AnyPin, receiver: Receiver<'static, NoopRawMutex, LedSta
33 let mut led = Output::new(led, Level::Low, OutputDrive::Standard); 33 let mut led = Output::new(led, Level::Low, OutputDrive::Standard);
34 34
35 loop { 35 loop {
36 match receiver.recv().await { 36 match receiver.receive().await {
37 LedState::On => led.set_high(), 37 LedState::On => led.set_high(),
38 LedState::Off => led.set_low(), 38 LedState::Off => led.set_low(),
39 } 39 }
diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
new file mode 100644
index 000000000..d1b796fab
--- /dev/null
+++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
@@ -0,0 +1,124 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_net::tcp::TcpSocket;
8use embassy_net::{Stack, StackResources};
9use embassy_net_enc28j60::Enc28j60;
10use embassy_nrf::gpio::{Level, Output, OutputDrive};
11use embassy_nrf::rng::Rng;
12use embassy_nrf::spim::Spim;
13use embassy_nrf::{bind_interrupts, peripherals, spim};
14use embassy_time::Delay;
15use embedded_hal_bus::spi::ExclusiveDevice;
16use embedded_io_async::Write;
17use static_cell::make_static;
18use {defmt_rtt as _, panic_probe as _};
19
20bind_interrupts!(struct Irqs {
21 SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
22 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>;
23});
24
25#[embassy_executor::task]
26async fn net_task(
27 stack: &'static Stack<
28 Enc28j60<
29 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_15>, Delay>,
30 Output<'static, peripherals::P0_13>,
31 >,
32 >,
33) -> ! {
34 stack.run().await
35}
36
37#[embassy_executor::main]
38async fn main(spawner: Spawner) {
39 let p = embassy_nrf::init(Default::default());
40 info!("running!");
41
42 let eth_sck = p.P0_20;
43 let eth_mosi = p.P0_22;
44 let eth_miso = p.P0_24;
45 let eth_cs = p.P0_15;
46 let eth_rst = p.P0_13;
47 let _eth_irq = p.P0_12;
48
49 let mut config = spim::Config::default();
50 config.frequency = spim::Frequency::M16;
51 let spi = spim::Spim::new(p.SPI3, Irqs, eth_sck, eth_miso, eth_mosi, config);
52 let cs = Output::new(eth_cs, Level::High, OutputDrive::Standard);
53 let spi = ExclusiveDevice::new(spi, cs, Delay);
54
55 let rst = Output::new(eth_rst, Level::High, OutputDrive::Standard);
56 let mac_addr = [2, 3, 4, 5, 6, 7];
57 let device = Enc28j60::new(spi, Some(rst), mac_addr);
58
59 let config = embassy_net::Config::dhcpv4(Default::default());
60 // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
61 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
62 // dns_servers: Vec::new(),
63 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
64 // });
65
66 // Generate random seed
67 let mut rng = Rng::new(p.RNG, Irqs);
68 let mut seed = [0; 8];
69 rng.blocking_fill_bytes(&mut seed);
70 let seed = u64::from_le_bytes(seed);
71
72 // Init network stack
73 let stack = &*make_static!(Stack::new(
74 device,
75 config,
76 make_static!(StackResources::<2>::new()),
77 seed
78 ));
79
80 unwrap!(spawner.spawn(net_task(stack)));
81
82 // And now we can use it!
83
84 let mut rx_buffer = [0; 4096];
85 let mut tx_buffer = [0; 4096];
86 let mut buf = [0; 4096];
87
88 loop {
89 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
90 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
91
92 info!("Listening on TCP:1234...");
93 if let Err(e) = socket.accept(1234).await {
94 warn!("accept error: {:?}", e);
95 continue;
96 }
97
98 info!("Received connection from {:?}", socket.remote_endpoint());
99
100 loop {
101 let n = match socket.read(&mut buf).await {
102 Ok(0) => {
103 warn!("read EOF");
104 break;
105 }
106 Ok(n) => n,
107 Err(e) => {
108 warn!("read error: {:?}", e);
109 break;
110 }
111 };
112
113 info!("rxd {:02x}", &buf[..n]);
114
115 match socket.write_all(&buf[..n]).await {
116 Ok(()) => {}
117 Err(e) => {
118 warn!("write error: {:?}", e);
119 break;
120 }
121 };
122 }
123 }
124}
diff --git a/examples/nrf52840/src/bin/uart_split.rs b/examples/nrf52840/src/bin/uart_split.rs
index 9979a1d53..b748bfcd8 100644
--- a/examples/nrf52840/src/bin/uart_split.rs
+++ b/examples/nrf52840/src/bin/uart_split.rs
@@ -46,7 +46,7 @@ async fn main(spawner: Spawner) {
46 // back out the buffer we receive from the read 46 // back out the buffer we receive from the read
47 // task. 47 // task.
48 loop { 48 loop {
49 let buf = CHANNEL.recv().await; 49 let buf = CHANNEL.receive().await;
50 info!("writing..."); 50 info!("writing...");
51 unwrap!(tx.write(&buf).await); 51 unwrap!(tx.write(&buf).await);
52 } 52 }
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
index e3b80d821..a60822fd9 100644
--- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs
+++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
@@ -11,7 +11,7 @@ use embassy_nrf::rng::Rng;
11use embassy_nrf::spim::{self, Spim}; 11use embassy_nrf::spim::{self, Spim};
12use embassy_nrf::{bind_interrupts, peripherals}; 12use embassy_nrf::{bind_interrupts, peripherals};
13use embassy_time::Delay; 13use embassy_time::Delay;
14use embedded_hal_async::spi::ExclusiveDevice; 14use embedded_hal_bus::spi::ExclusiveDevice;
15use embedded_io_async::Write; 15use embedded_io_async::Write;
16use static_cell::make_static; 16use static_cell::make_static;
17use {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 _};
@@ -72,8 +72,8 @@ async fn main(spawner: Spawner) {
72 72
73 unwrap!(spawner.spawn(wifi_task(runner))); 73 unwrap!(spawner.spawn(wifi_task(runner)));
74 74
75 control.init().await; 75 unwrap!(control.init().await);
76 control.join(WIFI_NETWORK, WIFI_PASSWORD).await; 76 unwrap!(control.connect(WIFI_NETWORK, WIFI_PASSWORD).await);
77 77
78 let config = embassy_net::Config::dhcpv4(Default::default()); 78 let config = embassy_net::Config::dhcpv4(Default::default());
79 // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { 79 // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index d83e370df..102611bc0 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -13,7 +13,7 @@ embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["ni
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"] }
16embassy-net-w5500 = { version = "0.1.0", path = "../../embassy-net-w5500", features = ["defmt"] } 16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
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"] }
@@ -42,8 +42,9 @@ smart-leds = "0.3.0"
42heapless = "0.7.15" 42heapless = "0.7.15"
43usbd-hid = "0.6.1" 43usbd-hid = "0.6.1"
44 44
45embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" } 45embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
46embedded-hal-async = "0.2.0-alpha.2" 46embedded-hal-async = "1.0.0-rc.1"
47embedded-hal-bus = { version = "0.1.0-rc.1", features = ["async"] }
47embedded-io-async = { version = "0.5.0", features = ["defmt-03"] } 48embedded-io-async = { version = "0.5.0", features = ["defmt-03"] }
48embedded-storage = { version = "0.3" } 49embedded-storage = { version = "0.3" }
49static_cell = { version = "1.1", features = ["nightly"]} 50static_cell = { version = "1.1", features = ["nightly"]}
@@ -53,4 +54,7 @@ pio = "0.2.1"
53rand = { version = "0.8.5", default-features = false } 54rand = { version = "0.8.5", default-features = false }
54 55
55[profile.release] 56[profile.release]
56debug = 2 \ No newline at end of file 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/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
index 9f800d0d9..c0fde62ab 100644
--- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs
+++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
@@ -10,13 +10,14 @@ use defmt::*;
10use embassy_executor::Spawner; 10use embassy_executor::Spawner;
11use embassy_futures::yield_now; 11use embassy_futures::yield_now;
12use embassy_net::{Stack, StackResources}; 12use embassy_net::{Stack, StackResources};
13use embassy_net_w5500::*; 13use embassy_net_wiznet::chip::W5500;
14use embassy_net_wiznet::*;
14use embassy_rp::clocks::RoscRng; 15use embassy_rp::clocks::RoscRng;
15use embassy_rp::gpio::{Input, Level, Output, Pull}; 16use embassy_rp::gpio::{Input, Level, Output, Pull};
16use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; 17use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
17use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; 18use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
18use embassy_time::{Delay, Duration}; 19use embassy_time::{Delay, Duration};
19use embedded_hal_async::spi::ExclusiveDevice; 20use embedded_hal_bus::spi::ExclusiveDevice;
20use embedded_io_async::Write; 21use embedded_io_async::Write;
21use rand::RngCore; 22use rand::RngCore;
22use static_cell::make_static; 23use static_cell::make_static;
@@ -26,6 +27,7 @@ use {defmt_rtt as _, panic_probe as _};
26async fn ethernet_task( 27async fn ethernet_task(
27 runner: Runner< 28 runner: Runner<
28 'static, 29 'static,
30 W5500,
29 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, 31 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
30 Input<'static, PIN_21>, 32 Input<'static, PIN_21>,
31 Output<'static, PIN_20>, 33 Output<'static, PIN_20>,
@@ -54,7 +56,7 @@ async fn main(spawner: Spawner) {
54 56
55 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 57 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
56 let state = make_static!(State::<8, 8>::new()); 58 let state = make_static!(State::<8, 8>::new());
57 let (device, runner) = embassy_net_w5500::new( 59 let (device, runner) = embassy_net_wiznet::new(
58 mac_addr, 60 mac_addr,
59 state, 61 state,
60 ExclusiveDevice::new(spi, cs, Delay), 62 ExclusiveDevice::new(spi, cs, Delay),
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
index fee84b613..e593acae4 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
@@ -12,13 +12,14 @@ use defmt::*;
12use embassy_executor::Spawner; 12use embassy_executor::Spawner;
13use embassy_futures::yield_now; 13use embassy_futures::yield_now;
14use embassy_net::{Stack, StackResources}; 14use embassy_net::{Stack, StackResources};
15use embassy_net_w5500::*; 15use embassy_net_wiznet::chip::W5500;
16use embassy_net_wiznet::*;
16use embassy_rp::clocks::RoscRng; 17use embassy_rp::clocks::RoscRng;
17use embassy_rp::gpio::{Input, Level, Output, Pull}; 18use embassy_rp::gpio::{Input, Level, Output, Pull};
18use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; 19use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
19use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; 20use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
20use embassy_time::{Delay, Duration, Timer}; 21use embassy_time::{Delay, Duration, Timer};
21use embedded_hal_async::spi::ExclusiveDevice; 22use embedded_hal_bus::spi::ExclusiveDevice;
22use embedded_io_async::Write; 23use embedded_io_async::Write;
23use rand::RngCore; 24use rand::RngCore;
24use static_cell::make_static; 25use static_cell::make_static;
@@ -28,6 +29,7 @@ use {defmt_rtt as _, panic_probe as _};
28async fn ethernet_task( 29async fn ethernet_task(
29 runner: Runner< 30 runner: Runner<
30 'static, 31 'static,
32 W5500,
31 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, 33 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
32 Input<'static, PIN_21>, 34 Input<'static, PIN_21>,
33 Output<'static, PIN_20>, 35 Output<'static, PIN_20>,
@@ -57,7 +59,7 @@ async fn main(spawner: Spawner) {
57 59
58 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 60 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
59 let state = make_static!(State::<8, 8>::new()); 61 let state = make_static!(State::<8, 8>::new());
60 let (device, runner) = embassy_net_w5500::new( 62 let (device, runner) = embassy_net_wiznet::new(
61 mac_addr, 63 mac_addr,
62 state, 64 state,
63 ExclusiveDevice::new(spi, cs, Delay), 65 ExclusiveDevice::new(spi, cs, Delay),
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
index 024574267..c62caed7a 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
@@ -11,21 +11,24 @@ use defmt::*;
11use embassy_executor::Spawner; 11use embassy_executor::Spawner;
12use embassy_futures::yield_now; 12use embassy_futures::yield_now;
13use embassy_net::{Stack, StackResources}; 13use embassy_net::{Stack, StackResources};
14use embassy_net_w5500::*; 14use embassy_net_wiznet::chip::W5500;
15use embassy_net_wiznet::*;
15use embassy_rp::clocks::RoscRng; 16use embassy_rp::clocks::RoscRng;
16use embassy_rp::gpio::{Input, Level, Output, Pull}; 17use embassy_rp::gpio::{Input, Level, Output, Pull};
17use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; 18use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
18use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; 19use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
19use embassy_time::{Delay, Duration}; 20use embassy_time::{Delay, Duration};
20use embedded_hal_async::spi::ExclusiveDevice; 21use embedded_hal_bus::spi::ExclusiveDevice;
21use embedded_io_async::Write; 22use embedded_io_async::Write;
22use rand::RngCore; 23use rand::RngCore;
23use static_cell::make_static; 24use static_cell::make_static;
24use {defmt_rtt as _, panic_probe as _}; 25use {defmt_rtt as _, panic_probe as _};
26
25#[embassy_executor::task] 27#[embassy_executor::task]
26async fn ethernet_task( 28async fn ethernet_task(
27 runner: Runner< 29 runner: Runner<
28 'static, 30 'static,
31 W5500,
29 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, 32 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
30 Input<'static, PIN_21>, 33 Input<'static, PIN_21>,
31 Output<'static, PIN_20>, 34 Output<'static, PIN_20>,
@@ -55,7 +58,7 @@ async fn main(spawner: Spawner) {
55 58
56 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 59 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
57 let state = make_static!(State::<8, 8>::new()); 60 let state = make_static!(State::<8, 8>::new());
58 let (device, runner) = embassy_net_w5500::new( 61 let (device, runner) = embassy_net_wiznet::new(
59 mac_addr, 62 mac_addr,
60 state, 63 state,
61 ExclusiveDevice::new(spi, cs, Delay), 64 ExclusiveDevice::new(spi, cs, Delay),
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs
index 038432b17..76dabce1c 100644
--- a/examples/rp/src/bin/ethernet_w5500_udp.rs
+++ b/examples/rp/src/bin/ethernet_w5500_udp.rs
@@ -11,20 +11,23 @@ use embassy_executor::Spawner;
11use embassy_futures::yield_now; 11use embassy_futures::yield_now;
12use embassy_net::udp::{PacketMetadata, UdpSocket}; 12use embassy_net::udp::{PacketMetadata, UdpSocket};
13use embassy_net::{Stack, StackResources}; 13use embassy_net::{Stack, StackResources};
14use embassy_net_w5500::*; 14use embassy_net_wiznet::chip::W5500;
15use embassy_net_wiznet::*;
15use embassy_rp::clocks::RoscRng; 16use embassy_rp::clocks::RoscRng;
16use embassy_rp::gpio::{Input, Level, Output, Pull}; 17use embassy_rp::gpio::{Input, Level, Output, Pull};
17use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; 18use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
18use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; 19use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
19use embassy_time::Delay; 20use embassy_time::Delay;
20use embedded_hal_async::spi::ExclusiveDevice; 21use embedded_hal_bus::spi::ExclusiveDevice;
21use rand::RngCore; 22use rand::RngCore;
22use static_cell::make_static; 23use static_cell::make_static;
23use {defmt_rtt as _, panic_probe as _}; 24use {defmt_rtt as _, panic_probe as _};
25
24#[embassy_executor::task] 26#[embassy_executor::task]
25async fn ethernet_task( 27async fn ethernet_task(
26 runner: Runner< 28 runner: Runner<
27 'static, 29 'static,
30 W5500,
28 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, 31 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
29 Input<'static, PIN_21>, 32 Input<'static, PIN_21>,
30 Output<'static, PIN_20>, 33 Output<'static, PIN_20>,
@@ -53,7 +56,7 @@ async fn main(spawner: Spawner) {
53 56
54 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; 57 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
55 let state = make_static!(State::<8, 8>::new()); 58 let state = make_static!(State::<8, 8>::new());
56 let (device, runner) = embassy_net_w5500::new( 59 let (device, runner) = embassy_net_wiznet::new(
57 mac_addr, 60 mac_addr,
58 state, 61 state,
59 ExclusiveDevice::new(spi, cs, Delay), 62 ExclusiveDevice::new(spi, cs, Delay),
diff --git a/examples/rp/src/bin/flash.rs b/examples/rp/src/bin/flash.rs
index 88bb931d2..911a657eb 100644
--- a/examples/rp/src/bin/flash.rs
+++ b/examples/rp/src/bin/flash.rs
@@ -28,12 +28,12 @@ async fn main(_spawner: Spawner) {
28 let mut flash = embassy_rp::flash::Flash::<_, Async, FLASH_SIZE>::new(p.FLASH, p.DMA_CH0); 28 let mut flash = embassy_rp::flash::Flash::<_, Async, FLASH_SIZE>::new(p.FLASH, p.DMA_CH0);
29 29
30 // Get JEDEC id 30 // Get JEDEC id
31 let jedec = flash.jedec_id().unwrap(); 31 let jedec = flash.blocking_jedec_id().unwrap();
32 info!("jedec id: 0x{:x}", jedec); 32 info!("jedec id: 0x{:x}", jedec);
33 33
34 // Get unique id 34 // Get unique id
35 let mut uid = [0; 8]; 35 let mut uid = [0; 8];
36 flash.unique_id(&mut uid).unwrap(); 36 flash.blocking_unique_id(&mut uid).unwrap();
37 info!("unique id: {:?}", uid); 37 info!("unique id: {:?}", uid);
38 38
39 erase_write_sector(&mut flash, 0x00); 39 erase_write_sector(&mut flash, 0x00);
@@ -48,25 +48,25 @@ async fn main(_spawner: Spawner) {
48fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) { 48fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) {
49 info!(">>>> [multiwrite_bytes]"); 49 info!(">>>> [multiwrite_bytes]");
50 let mut read_buf = [0u8; ERASE_SIZE]; 50 let mut read_buf = [0u8; ERASE_SIZE];
51 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf)); 51 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf));
52 52
53 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); 53 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
54 info!("Contents start with {=[u8]}", read_buf[0..4]); 54 info!("Contents start with {=[u8]}", read_buf[0..4]);
55 55
56 defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); 56 defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
57 57
58 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf)); 58 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf));
59 info!("Contents after erase starts with {=[u8]}", read_buf[0..4]); 59 info!("Contents after erase starts with {=[u8]}", read_buf[0..4]);
60 if read_buf.iter().any(|x| *x != 0xFF) { 60 if read_buf.iter().any(|x| *x != 0xFF) {
61 defmt::panic!("unexpected"); 61 defmt::panic!("unexpected");
62 } 62 }
63 63
64 defmt::unwrap!(flash.write(ADDR_OFFSET + offset, &[0x01])); 64 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, &[0x01]));
65 defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 1, &[0x02])); 65 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 1, &[0x02]));
66 defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 2, &[0x03])); 66 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 2, &[0x03]));
67 defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 3, &[0x04])); 67 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 3, &[0x04]));
68 68
69 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf)); 69 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf));
70 info!("Contents after write starts with {=[u8]}", read_buf[0..4]); 70 info!("Contents after write starts with {=[u8]}", read_buf[0..4]);
71 if &read_buf[0..4] != &[0x01, 0x02, 0x03, 0x04] { 71 if &read_buf[0..4] != &[0x01, 0x02, 0x03, 0x04] {
72 defmt::panic!("unexpected"); 72 defmt::panic!("unexpected");
@@ -76,14 +76,14 @@ fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH
76fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) { 76fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) {
77 info!(">>>> [erase_write_sector]"); 77 info!(">>>> [erase_write_sector]");
78 let mut buf = [0u8; ERASE_SIZE]; 78 let mut buf = [0u8; ERASE_SIZE];
79 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf)); 79 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf));
80 80
81 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); 81 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
82 info!("Contents start with {=[u8]}", buf[0..4]); 82 info!("Contents start with {=[u8]}", buf[0..4]);
83 83
84 defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); 84 defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
85 85
86 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf)); 86 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf));
87 info!("Contents after erase starts with {=[u8]}", buf[0..4]); 87 info!("Contents after erase starts with {=[u8]}", buf[0..4]);
88 if buf.iter().any(|x| *x != 0xFF) { 88 if buf.iter().any(|x| *x != 0xFF) {
89 defmt::panic!("unexpected"); 89 defmt::panic!("unexpected");
@@ -93,9 +93,9 @@ fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLA
93 *b = 0xDA; 93 *b = 0xDA;
94 } 94 }
95 95
96 defmt::unwrap!(flash.write(ADDR_OFFSET + offset, &buf)); 96 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, &buf));
97 97
98 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf)); 98 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf));
99 info!("Contents after write starts with {=[u8]}", buf[0..4]); 99 info!("Contents after write starts with {=[u8]}", buf[0..4]);
100 if buf.iter().any(|x| *x != 0xDA) { 100 if buf.iter().any(|x| *x != 0xDA) {
101 defmt::panic!("unexpected"); 101 defmt::panic!("unexpected");
@@ -111,7 +111,7 @@ async fn background_read(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async,
111 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); 111 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
112 info!("Contents start with {=u32:x}", buf[0]); 112 info!("Contents start with {=u32:x}", buf[0]);
113 113
114 defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); 114 defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
115 115
116 defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await; 116 defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await;
117 info!("Contents after erase starts with {=u32:x}", buf[0]); 117 info!("Contents after erase starts with {=u32:x}", buf[0]);
@@ -123,7 +123,7 @@ async fn background_read(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async,
123 *b = 0xDABA1234; 123 *b = 0xDABA1234;
124 } 124 }
125 125
126 defmt::unwrap!(flash.write(ADDR_OFFSET + offset, unsafe { 126 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, unsafe {
127 core::slice::from_raw_parts(buf.as_ptr() as *const u8, buf.len() * 4) 127 core::slice::from_raw_parts(buf.as_ptr() as *const u8, buf.len() * 4)
128 })); 128 }));
129 129
diff --git a/examples/rp/src/bin/lora_p2p_send_multicore.rs b/examples/rp/src/bin/lora_p2p_send_multicore.rs
index 89a62818d..b54cc92f6 100644
--- a/examples/rp/src/bin/lora_p2p_send_multicore.rs
+++ b/examples/rp/src/bin/lora_p2p_send_multicore.rs
@@ -113,7 +113,7 @@ async fn core1_task(
113 }; 113 };
114 114
115 loop { 115 loop {
116 let buffer: [u8; 3] = CHANNEL.recv().await; 116 let buffer: [u8; 3] = CHANNEL.receive().await;
117 match lora.prepare_for_tx(&mdltn_params, 20, false).await { 117 match lora.prepare_for_tx(&mdltn_params, 20, false).await {
118 Ok(()) => {} 118 Ok(()) => {}
119 Err(err) => { 119 Err(err) => {
diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs
index 893b724bf..bf017f6a7 100644
--- a/examples/rp/src/bin/multicore.rs
+++ b/examples/rp/src/bin/multicore.rs
@@ -56,7 +56,7 @@ async fn core0_task() {
56async fn core1_task(mut led: Output<'static, PIN_25>) { 56async fn core1_task(mut led: Output<'static, PIN_25>) {
57 info!("Hello from core 1"); 57 info!("Hello from core 1");
58 loop { 58 loop {
59 match CHANNEL.recv().await { 59 match CHANNEL.receive().await {
60 LedState::On => led.set_high(), 60 LedState::On => led.set_high(),
61 LedState::Off => led.set_low(), 61 LedState::Off => led.set_low(),
62 } 62 }
diff --git a/examples/stm32f3/src/bin/button_events.rs b/examples/stm32f3/src/bin/button_events.rs
index 02c475f66..8e97e85eb 100644
--- a/examples/stm32f3/src/bin/button_events.rs
+++ b/examples/stm32f3/src/bin/button_events.rs
@@ -49,12 +49,12 @@ impl<'a> Leds<'a> {
49 49
50 async fn show(&mut self) { 50 async fn show(&mut self) {
51 self.leds[self.current_led].set_high(); 51 self.leds[self.current_led].set_high();
52 if let Ok(new_message) = with_timeout(Duration::from_millis(500), CHANNEL.recv()).await { 52 if let Ok(new_message) = with_timeout(Duration::from_millis(500), CHANNEL.receive()).await {
53 self.leds[self.current_led].set_low(); 53 self.leds[self.current_led].set_low();
54 self.process_event(new_message).await; 54 self.process_event(new_message).await;
55 } else { 55 } else {
56 self.leds[self.current_led].set_low(); 56 self.leds[self.current_led].set_low();
57 if let Ok(new_message) = with_timeout(Duration::from_millis(200), CHANNEL.recv()).await { 57 if let Ok(new_message) = with_timeout(Duration::from_millis(200), CHANNEL.receive()).await {
58 self.process_event(new_message).await; 58 self.process_event(new_message).await;
59 } 59 }
60 } 60 }
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml
index 44d0a9574..5d73e435e 100644
--- a/examples/stm32h5/Cargo.toml
+++ b/examples/stm32h5/Cargo.toml
@@ -20,8 +20,8 @@ defmt-rtt = "0.4"
20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
21cortex-m-rt = "0.7.0" 21cortex-m-rt = "0.7.0"
22embedded-hal = "0.2.6" 22embedded-hal = "0.2.6"
23embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" } 23embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
24embedded-hal-async = { version = "=0.2.0-alpha.2" } 24embedded-hal-async = { version = "=1.0.0-rc.1" }
25embedded-nal-async = { version = "0.5.0" } 25embedded-nal-async = { version = "0.5.0" }
26panic-probe = { version = "0.3", features = ["print-defmt"] } 26panic-probe = { version = "0.3", features = ["print-defmt"] }
27futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 27futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs
index debd6f454..a6b2e690b 100644
--- a/examples/stm32h5/src/bin/usart_split.rs
+++ b/examples/stm32h5/src/bin/usart_split.rs
@@ -44,7 +44,7 @@ async fn main(spawner: Spawner) -> ! {
44 unwrap!(spawner.spawn(reader(rx))); 44 unwrap!(spawner.spawn(reader(rx)));
45 45
46 loop { 46 loop {
47 let buf = CHANNEL.recv().await; 47 let buf = CHANNEL.receive().await;
48 info!("writing..."); 48 info!("writing...");
49 unwrap!(tx.write(&buf).await); 49 unwrap!(tx.write(&buf).await);
50 } 50 }
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index e2e5f9364..c78c4c602 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -20,8 +20,8 @@ defmt-rtt = "0.4"
20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
21cortex-m-rt = "0.7.0" 21cortex-m-rt = "0.7.0"
22embedded-hal = "0.2.6" 22embedded-hal = "0.2.6"
23embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" } 23embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
24embedded-hal-async = { version = "=0.2.0-alpha.2" } 24embedded-hal-async = { version = "=1.0.0-rc.1" }
25embedded-nal-async = { version = "0.5.0" } 25embedded-nal-async = { version = "0.5.0" }
26panic-probe = { version = "0.3", features = ["print-defmt"] } 26panic-probe = { version = "0.3", features = ["print-defmt"] }
27futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 27futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs
index 330d1ce09..aa0753450 100644
--- a/examples/stm32h7/src/bin/usart_split.rs
+++ b/examples/stm32h7/src/bin/usart_split.rs
@@ -44,7 +44,7 @@ async fn main(spawner: Spawner) -> ! {
44 unwrap!(spawner.spawn(reader(rx))); 44 unwrap!(spawner.spawn(reader(rx)));
45 45
46 loop { 46 loop {
47 let buf = CHANNEL.recv().await; 47 let buf = CHANNEL.receive().await;
48 info!("writing..."); 48 info!("writing...");
49 unwrap!(tx.write(&buf).await); 49 unwrap!(tx.write(&buf).await);
50 } 50 }
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index 33aa05e65..332a6c5e5 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -37,3 +37,6 @@ 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/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index 3b27d8e81..944c8c27b 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -19,8 +19,8 @@ defmt-rtt = "0.4"
19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 21embedded-hal = "0.2.6"
22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" } 22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
23embedded-hal-async = { version = "=0.2.0-alpha.2" } 23embedded-hal-async = { version = "=1.0.0-rc.1" }
24panic-probe = { version = "0.3", features = ["print-defmt"] } 24panic-probe = { version = "0.3", features = ["print-defmt"] }
25futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 25futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
26heapless = { version = "0.7.5", default-features = false } 26heapless = { version = "0.7.5", default-features = false }
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml
index 48b69c8d0..5440807f6 100644
--- a/examples/stm32wl/Cargo.toml
+++ b/examples/stm32wl/Cargo.toml
@@ -30,3 +30,6 @@ 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/rust-toolchain.toml b/rust-toolchain.toml
index 179ed1d6a..7b34afa2b 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,7 +1,7 @@
1# Before upgrading check that everything is available on all tier1 targets here: 1# Before upgrading check that everything is available on all tier1 targets here:
2# https://rust-lang.github.io/rustup-components-history 2# https://rust-lang.github.io/rustup-components-history
3[toolchain] 3[toolchain]
4channel = "nightly-2023-06-28" 4channel = "nightly-2023-08-19"
5components = [ "rust-src", "rustfmt", "llvm-tools-preview" ] 5components = [ "rust-src", "rustfmt", "llvm-tools-preview" ]
6targets = [ 6targets = [
7 "thumbv7em-none-eabi", 7 "thumbv7em-none-eabi",
diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml
index 974a9413f..034ed85ea 100644
--- a/tests/nrf/Cargo.toml
+++ b/tests/nrf/Cargo.toml
@@ -15,7 +15,9 @@ embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defm
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"] }
17embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } 17embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
18embedded-hal-async = { version = "0.2.0-alpha.2" } 18embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] }
19embedded-hal-async = { version = "1.0.0-rc.1" }
20embedded-hal-bus = { version = "0.1.0-rc.1", features = ["async"] }
19static_cell = { version = "1.1", features = [ "nightly" ] } 21static_cell = { version = "1.1", features = [ "nightly" ] }
20 22
21defmt = "0.3" 23defmt = "0.3"
diff --git a/tests/nrf/src/bin/buffered_uart.rs b/tests/nrf/src/bin/buffered_uart.rs
index 72a4cb4ef..932e59264 100644
--- a/tests/nrf/src/bin/buffered_uart.rs
+++ b/tests/nrf/src/bin/buffered_uart.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"nrf52840-dk");
5mod common;
6 5
7use defmt::{assert_eq, *}; 6use defmt::{assert_eq, *};
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/tests/nrf/src/bin/buffered_uart_spam.rs b/tests/nrf/src/bin/buffered_uart_spam.rs
index 50960206f..8abeae6d4 100644
--- a/tests/nrf/src/bin/buffered_uart_spam.rs
+++ b/tests/nrf/src/bin/buffered_uart_spam.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"nrf52840-dk");
5mod common;
6 5
7use core::mem; 6use core::mem;
8use core::ptr::NonNull; 7use core::ptr::NonNull;
diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
new file mode 100644
index 000000000..0446d39ac
--- /dev/null
+++ b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
@@ -0,0 +1,250 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4teleprobe_meta::target!(b"ak-gwe-r7");
5teleprobe_meta::timeout!(120);
6
7use defmt::{error, info, unwrap};
8use embassy_executor::Spawner;
9use embassy_futures::join::join;
10use embassy_net::tcp::TcpSocket;
11use embassy_net::{Ipv4Address, Stack, StackResources};
12use embassy_net_enc28j60::Enc28j60;
13use embassy_nrf::gpio::{Level, Output, OutputDrive};
14use embassy_nrf::rng::Rng;
15use embassy_nrf::spim::{self, Spim};
16use embassy_nrf::{bind_interrupts, peripherals};
17use embassy_time::{with_timeout, Delay, Duration, Timer};
18use embedded_hal_bus::spi::ExclusiveDevice;
19use static_cell::make_static;
20use {defmt_rtt as _, panic_probe as _};
21
22bind_interrupts!(struct Irqs {
23 SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
24 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>;
25});
26
27type MyDriver = Enc28j60<
28 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_15>, Delay>,
29 Output<'static, peripherals::P0_13>,
30>;
31
32#[embassy_executor::task]
33async fn net_task(stack: &'static Stack<MyDriver>) -> ! {
34 stack.run().await
35}
36
37#[embassy_executor::main]
38async fn main(spawner: Spawner) {
39 let p = embassy_nrf::init(Default::default());
40 info!("running!");
41
42 let eth_sck = p.P0_20;
43 let eth_mosi = p.P0_22;
44 let eth_miso = p.P0_24;
45 let eth_cs = p.P0_15;
46 let eth_rst = p.P0_13;
47 let _eth_irq = p.P0_12;
48
49 let mut config = spim::Config::default();
50 config.frequency = spim::Frequency::M16;
51 let spi = spim::Spim::new(p.SPI3, Irqs, eth_sck, eth_miso, eth_mosi, config);
52 let cs = Output::new(eth_cs, Level::High, OutputDrive::Standard);
53 let spi = ExclusiveDevice::new(spi, cs, Delay);
54
55 let rst = Output::new(eth_rst, Level::High, OutputDrive::Standard);
56 let mac_addr = [2, 3, 4, 5, 6, 7];
57 let device = Enc28j60::new(spi, Some(rst), mac_addr);
58
59 let config = embassy_net::Config::dhcpv4(Default::default());
60 // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
61 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
62 // dns_servers: Vec::new(),
63 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
64 // });
65
66 // Generate random seed
67 let mut rng = Rng::new(p.RNG, Irqs);
68 let mut seed = [0; 8];
69 rng.blocking_fill_bytes(&mut seed);
70 let seed = u64::from_le_bytes(seed);
71
72 // Init network stack
73 let stack = &*make_static!(Stack::new(
74 device,
75 config,
76 make_static!(StackResources::<2>::new()),
77 seed
78 ));
79
80 unwrap!(spawner.spawn(net_task(stack)));
81
82 info!("Waiting for DHCP up...");
83 while stack.config_v4().is_none() {
84 Timer::after(Duration::from_millis(100)).await;
85 }
86 info!("IP addressing up!");
87
88 let down = test_download(stack).await;
89 let up = test_upload(stack).await;
90 let updown = test_upload_download(stack).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
96 info!("Test OK");
97 cortex_m::asm::bkpt();
98}
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/timer.rs b/tests/nrf/src/bin/timer.rs
index 607c5bbf1..c00f35fd1 100644
--- a/tests/nrf/src/bin/timer.rs
+++ b/tests/nrf/src/bin/timer.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"nrf52840-dk");
5mod common;
6 5
7use defmt::{assert, info}; 6use defmt::{assert, info};
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
index e2adfe0be..97ebafec8 100644
--- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
+++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
@@ -1,9 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4teleprobe_meta::target!(b"nrf52840-dk");
5#[path = "../common.rs"] 5teleprobe_meta::timeout!(120);
6mod common;
7 6
8use defmt::{error, info, unwrap}; 7use defmt::{error, info, unwrap};
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
@@ -15,12 +14,10 @@ use embassy_nrf::rng::Rng;
15use embassy_nrf::spim::{self, Spim}; 14use embassy_nrf::spim::{self, Spim};
16use embassy_nrf::{bind_interrupts, peripherals}; 15use embassy_nrf::{bind_interrupts, peripherals};
17use embassy_time::{with_timeout, Delay, Duration, Timer}; 16use embassy_time::{with_timeout, Delay, Duration, Timer};
18use embedded_hal_async::spi::ExclusiveDevice; 17use embedded_hal_bus::spi::ExclusiveDevice;
19use static_cell::make_static; 18use static_cell::make_static;
20use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _}; 19use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _};
21 20
22teleprobe_meta::timeout!(120);
23
24bind_interrupts!(struct Irqs { 21bind_interrupts!(struct Irqs {
25 SPIM3 => spim::InterruptHandler<peripherals::SPI3>; 22 SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
26 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>; 23 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>;
@@ -76,8 +73,8 @@ async fn main(spawner: Spawner) {
76 73
77 unwrap!(spawner.spawn(wifi_task(runner))); 74 unwrap!(spawner.spawn(wifi_task(runner)));
78 75
79 control.init().await; 76 unwrap!(control.init().await);
80 control.join(WIFI_NETWORK, WIFI_PASSWORD).await; 77 unwrap!(control.connect(WIFI_NETWORK, WIFI_PASSWORD).await);
81 78
82 // Generate random seed 79 // Generate random seed
83 let mut rng = Rng::new(p.RNG, Irqs); 80 let mut rng = Rng::new(p.RNG, Irqs);
diff --git a/tests/nrf/src/common.rs b/tests/nrf/src/common.rs
deleted file mode 100644
index 1a05ac1c5..000000000
--- a/tests/nrf/src/common.rs
+++ /dev/null
@@ -1 +0,0 @@
1teleprobe_meta::target!(b"nrf52840-dk");
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index 90a3bd0cf..6a3df4b9c 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -9,10 +9,11 @@ teleprobe-meta = "1.1"
9 9
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt"] } 12embassy-time = { version = "0.1.2", 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"] }
16cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } 17cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] }
17cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } 18cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] }
18 19
@@ -22,8 +23,9 @@ defmt-rtt = "0.4"
22cortex-m = { version = "0.7.6" } 23cortex-m = { version = "0.7.6" }
23cortex-m-rt = "0.7.0" 24cortex-m-rt = "0.7.0"
24embedded-hal = "0.2.6" 25embedded-hal = "0.2.6"
25embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" } 26embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
26embedded-hal-async = { version = "=0.2.0-alpha.2" } 27embedded-hal-async = { version = "=1.0.0-rc.1" }
28embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] }
27panic-probe = { version = "0.3.0", features = ["print-defmt"] } 29panic-probe = { version = "0.3.0", features = ["print-defmt"] }
28futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 30futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
29embedded-io-async = { version = "0.5.0" } 31embedded-io-async = { version = "0.5.0" }
@@ -31,6 +33,7 @@ embedded-storage = { version = "0.3" }
31static_cell = { version = "1.1", features = ["nightly"]} 33static_cell = { version = "1.1", features = ["nightly"]}
32pio = "0.2" 34pio = "0.2"
33pio-proc = "0.2" 35pio-proc = "0.2"
36rand = { version = "0.8.5", default-features = false }
34 37
35[profile.dev] 38[profile.dev]
36debug = 2 39debug = 2
diff --git a/tests/rp/src/bin/adc.rs b/tests/rp/src/bin/adc.rs
index b29a3a7cb..0250fd5f4 100644
--- a/tests/rp/src/bin/adc.rs
+++ b/tests/rp/src/bin/adc.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use defmt::*; 6use defmt::*;
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs
index fffdabc9b..1c665f95d 100644
--- a/tests/rp/src/bin/cyw43-perf.rs
+++ b/tests/rp/src/bin/cyw43-perf.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use cyw43_pio::PioSpi; 6use cyw43_pio::PioSpi;
8use defmt::{assert, panic, *}; 7use defmt::{assert, panic, *};
diff --git a/tests/rp/src/bin/dma_copy_async.rs b/tests/rp/src/bin/dma_copy_async.rs
index 2c0b559a9..b071ed9df 100644
--- a/tests/rp/src/bin/dma_copy_async.rs
+++ b/tests/rp/src/bin/dma_copy_async.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use defmt::{assert_eq, *}; 6use defmt::{assert_eq, *};
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/ethernet_w5100s_perf.rs b/tests/rp/src/bin/ethernet_w5100s_perf.rs
new file mode 100644
index 000000000..faa8638c0
--- /dev/null
+++ b/tests/rp/src/bin/ethernet_w5100s_perf.rs
@@ -0,0 +1,249 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4teleprobe_meta::target!(b"w5100s-evb-pico");
5teleprobe_meta::timeout!(120);
6
7use defmt::{assert, *};
8use embassy_executor::Spawner;
9use embassy_futures::join::join;
10use embassy_net::tcp::TcpSocket;
11use embassy_net::{Ipv4Address, Stack, StackResources};
12use embassy_net_wiznet::chip::W5100S;
13use embassy_net_wiznet::*;
14use embassy_rp::clocks::RoscRng;
15use embassy_rp::gpio::{Input, Level, Output, Pull};
16use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
17use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
18use embassy_time::{with_timeout, Delay, Duration, Timer};
19use embedded_hal_bus::spi::ExclusiveDevice;
20use rand::RngCore;
21use static_cell::make_static;
22use {defmt_rtt as _, panic_probe as _};
23
24#[embassy_executor::task]
25async fn ethernet_task(
26 runner: Runner<
27 'static,
28 W5100S,
29 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
30 Input<'static, PIN_21>,
31 Output<'static, PIN_20>,
32 >,
33) -> ! {
34 runner.run().await
35}
36
37#[embassy_executor::task]
38async fn net_task(stack: &'static Stack<Device<'static>>) -> ! {
39 stack.run().await
40}
41
42#[embassy_executor::main]
43async fn main(spawner: Spawner) {
44 let p = embassy_rp::init(Default::default());
45 let mut rng = RoscRng;
46
47 let mut spi_cfg = SpiConfig::default();
48 spi_cfg.frequency = 50_000_000;
49 let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18);
50 let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg);
51 let cs = Output::new(p.PIN_17, Level::High);
52 let w5500_int = Input::new(p.PIN_21, Pull::Up);
53 let w5500_reset = Output::new(p.PIN_20, Level::High);
54
55 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
56 let state = make_static!(State::<8, 8>::new());
57 let (device, runner) = embassy_net_wiznet::new(
58 mac_addr,
59 state,
60 ExclusiveDevice::new(spi, cs, Delay),
61 w5500_int,
62 w5500_reset,
63 )
64 .await;
65 unwrap!(spawner.spawn(ethernet_task(runner)));
66
67 // Generate random seed
68 let seed = rng.next_u64();
69
70 // Init network stack
71 let stack = &*make_static!(Stack::new(
72 device,
73 embassy_net::Config::dhcpv4(Default::default()),
74 make_static!(StackResources::<2>::new()),
75 seed
76 ));
77
78 // Launch network task
79 unwrap!(spawner.spawn(net_task(&stack)));
80
81 info!("Waiting for DHCP up...");
82 while stack.config_v4().is_none() {
83 Timer::after(Duration::from_millis(100)).await;
84 }
85 info!("IP addressing up!");
86
87 let down = test_download(stack).await;
88 let up = test_upload(stack).await;
89 let updown = test_upload_download(stack).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
95 info!("Test OK");
96 cortex_m::asm::bkpt();
97}
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/flash.rs b/tests/rp/src/bin/flash.rs
index c31d6decf..75be2bf06 100644
--- a/tests/rp/src/bin/flash.rs
+++ b/tests/rp/src/bin/flash.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use defmt::*; 6use defmt::*;
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
@@ -26,23 +25,23 @@ async fn main(_spawner: Spawner) {
26 let mut flash = embassy_rp::flash::Flash::<_, Async, { 2 * 1024 * 1024 }>::new(p.FLASH, p.DMA_CH0); 25 let mut flash = embassy_rp::flash::Flash::<_, Async, { 2 * 1024 * 1024 }>::new(p.FLASH, p.DMA_CH0);
27 26
28 // Get JEDEC id 27 // Get JEDEC id
29 let jedec = defmt::unwrap!(flash.jedec_id()); 28 let jedec = defmt::unwrap!(flash.blocking_jedec_id());
30 info!("jedec id: 0x{:x}", jedec); 29 info!("jedec id: 0x{:x}", jedec);
31 30
32 // Get unique id 31 // Get unique id
33 let mut uid = [0; 8]; 32 let mut uid = [0; 8];
34 defmt::unwrap!(flash.unique_id(&mut uid)); 33 defmt::unwrap!(flash.blocking_unique_id(&mut uid));
35 info!("unique id: {:?}", uid); 34 info!("unique id: {:?}", uid);
36 35
37 let mut buf = [0u8; ERASE_SIZE]; 36 let mut buf = [0u8; ERASE_SIZE];
38 defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf)); 37 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET, &mut buf));
39 38
40 info!("Addr of flash block is {:x}", ADDR_OFFSET + FLASH_BASE as u32); 39 info!("Addr of flash block is {:x}", ADDR_OFFSET + FLASH_BASE as u32);
41 info!("Contents start with {=[u8]}", buf[0..4]); 40 info!("Contents start with {=[u8]}", buf[0..4]);
42 41
43 defmt::unwrap!(flash.erase(ADDR_OFFSET, ADDR_OFFSET + ERASE_SIZE as u32)); 42 defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET, ADDR_OFFSET + ERASE_SIZE as u32));
44 43
45 defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf)); 44 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET, &mut buf));
46 info!("Contents after erase starts with {=[u8]}", buf[0..4]); 45 info!("Contents after erase starts with {=[u8]}", buf[0..4]);
47 if buf.iter().any(|x| *x != 0xFF) { 46 if buf.iter().any(|x| *x != 0xFF) {
48 defmt::panic!("unexpected"); 47 defmt::panic!("unexpected");
@@ -52,9 +51,9 @@ async fn main(_spawner: Spawner) {
52 *b = 0xDA; 51 *b = 0xDA;
53 } 52 }
54 53
55 defmt::unwrap!(flash.write(ADDR_OFFSET, &mut buf)); 54 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET, &mut buf));
56 55
57 defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf)); 56 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET, &mut buf));
58 info!("Contents after write starts with {=[u8]}", buf[0..4]); 57 info!("Contents after write starts with {=[u8]}", buf[0..4]);
59 if buf.iter().any(|x| *x != 0xDA) { 58 if buf.iter().any(|x| *x != 0xDA) {
60 defmt::panic!("unexpected"); 59 defmt::panic!("unexpected");
diff --git a/tests/rp/src/bin/float.rs b/tests/rp/src/bin/float.rs
index 0e0de85fa..2874aa910 100644
--- a/tests/rp/src/bin/float.rs
+++ b/tests/rp/src/bin/float.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use defmt::*; 6use defmt::*;
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/gpio.rs b/tests/rp/src/bin/gpio.rs
index 946b7dc88..1a43a9283 100644
--- a/tests/rp/src/bin/gpio.rs
+++ b/tests/rp/src/bin/gpio.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use defmt::{assert, *}; 6use defmt::{assert, *};
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/gpio_async.rs b/tests/rp/src/bin/gpio_async.rs
index 532494de5..60c65b7a0 100644
--- a/tests/rp/src/bin/gpio_async.rs
+++ b/tests/rp/src/bin/gpio_async.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use defmt::{assert, *}; 6use defmt::{assert, *};
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/gpio_multicore.rs b/tests/rp/src/bin/gpio_multicore.rs
index 780112bc1..6ab7f6717 100644
--- a/tests/rp/src/bin/gpio_multicore.rs
+++ b/tests/rp/src/bin/gpio_multicore.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use defmt::{info, unwrap}; 6use defmt::{info, unwrap};
8use embassy_executor::Executor; 7use embassy_executor::Executor;
@@ -38,11 +37,11 @@ async fn core0_task(p: PIN_0) {
38 let mut pin = Output::new(p, Level::Low); 37 let mut pin = Output::new(p, Level::Low);
39 38
40 CHANNEL0.send(()).await; 39 CHANNEL0.send(()).await;
41 CHANNEL1.recv().await; 40 CHANNEL1.receive().await;
42 41
43 pin.set_high(); 42 pin.set_high();
44 43
45 CHANNEL1.recv().await; 44 CHANNEL1.receive().await;
46 45
47 info!("Test OK"); 46 info!("Test OK");
48 cortex_m::asm::bkpt(); 47 cortex_m::asm::bkpt();
@@ -52,7 +51,7 @@ async fn core0_task(p: PIN_0) {
52async fn core1_task(p: PIN_1) { 51async fn core1_task(p: PIN_1) {
53 info!("CORE1 is running"); 52 info!("CORE1 is running");
54 53
55 CHANNEL0.recv().await; 54 CHANNEL0.receive().await;
56 55
57 let mut pin = Input::new(p, Pull::Down); 56 let mut pin = Input::new(p, Pull::Down);
58 let wait = pin.wait_for_rising_edge(); 57 let wait = pin.wait_for_rising_edge();
diff --git a/tests/rp/src/bin/multicore.rs b/tests/rp/src/bin/multicore.rs
index 114889dec..f4188135e 100644
--- a/tests/rp/src/bin/multicore.rs
+++ b/tests/rp/src/bin/multicore.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use defmt::{info, unwrap}; 6use defmt::{info, unwrap};
8use embassy_executor::Executor; 7use embassy_executor::Executor;
@@ -34,7 +33,7 @@ async fn core0_task() {
34 info!("CORE0 is running"); 33 info!("CORE0 is running");
35 let ping = true; 34 let ping = true;
36 CHANNEL0.send(ping).await; 35 CHANNEL0.send(ping).await;
37 let pong = CHANNEL1.recv().await; 36 let pong = CHANNEL1.receive().await;
38 assert_eq!(ping, pong); 37 assert_eq!(ping, pong);
39 38
40 info!("Test OK"); 39 info!("Test OK");
@@ -44,6 +43,6 @@ async fn core0_task() {
44#[embassy_executor::task] 43#[embassy_executor::task]
45async fn core1_task() { 44async fn core1_task() {
46 info!("CORE1 is running"); 45 info!("CORE1 is running");
47 let ping = CHANNEL0.recv().await; 46 let ping = CHANNEL0.receive().await;
48 CHANNEL1.send(ping).await; 47 CHANNEL1.send(ping).await;
49} 48}
diff --git a/tests/rp/src/bin/pio_irq.rs b/tests/rp/src/bin/pio_irq.rs
index bdea63eaa..c71e55d91 100644
--- a/tests/rp/src/bin/pio_irq.rs
+++ b/tests/rp/src/bin/pio_irq.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use defmt::info; 6use defmt::info;
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/pio_multi_load.rs b/tests/rp/src/bin/pio_multi_load.rs
index 356f16795..6343ff3a9 100644
--- a/tests/rp/src/bin/pio_multi_load.rs
+++ b/tests/rp/src/bin/pio_multi_load.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use defmt::info; 6use defmt::info;
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/pwm.rs b/tests/rp/src/bin/pwm.rs
index c71d21ef9..8c02b8441 100644
--- a/tests/rp/src/bin/pwm.rs
+++ b/tests/rp/src/bin/pwm.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use defmt::{assert, assert_eq, assert_ne, *}; 6use defmt::{assert, assert_eq, assert_ne, *};
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/spi.rs b/tests/rp/src/bin/spi.rs
index 84dfa5a2c..f347b80ca 100644
--- a/tests/rp/src/bin/spi.rs
+++ b/tests/rp/src/bin/spi.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use defmt::{assert_eq, *}; 6use defmt::{assert_eq, *};
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/spi_async.rs b/tests/rp/src/bin/spi_async.rs
index a4080b03d..80d5a7147 100644
--- a/tests/rp/src/bin/spi_async.rs
+++ b/tests/rp/src/bin/spi_async.rs
@@ -4,8 +4,7 @@
4#![no_std] 4#![no_std]
5#![no_main] 5#![no_main]
6#![feature(type_alias_impl_trait)] 6#![feature(type_alias_impl_trait)]
7#[path = "../common.rs"] 7teleprobe_meta::target!(b"rpi-pico");
8mod common;
9 8
10use defmt::{assert_eq, *}; 9use defmt::{assert_eq, *};
11use embassy_executor::Spawner; 10use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/uart.rs b/tests/rp/src/bin/uart.rs
index 2331c7d36..00f3e1949 100644
--- a/tests/rp/src/bin/uart.rs
+++ b/tests/rp/src/bin/uart.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use defmt::{assert_eq, *}; 6use defmt::{assert_eq, *};
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs
index edabf55b7..6ab7de29e 100644
--- a/tests/rp/src/bin/uart_buffered.rs
+++ b/tests/rp/src/bin/uart_buffered.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use defmt::{assert_eq, panic, *}; 6use defmt::{assert_eq, panic, *};
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/uart_dma.rs b/tests/rp/src/bin/uart_dma.rs
index fee6c825d..cd4af1ef2 100644
--- a/tests/rp/src/bin/uart_dma.rs
+++ b/tests/rp/src/bin/uart_dma.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use defmt::{assert_eq, *}; 6use defmt::{assert_eq, *};
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/tests/rp/src/bin/uart_upgrade.rs b/tests/rp/src/bin/uart_upgrade.rs
index effd0bc49..c07fc08cd 100644
--- a/tests/rp/src/bin/uart_upgrade.rs
+++ b/tests/rp/src/bin/uart_upgrade.rs
@@ -1,8 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4#[path = "../common.rs"] 4teleprobe_meta::target!(b"rpi-pico");
5mod common;
6 5
7use defmt::{assert_eq, *}; 6use defmt::{assert_eq, *};
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/tests/rp/src/common.rs b/tests/rp/src/common.rs
deleted file mode 100644
index 955674f27..000000000
--- a/tests/rp/src/common.rs
+++ /dev/null
@@ -1 +0,0 @@
1teleprobe_meta::target!(b"rpi-pico");
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 17320649e..e26388976 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -41,8 +41,8 @@ defmt-rtt = "0.4"
41cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 41cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
42cortex-m-rt = "0.7.0" 42cortex-m-rt = "0.7.0"
43embedded-hal = "0.2.6" 43embedded-hal = "0.2.6"
44embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" } 44embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
45embedded-hal-async = { version = "=0.2.0-alpha.2" } 45embedded-hal-async = { version = "=1.0.0-rc.1" }
46micromath = "2.0.0" 46micromath = "2.0.0"
47panic-probe = { version = "0.3.0", features = ["print-defmt"] } 47panic-probe = { version = "0.3.0", features = ["print-defmt"] }
48rand_core = { version = "0.6", default-features = false } 48rand_core = { version = "0.6", default-features = false }
diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs
index 8737ca8ee..acf545216 100644
--- a/tests/stm32/src/bin/can.rs
+++ b/tests/stm32/src/bin/can.rs
@@ -80,8 +80,8 @@ async fn main(_spawner: Spawner) {
80 const MIN_LATENCY: Duration = Duration::from_micros(50); 80 const MIN_LATENCY: Duration = Duration::from_micros(50);
81 const MAX_LATENCY: Duration = Duration::from_micros(150); 81 const MAX_LATENCY: Duration = Duration::from_micros(150);
82 assert!( 82 assert!(
83 MIN_LATENCY < latency && latency < MAX_LATENCY, 83 MIN_LATENCY <= latency && latency <= MAX_LATENCY,
84 "{} < {} < {}", 84 "{} <= {} <= {}",
85 MIN_LATENCY, 85 MIN_LATENCY,
86 latency, 86 latency,
87 MAX_LATENCY 87 MAX_LATENCY