aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xci.sh5
-rw-r--r--docs/modules/ROOT/pages/basic_application.adoc23
-rw-r--r--docs/modules/ROOT/pages/bootloader.adoc1
-rw-r--r--docs/modules/ROOT/pages/layer_by_layer.adoc8
-rw-r--r--docs/modules/ROOT/pages/stm32.adoc4
-rw-r--r--embassy-boot/boot/Cargo.toml14
-rw-r--r--embassy-boot/boot/README.md (renamed from embassy-boot/README.md)0
-rw-r--r--embassy-boot/boot/src/lib.rs2
-rw-r--r--embassy-boot/nrf/README.md26
-rw-r--r--embassy-boot/nrf/src/lib.rs2
-rw-r--r--embassy-boot/rp/Cargo.toml71
-rw-r--r--embassy-boot/rp/README.md26
-rw-r--r--embassy-boot/rp/build.rs8
-rw-r--r--embassy-boot/rp/src/fmt.rs225
-rw-r--r--embassy-boot/rp/src/lib.rs90
-rw-r--r--embassy-boot/stm32/Cargo.toml2
-rw-r--r--embassy-boot/stm32/README.md27
-rw-r--r--embassy-boot/stm32/src/lib.rs2
-rw-r--r--embassy-embedded-hal/Cargo.toml2
-rw-r--r--embassy-embedded-hal/src/adapter.rs79
-rw-r--r--embassy-embedded-hal/src/lib.rs6
-rw-r--r--embassy-embedded-hal/src/shared_bus/asynch/i2c.rs107
-rw-r--r--embassy-embedded-hal/src/shared_bus/asynch/spi.rs70
-rw-r--r--embassy-executor/Cargo.toml17
-rw-r--r--embassy-executor/src/lib.rs10
-rw-r--r--embassy-hal-common/src/atomic_ring_buffer.rs331
-rw-r--r--embassy-hal-common/src/lib.rs1
-rw-r--r--embassy-lora/Cargo.toml2
-rw-r--r--embassy-lora/src/sx126x/mod.rs6
-rw-r--r--embassy-macros/Cargo.toml10
-rw-r--r--embassy-macros/README.md21
-rw-r--r--embassy-macros/src/lib.rs128
-rw-r--r--embassy-macros/src/macros/main.rs87
-rw-r--r--embassy-net/Cargo.toml6
-rw-r--r--embassy-net/src/device.rs14
-rw-r--r--embassy-net/src/lib.rs6
-rw-r--r--embassy-net/src/stack.rs53
-rw-r--r--embassy-net/src/tcp.rs182
-rw-r--r--embassy-net/src/udp.rs41
-rw-r--r--embassy-nrf/Cargo.toml4
-rw-r--r--embassy-nrf/src/buffered_uarte.rs66
-rw-r--r--embassy-nrf/src/chips/nrf52805.rs4
-rw-r--r--embassy-nrf/src/chips/nrf52810.rs4
-rw-r--r--embassy-nrf/src/chips/nrf52811.rs5
-rw-r--r--embassy-nrf/src/chips/nrf52820.rs6
-rw-r--r--embassy-nrf/src/chips/nrf52832.rs14
-rw-r--r--embassy-nrf/src/chips/nrf52833.rs14
-rw-r--r--embassy-nrf/src/chips/nrf52840.rs14
-rw-r--r--embassy-nrf/src/chips/nrf5340_app.rs10
-rw-r--r--embassy-nrf/src/chips/nrf5340_net.rs2
-rw-r--r--embassy-nrf/src/chips/nrf9160.rs10
-rw-r--r--embassy-nrf/src/gpiote.rs75
-rw-r--r--embassy-nrf/src/i2s.rs1141
-rw-r--r--embassy-nrf/src/lib.rs17
-rw-r--r--embassy-nrf/src/spim.rs31
-rw-r--r--embassy-nrf/src/spis.rs539
-rw-r--r--embassy-nrf/src/twim.rs28
-rw-r--r--embassy-nrf/src/twis.rs759
-rw-r--r--embassy-nrf/src/uarte.rs26
-rw-r--r--embassy-nrf/src/usb.rs381
-rw-r--r--embassy-rp/Cargo.toml7
-rw-r--r--embassy-rp/src/adc.rs173
-rw-r--r--embassy-rp/src/clocks.rs39
-rw-r--r--embassy-rp/src/flash.rs5
-rw-r--r--embassy-rp/src/gpio.rs95
-rw-r--r--embassy-rp/src/i2c.rs75
-rw-r--r--embassy-rp/src/lib.rs8
-rw-r--r--embassy-rp/src/rtc/mod.rs2
-rw-r--r--embassy-rp/src/spi.rs32
-rw-r--r--embassy-rp/src/uart/buffered.rs696
-rw-r--r--embassy-rp/src/uart/mod.rs91
-rw-r--r--embassy-rp/src/usb.rs513
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/src/adc/v3.rs4
-rw-r--r--embassy-stm32/src/dma/bdma.rs7
-rw-r--r--embassy-stm32/src/dma/dma.rs7
-rw-r--r--embassy-stm32/src/dma/mod.rs8
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs18
-rw-r--r--embassy-stm32/src/exti.rs36
-rw-r--r--embassy-stm32/src/flash/h7.rs17
-rw-r--r--embassy-stm32/src/i2c/v2.rs34
-rw-r--r--embassy-stm32/src/lib.rs23
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs34
-rw-r--r--embassy-stm32/src/spi/mod.rs44
-rw-r--r--embassy-stm32/src/usart/buffered.rs69
-rw-r--r--embassy-stm32/src/usb/usb.rs582
-rw-r--r--embassy-stm32/src/wdg/mod.rs8
-rw-r--r--embassy-sync/Cargo.toml2
-rw-r--r--embassy-sync/src/lib.rs3
-rw-r--r--embassy-sync/src/pipe.rs74
-rw-r--r--embassy-sync/src/signal.rs9
-rw-r--r--embassy-sync/src/waitqueue/waker.rs2
-rw-r--r--embassy-time/Cargo.toml2
-rw-r--r--embassy-time/src/delay.rs16
-rw-r--r--embassy-time/src/lib.rs3
-rw-r--r--embassy-usb-driver/src/lib.rs73
-rw-r--r--embassy-usb-logger/Cargo.toml13
-rw-r--r--embassy-usb-logger/README.md15
-rw-r--r--embassy-usb-logger/src/lib.rs146
-rw-r--r--embassy-usb/src/class/hid.rs2
-rw-r--r--examples/boot/application/nrf/Cargo.toml2
-rw-r--r--examples/boot/application/rp/.cargo/config.toml12
-rw-r--r--examples/boot/application/rp/Cargo.toml33
-rw-r--r--examples/boot/application/rp/README.md28
-rw-r--r--examples/boot/application/rp/build.rs35
-rw-r--r--examples/boot/application/rp/memory.x15
-rw-r--r--examples/boot/application/rp/src/bin/a.rs52
-rw-r--r--examples/boot/application/rp/src/bin/b.rs23
-rw-r--r--examples/boot/application/stm32f3/Cargo.toml2
-rw-r--r--examples/boot/application/stm32f7/Cargo.toml2
-rw-r--r--examples/boot/application/stm32h7/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l0/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l1/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l4/Cargo.toml2
-rw-r--r--examples/boot/application/stm32wl/Cargo.toml2
-rw-r--r--examples/boot/bootloader/nrf/Cargo.toml2
-rw-r--r--examples/boot/bootloader/rp/.cargo/config.toml8
-rw-r--r--examples/boot/bootloader/rp/Cargo.toml29
-rw-r--r--examples/boot/bootloader/rp/README.md17
-rw-r--r--examples/boot/bootloader/rp/build.rs28
-rw-r--r--examples/boot/bootloader/rp/memory.x19
-rw-r--r--examples/boot/bootloader/rp/src/main.rs51
-rw-r--r--examples/boot/bootloader/stm32/Cargo.toml2
-rw-r--r--examples/nrf/Cargo.toml6
-rw-r--r--examples/nrf/src/bin/i2s_effect.rs117
-rw-r--r--examples/nrf/src/bin/i2s_monitor.rs115
-rw-r--r--examples/nrf/src/bin/i2s_waveform.rs151
-rw-r--r--examples/nrf/src/bin/spis.rs27
-rw-r--r--examples/nrf/src/bin/twis.rs46
-rw-r--r--examples/rp/Cargo.toml8
-rw-r--r--examples/rp/src/bin/adc.rs33
-rw-r--r--examples/rp/src/bin/usb_logger.rs30
-rw-r--r--examples/std/Cargo.toml2
-rw-r--r--examples/stm32f0/.cargo/config.toml2
-rw-r--r--examples/stm32f0/Cargo.toml4
-rw-r--r--examples/stm32f0/src/bin/blinky.rs28
-rw-r--r--examples/stm32f1/Cargo.toml2
-rw-r--r--examples/stm32f2/Cargo.toml2
-rw-r--r--examples/stm32f3/Cargo.toml2
-rw-r--r--examples/stm32f4/Cargo.toml4
-rw-r--r--examples/stm32f7/Cargo.toml4
-rw-r--r--examples/stm32g0/Cargo.toml2
-rw-r--r--examples/stm32g4/Cargo.toml2
-rw-r--r--examples/stm32h7/Cargo.toml8
-rw-r--r--examples/stm32h7/src/bin/wdg.rs24
-rw-r--r--examples/stm32l0/Cargo.toml4
-rw-r--r--examples/stm32l1/Cargo.toml2
-rw-r--r--examples/stm32l4/Cargo.toml4
-rw-r--r--examples/stm32l5/Cargo.toml4
-rw-r--r--examples/stm32u5/Cargo.toml7
-rw-r--r--examples/stm32wb/Cargo.toml2
-rw-r--r--examples/stm32wl/Cargo.toml2
-rw-r--r--rust-toolchain.toml2
-rw-r--r--tests/rp/Cargo.toml6
-rw-r--r--tests/rp/src/bin/gpio.rs28
-rw-r--r--tests/rp/src/bin/uart_buffered.rs13
-rw-r--r--tests/stm32/Cargo.toml4
157 files changed, 6699 insertions, 2224 deletions
diff --git a/ci.sh b/ci.sh
index cd1c0786c..9f79c87b9 100755
--- a/ci.sh
+++ b/ci.sh
@@ -36,6 +36,8 @@ cargo batch \
36 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \ 36 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \
37 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \ 37 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \
38 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ 38 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
39 --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
40 --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \
39 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,pool-16 \ 41 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,pool-16 \
40 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,pool-16,unstable-traits \ 42 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,pool-16,unstable-traits \
41 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,pool-16,nightly \ 43 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,pool-16,nightly \
@@ -79,6 +81,7 @@ cargo batch \
79 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f103re,defmt,exti,time-driver-any,unstable-traits \ 81 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f103re,defmt,exti,time-driver-any,unstable-traits \
80 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f100c4,defmt,exti,time-driver-any,unstable-traits \ 82 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f100c4,defmt,exti,time-driver-any,unstable-traits \
81 --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ 83 --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
84 --- build --release --manifest-path embassy-boot/rp/Cargo.toml --target thumbv6m-none-eabi \
82 --- build --release --manifest-path embassy-boot/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ 85 --- build --release --manifest-path embassy-boot/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
83 --- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \ 86 --- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \
84 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \ 87 --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \
@@ -104,6 +107,7 @@ cargo batch \
104 --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \ 107 --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \
105 --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \ 108 --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \
106 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/nrf --bin b \ 109 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/nrf --bin b \
110 --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/boot/rp --bin b \
107 --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32f3 --bin b \ 111 --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32f3 --bin b \
108 --- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32f7 --bin b \ 112 --- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32f7 --bin b \
109 --- build --release --manifest-path examples/boot/application/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32h7 --bin b \ 113 --- build --release --manifest-path examples/boot/application/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32h7 --bin b \
@@ -112,6 +116,7 @@ cargo batch \
112 --- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32l4 --bin b \ 116 --- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32l4 --bin b \
113 --- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/boot/stm32wl --bin b \ 117 --- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/boot/stm32wl --bin b \
114 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ 118 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
119 --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \
115 --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ 120 --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
116 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \ 121 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \
117 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/bluepill-stm32f103c8 \ 122 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/bluepill-stm32f103c8 \
diff --git a/docs/modules/ROOT/pages/basic_application.adoc b/docs/modules/ROOT/pages/basic_application.adoc
index 4dc4a6359..3f4f16e28 100644
--- a/docs/modules/ROOT/pages/basic_application.adoc
+++ b/docs/modules/ROOT/pages/basic_application.adoc
@@ -21,7 +21,7 @@ Then, what follows are some declarations on how to deal with panics and faults.
21 21
22[source,rust] 22[source,rust]
23---- 23----
24include::example$basic/src/main.rs[lines="11..12"] 24include::example$basic/src/main.rs[lines="10"]
25---- 25----
26 26
27=== Task declaration 27=== Task declaration
@@ -30,7 +30,7 @@ After a bit of import declaration, the tasks run by the application should be de
30 30
31[source,rust] 31[source,rust]
32---- 32----
33include::example$basic/src/main.rs[lines="13..22"] 33include::example$basic/src/main.rs[lines="12..20"]
34---- 34----
35 35
36An embassy task must be declared `async`, and may NOT take generic arguments. In this case, we are handed the LED that should be blinked and the interval of the blinking. 36An embassy task must be declared `async`, and may NOT take generic arguments. In this case, we are handed the LED that should be blinked and the interval of the blinking.
@@ -45,23 +45,10 @@ The `Spawner` is the way the main application spawns other tasks. The `Periphera
45 45
46[source,rust] 46[source,rust]
47---- 47----
48include::example$basic/src/main.rs[lines="23..-1"] 48include::example$basic/src/main.rs[lines="22..-1"]
49---- 49----
50 50
51`#[embassy_executor::main]` takes an optional `config` parameter specifying a function that returns an instance of HAL's `Config` struct. For example: 51What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy::main]` macro. The macro does the following:
52
53```rust
54fn embassy_config() -> embassy_nrf::config::Config {
55 embassy_nrf::config::Config::default()
56}
57
58#[embassy_executor::main(config = "embassy_config()")]
59async fn main(_spawner: Spawner, p: embassy_nrf::Peripherals) {
60 // ...
61}
62```
63
64What happens when the `blinker` task have been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy::main]` macro. The macro does the following:
65 52
66. Creates an Embassy Executor 53. Creates an Embassy Executor
67. Initializes the microcontroller HAL to get the `Peripherals` 54. Initializes the microcontroller HAL to get the `Peripherals`
@@ -76,7 +63,7 @@ The project definition needs to contain the embassy dependencies:
76 63
77[source,toml] 64[source,toml]
78---- 65----
79include::example$basic/Cargo.toml[lines="8..9"] 66include::example$basic/Cargo.toml[lines="9..11"]
80---- 67----
81 68
82Depending on your microcontroller, you may need to replace `embassy-nrf` with something else (`embassy-stm32` for STM32. Remember to update feature flags as well). 69Depending on your microcontroller, you may need to replace `embassy-nrf` with something else (`embassy-stm32` for STM32. Remember to update feature flags as well).
diff --git a/docs/modules/ROOT/pages/bootloader.adoc b/docs/modules/ROOT/pages/bootloader.adoc
index 7dbfeb3eb..b50de5abd 100644
--- a/docs/modules/ROOT/pages/bootloader.adoc
+++ b/docs/modules/ROOT/pages/bootloader.adoc
@@ -15,6 +15,7 @@ The bootloader supports
15 15
16* nRF52 with and without softdevice 16* nRF52 with and without softdevice
17* STM32 L4, WB, WL, L1, L0, F3, F7 and H7 17* STM32 L4, WB, WL, L1, L0, F3, F7 and H7
18* Raspberry Pi: RP2040
18 19
19In general, the bootloader works on any platform that implements the `embedded-storage` traits for its internal flash, but may require custom initialization code to work. 20In general, the bootloader works on any platform that implements the `embedded-storage` traits for its internal flash, but may require custom initialization code to work.
20 21
diff --git a/docs/modules/ROOT/pages/layer_by_layer.adoc b/docs/modules/ROOT/pages/layer_by_layer.adoc
index a96dd9fe2..a78a64a97 100644
--- a/docs/modules/ROOT/pages/layer_by_layer.adoc
+++ b/docs/modules/ROOT/pages/layer_by_layer.adoc
@@ -8,7 +8,7 @@ The application we'll write is a simple 'push button, blink led' application, wh
8 8
9== PAC version 9== PAC version
10 10
11The PAC is the lowest API for accessing peripherals and registers, if you don't count reading/writing directly to memory addresses. It provide distinct types 11The PAC is the lowest API for accessing peripherals and registers, if you don't count reading/writing directly to memory addresses. It provides distinct types
12to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code. 12to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code.
13 13
14Writing an application using the PAC directly is therefore not recommended, but if the functionality you want to use is not exposed in the upper layers, that's what you need to use. 14Writing an application using the PAC directly is therefore not recommended, but if the functionality you want to use is not exposed in the upper layers, that's what you need to use.
@@ -20,13 +20,13 @@ The blinky app using PAC is shown below:
20include::example$layer-by-layer/blinky-pac/src/main.rs[] 20include::example$layer-by-layer/blinky-pac/src/main.rs[]
21---- 21----
22 22
23As you can see, there are a lot of code needed to enable the peripheral clocks, configuring the input pins and the output pins of the application. 23As you can see, a lot of code is needed to enable the peripheral clocks and to configure the input pins and the output pins of the application.
24 24
25Another downside of this application is that it is busy-looping while polling the button state. This prevents the microcontroller from utilizing any sleep mode to save power. 25Another downside of this application is that it is busy-looping while polling the button state. This prevents the microcontroller from utilizing any sleep mode to save power.
26 26
27== HAL version 27== HAL version
28 28
29To simplify our application, we can use the HAL instead. The HAL exposes higher level APIs that handle details such 29To simplify our application, we can use the HAL instead. The HAL exposes higher level APIs that handle details such as:
30 30
31* Automatically enabling the peripheral clock when you're using the peripheral 31* Automatically enabling the peripheral clock when you're using the peripheral
32* Deriving and applying register configuration from higher level types 32* Deriving and applying register configuration from higher level types
@@ -39,7 +39,7 @@ The HAL example is shown below:
39include::example$layer-by-layer/blinky-hal/src/main.rs[] 39include::example$layer-by-layer/blinky-hal/src/main.rs[]
40---- 40----
41 41
42As you can see, the application becomes a lot simpler, even without using any async code. The `Input` and `Output` hides all the details accessing the GPIO registers, and allow you to use a much simpler API to query the state of the button and toggle the LED output accordingly. 42As you can see, the application becomes a lot simpler, even without using any async code. The `Input` and `Output` types hide all the details of accessing the GPIO registers and allow you to use a much simpler API for querying the state of the button and toggling the LED output.
43 43
44The same downside from the PAC example still applies though: the application is busy looping and consuming more power than necessary. 44The same downside from the PAC example still applies though: the application is busy looping and consuming more power than necessary.
45 45
diff --git a/docs/modules/ROOT/pages/stm32.adoc b/docs/modules/ROOT/pages/stm32.adoc
index 8ed9ab04b..7bfc0592b 100644
--- a/docs/modules/ROOT/pages/stm32.adoc
+++ b/docs/modules/ROOT/pages/stm32.adoc
@@ -4,9 +4,9 @@ The link:https://github.com/embassy-rs/embassy/tree/master/embassy-stm32[Embassy
4 4
5== The infinite variant problem 5== The infinite variant problem
6 6
7STM32 microcontrollers comes in many families and flavors, and supporting all of them is a big undertaking. Embassy has taken advantage of the fact 7STM32 microcontrollers come in many families, and flavors and supporting all of them is a big undertaking. Embassy has taken advantage of the fact
8that the STM32 peripheral versions are shared across chip families. Instead of re-implementing the SPI 8that the STM32 peripheral versions are shared across chip families. Instead of re-implementing the SPI
9peripheral for every STM32 chip family, embassy have a single SPI implementation that depends on 9peripheral for every STM32 chip family, embassy has a single SPI implementation that depends on
10code-generated register types that are identical for STM32 families with the same version of a given peripheral. 10code-generated register types that are identical for STM32 families with the same version of a given peripheral.
11 11
12=== The metapac 12=== The metapac
diff --git a/embassy-boot/boot/Cargo.toml b/embassy-boot/boot/Cargo.toml
index 54c67a375..ae4efbd2e 100644
--- a/embassy-boot/boot/Cargo.toml
+++ b/embassy-boot/boot/Cargo.toml
@@ -1,14 +1,24 @@
1[package] 1[package]
2edition = "2021" 2edition = "2021"
3name = "embassy-boot" 3name = "embassy-boot"
4version = "0.1.0" 4version = "0.1.1"
5description = "Bootloader using Embassy" 5description = "A lightweight bootloader supporting firmware updates in a power-fail-safe way, with trial boots and rollbacks."
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7repository = "https://github.com/embassy-rs/embassy"
8categories = [
9 "embedded",
10 "no-std",
11 "asynchronous",
12]
7 13
8[package.metadata.embassy_docs] 14[package.metadata.embassy_docs]
9src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-v$VERSION/embassy-boot/boot/src/" 15src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-v$VERSION/embassy-boot/boot/src/"
10src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot/boot/src/" 16src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot/boot/src/"
11target = "thumbv7em-none-eabi" 17target = "thumbv7em-none-eabi"
18features = ["defmt"]
19
20[package.metadata.docs.rs]
21features = ["defmt"]
12 22
13[lib] 23[lib]
14 24
diff --git a/embassy-boot/README.md b/embassy-boot/boot/README.md
index 414405377..414405377 100644
--- a/embassy-boot/README.md
+++ b/embassy-boot/boot/README.md
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs
index 429323ec9..76b14bc8c 100644
--- a/embassy-boot/boot/src/lib.rs
+++ b/embassy-boot/boot/src/lib.rs
@@ -1,7 +1,7 @@
1#![feature(type_alias_impl_trait)] 1#![feature(type_alias_impl_trait)]
2#![no_std] 2#![no_std]
3#![warn(missing_docs)] 3#![warn(missing_docs)]
4#![doc = include_str!("../../README.md")] 4#![doc = include_str!("../README.md")]
5mod fmt; 5mod fmt;
6 6
7use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; 7use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
diff --git a/embassy-boot/nrf/README.md b/embassy-boot/nrf/README.md
new file mode 100644
index 000000000..02f35c0a6
--- /dev/null
+++ b/embassy-boot/nrf/README.md
@@ -0,0 +1,26 @@
1# embassy-boot-nrf
2
3An [Embassy](https://embassy.dev) project.
4
5An adaptation of `embassy-boot` for nRF.
6
7## Features
8
9* Load applications with our without the softdevice.
10* Configure bootloader partitions based on linker script.
11* Using watchdog timer to detect application failure.
12
13
14## Minimum supported Rust version (MSRV)
15
16`embassy-boot-nrf` requires Rust nightly to compile as it relies on async traits for interacting with the flash peripherals.
17
18## License
19
20This work is licensed under either of
21
22- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
23 <http://www.apache.org/licenses/LICENSE-2.0>)
24- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
25
26at your option.
diff --git a/embassy-boot/nrf/src/lib.rs b/embassy-boot/nrf/src/lib.rs
index 82475d1e2..205bbd6df 100644
--- a/embassy-boot/nrf/src/lib.rs
+++ b/embassy-boot/nrf/src/lib.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![feature(type_alias_impl_trait)] 2#![feature(type_alias_impl_trait)]
3#![warn(missing_docs)] 3#![warn(missing_docs)]
4#![doc = include_str!("../../README.md")] 4#![doc = include_str!("../README.md")]
5mod fmt; 5mod fmt;
6 6
7pub use embassy_boot::{AlignedBuffer, BootFlash, FirmwareUpdater, FlashConfig, Partition, SingleFlashConfig}; 7pub use embassy_boot::{AlignedBuffer, BootFlash, FirmwareUpdater, FlashConfig, Partition, SingleFlashConfig};
diff --git a/embassy-boot/rp/Cargo.toml b/embassy-boot/rp/Cargo.toml
new file mode 100644
index 000000000..93099b233
--- /dev/null
+++ b/embassy-boot/rp/Cargo.toml
@@ -0,0 +1,71 @@
1[package]
2edition = "2021"
3name = "embassy-boot-rp"
4version = "0.1.0"
5description = "Bootloader lib for RP2040 chips"
6license = "MIT OR Apache-2.0"
7
8[package.metadata.embassy_docs]
9src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-rp-v$VERSION/src/"
10src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot/rp/src/"
11target = "thumbv6m-none-eabi"
12
13[lib]
14
15[dependencies]
16defmt = { version = "0.3", optional = true }
17defmt-rtt = { version = "0.4", optional = true }
18log = { version = "0.4", optional = true }
19
20embassy-sync = { path = "../../embassy-sync" }
21embassy-rp = { path = "../../embassy-rp", default-features = false, features = ["nightly"] }
22embassy-boot = { path = "../boot", default-features = false }
23cortex-m = { version = "0.7.6" }
24cortex-m-rt = { version = "0.7" }
25embedded-storage = "0.3.0"
26embedded-storage-async = "0.3.0"
27cfg-if = "1.0.0"
28
29[features]
30defmt = [
31 "dep:defmt",
32 "embassy-boot/defmt",
33 "embassy-rp/defmt",
34]
35log = [
36 "dep:log",
37 "embassy-boot/log",
38 "embassy-rp/log",
39]
40debug = ["defmt-rtt"]
41
42[profile.dev]
43debug = 2
44debug-assertions = true
45incremental = false
46opt-level = 'z'
47overflow-checks = true
48
49[profile.release]
50codegen-units = 1
51debug = 2
52debug-assertions = false
53incremental = false
54lto = 'fat'
55opt-level = 'z'
56overflow-checks = false
57
58# do not optimize proc-macro crates = faster builds from scratch
59[profile.dev.build-override]
60codegen-units = 8
61debug = false
62debug-assertions = false
63opt-level = 0
64overflow-checks = false
65
66[profile.release.build-override]
67codegen-units = 8
68debug = false
69debug-assertions = false
70opt-level = 0
71overflow-checks = false
diff --git a/embassy-boot/rp/README.md b/embassy-boot/rp/README.md
new file mode 100644
index 000000000..c0c2d85fa
--- /dev/null
+++ b/embassy-boot/rp/README.md
@@ -0,0 +1,26 @@
1# embassy-boot-rp
2
3An [Embassy](https://embassy.dev) project.
4
5An adaptation of `embassy-boot` for RP2040.
6
7NOTE: The applications using this bootloader should not link with the `link-rp.x` linker script.
8
9## Features
10
11* Configure bootloader partitions based on linker script.
12* Load applications from active partition.
13
14## Minimum supported Rust version (MSRV)
15
16`embassy-boot-rp` requires Rust nightly to compile as it relies on async traits for interacting with the flash peripherals.
17
18## License
19
20This work is licensed under either of
21
22- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
23 <http://www.apache.org/licenses/LICENSE-2.0>)
24- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
25
26at your option.
diff --git a/embassy-boot/rp/build.rs b/embassy-boot/rp/build.rs
new file mode 100644
index 000000000..2cbc7ef5e
--- /dev/null
+++ b/embassy-boot/rp/build.rs
@@ -0,0 +1,8 @@
1use std::env;
2
3fn main() {
4 let target = env::var("TARGET").unwrap();
5 if target.starts_with("thumbv6m-") {
6 println!("cargo:rustc-cfg=armv6m");
7 }
8}
diff --git a/embassy-boot/rp/src/fmt.rs b/embassy-boot/rp/src/fmt.rs
new file mode 100644
index 000000000..066970813
--- /dev/null
+++ b/embassy-boot/rp/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-boot/rp/src/lib.rs b/embassy-boot/rp/src/lib.rs
new file mode 100644
index 000000000..85fc81827
--- /dev/null
+++ b/embassy-boot/rp/src/lib.rs
@@ -0,0 +1,90 @@
1#![no_std]
2#![feature(type_alias_impl_trait)]
3#![warn(missing_docs)]
4#![doc = include_str!("../README.md")]
5mod fmt;
6
7pub use embassy_boot::{AlignedBuffer, BootFlash, FirmwareUpdater, FlashConfig, Partition, SingleFlashConfig, State};
8use embassy_rp::flash::{ERASE_SIZE, WRITE_SIZE};
9
10/// A bootloader for RP2040 devices.
11pub struct BootLoader {
12 boot: embassy_boot::BootLoader,
13 magic: AlignedBuffer<WRITE_SIZE>,
14 page: AlignedBuffer<ERASE_SIZE>,
15}
16
17impl BootLoader {
18 /// Create a new bootloader instance using the supplied partitions for active, dfu and state.
19 pub fn new(active: Partition, dfu: Partition, state: Partition) -> Self {
20 Self {
21 boot: embassy_boot::BootLoader::new(active, dfu, state),
22 magic: AlignedBuffer([0; WRITE_SIZE]),
23 page: AlignedBuffer([0; ERASE_SIZE]),
24 }
25 }
26
27 /// Inspect the bootloader state and perform actions required before booting, such as swapping
28 /// firmware.
29 pub fn prepare<F: FlashConfig>(&mut self, flash: &mut F) -> usize {
30 match self.boot.prepare_boot(flash, self.magic.as_mut(), self.page.as_mut()) {
31 Ok(_) => embassy_rp::flash::FLASH_BASE + self.boot.boot_address(),
32 Err(_) => panic!("boot prepare error!"),
33 }
34 }
35
36 /// Boots the application.
37 ///
38 /// # Safety
39 ///
40 /// This modifies the stack pointer and reset vector and will run code placed in the active partition.
41 pub unsafe fn load(&mut self, start: usize) -> ! {
42 trace!("Loading app at 0x{:x}", start);
43 #[allow(unused_mut)]
44 let mut p = cortex_m::Peripherals::steal();
45 #[cfg(not(armv6m))]
46 p.SCB.invalidate_icache();
47 p.SCB.vtor.write(start as u32);
48
49 cortex_m::asm::bootload(start as *const u32)
50 }
51}
52
53impl Default for BootLoader {
54 /// Create a new bootloader instance using parameters from linker script
55 fn default() -> Self {
56 extern "C" {
57 static __bootloader_state_start: u32;
58 static __bootloader_state_end: u32;
59 static __bootloader_active_start: u32;
60 static __bootloader_active_end: u32;
61 static __bootloader_dfu_start: u32;
62 static __bootloader_dfu_end: u32;
63 }
64
65 let active = unsafe {
66 Partition::new(
67 &__bootloader_active_start as *const u32 as usize,
68 &__bootloader_active_end as *const u32 as usize,
69 )
70 };
71 let dfu = unsafe {
72 Partition::new(
73 &__bootloader_dfu_start as *const u32 as usize,
74 &__bootloader_dfu_end as *const u32 as usize,
75 )
76 };
77 let state = unsafe {
78 Partition::new(
79 &__bootloader_state_start as *const u32 as usize,
80 &__bootloader_state_end as *const u32 as usize,
81 )
82 };
83
84 trace!("ACTIVE: 0x{:x} - 0x{:x}", active.from, active.to);
85 trace!("DFU: 0x{:x} - 0x{:x}", dfu.from, dfu.to);
86 trace!("STATE: 0x{:x} - 0x{:x}", state.from, state.to);
87
88 Self::new(active, dfu, state)
89 }
90}
diff --git a/embassy-boot/stm32/Cargo.toml b/embassy-boot/stm32/Cargo.toml
index 9d12c6cfd..2fc169b32 100644
--- a/embassy-boot/stm32/Cargo.toml
+++ b/embassy-boot/stm32/Cargo.toml
@@ -15,7 +15,7 @@ target = "thumbv7em-none-eabi"
15 15
16[dependencies] 16[dependencies]
17defmt = { version = "0.3", optional = true } 17defmt = { version = "0.3", optional = true }
18defmt-rtt = { version = "0.3", optional = true } 18defmt-rtt = { version = "0.4", optional = true }
19log = { version = "0.4", optional = true } 19log = { version = "0.4", optional = true }
20 20
21embassy-sync = { path = "../../embassy-sync" } 21embassy-sync = { path = "../../embassy-sync" }
diff --git a/embassy-boot/stm32/README.md b/embassy-boot/stm32/README.md
index a82b730b9..cb134b534 100644
--- a/embassy-boot/stm32/README.md
+++ b/embassy-boot/stm32/README.md
@@ -1,11 +1,24 @@
1# Bootloader for STM32 1# embassy-boot-stm32
2 2
3The bootloader uses `embassy-boot` to interact with the flash. 3An [Embassy](https://embassy.dev) project.
4 4
5# Usage 5An adaptation of `embassy-boot` for STM32.
6 6
7Flash the bootloader 7## Features
8 8
9``` 9* Configure bootloader partitions based on linker script.
10cargo flash --features embassy-stm32/stm32wl55jc-cm4 --release --chip STM32WLE5JCIx 10* Load applications from active partition.
11``` 11
12## Minimum supported Rust version (MSRV)
13
14`embassy-boot-stm32` requires Rust nightly to compile as it relies on async traits for interacting with the flash peripherals.
15
16## License
17
18This work is licensed under either of
19
20- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
21 <http://www.apache.org/licenses/LICENSE-2.0>)
22- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
23
24at your option.
diff --git a/embassy-boot/stm32/src/lib.rs b/embassy-boot/stm32/src/lib.rs
index d549eccc6..82f712c4d 100644
--- a/embassy-boot/stm32/src/lib.rs
+++ b/embassy-boot/stm32/src/lib.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![feature(type_alias_impl_trait)] 2#![feature(type_alias_impl_trait)]
3#![warn(missing_docs)] 3#![warn(missing_docs)]
4#![doc = include_str!("../../README.md")] 4#![doc = include_str!("../README.md")]
5mod fmt; 5mod fmt;
6 6
7pub use embassy_boot::{AlignedBuffer, BootFlash, FirmwareUpdater, FlashConfig, Partition, SingleFlashConfig, State}; 7pub use embassy_boot::{AlignedBuffer, BootFlash, FirmwareUpdater, FlashConfig, Partition, SingleFlashConfig, State};
diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml
index 85ee856a6..fa74be8c4 100644
--- a/embassy-embedded-hal/Cargo.toml
+++ b/embassy-embedded-hal/Cargo.toml
@@ -20,7 +20,7 @@ nightly = ["embedded-hal-async", "embedded-storage-async"]
20embassy-sync = { version = "0.1.0", path = "../embassy-sync" } 20embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
21embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 21embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } 22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
23embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true } 23embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true }
24embedded-storage = "0.3.0" 24embedded-storage = "0.3.0"
25embedded-storage-async = { version = "0.3.0", optional = true } 25embedded-storage-async = { version = "0.3.0", optional = true }
26nb = "1.0.0" 26nb = "1.0.0"
diff --git a/embassy-embedded-hal/src/adapter.rs b/embassy-embedded-hal/src/adapter.rs
index 1c43f015f..3680984f1 100644
--- a/embassy-embedded-hal/src/adapter.rs
+++ b/embassy-embedded-hal/src/adapter.rs
@@ -38,32 +38,31 @@ where
38 E: embedded_hal_1::i2c::Error + 'static, 38 E: embedded_hal_1::i2c::Error + 'static,
39 T: blocking::i2c::WriteRead<Error = E> + blocking::i2c::Read<Error = E> + blocking::i2c::Write<Error = E>, 39 T: blocking::i2c::WriteRead<Error = E> + blocking::i2c::Read<Error = E> + blocking::i2c::Write<Error = E>,
40{ 40{
41 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 41 async fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Result<(), Self::Error> {
42 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 42 self.wrapped.read(address, buffer)
43 type WriteReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
44
45 fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
46 async move { self.wrapped.read(address, buffer) }
47 } 43 }
48 44
49 fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { 45 async fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Result<(), Self::Error> {
50 async move { self.wrapped.write(address, bytes) } 46 self.wrapped.write(address, bytes)
51 } 47 }
52 48
53 fn write_read<'a>(&'a mut self, address: u8, bytes: &'a [u8], buffer: &'a mut [u8]) -> Self::WriteReadFuture<'a> { 49 async fn write_read<'a>(
54 async move { self.wrapped.write_read(address, bytes, buffer) } 50 &'a mut self,
51 address: u8,
52 bytes: &'a [u8],
53 buffer: &'a mut [u8],
54 ) -> Result<(), Self::Error> {
55 self.wrapped.write_read(address, bytes, buffer)
55 } 56 }
56 57
57 type TransactionFuture<'a, 'b> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a, 'b: 'a; 58 async fn transaction<'a, 'b>(
58
59 fn transaction<'a, 'b>(
60 &'a mut self, 59 &'a mut self,
61 address: u8, 60 address: u8,
62 operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], 61 operations: &'a mut [embedded_hal_async::i2c::Operation<'b>],
63 ) -> Self::TransactionFuture<'a, 'b> { 62 ) -> Result<(), Self::Error> {
64 let _ = address; 63 let _ = address;
65 let _ = operations; 64 let _ = operations;
66 async move { todo!() } 65 todo!()
67 } 66 }
68} 67}
69 68
@@ -84,23 +83,17 @@ where
84 E: embedded_hal_1::spi::Error + 'static, 83 E: embedded_hal_1::spi::Error + 'static,
85 T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>, 84 T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
86{ 85{
87 type TransferFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 86 async fn transfer<'a>(&'a mut self, read: &'a mut [u8], write: &'a [u8]) -> Result<(), Self::Error> {
88 87 // Ensure we write the expected bytes
89 fn transfer<'a>(&'a mut self, read: &'a mut [u8], write: &'a [u8]) -> Self::TransferFuture<'a> { 88 for i in 0..core::cmp::min(read.len(), write.len()) {
90 async move { 89 read[i] = write[i].clone();
91 // Ensure we write the expected bytes
92 for i in 0..core::cmp::min(read.len(), write.len()) {
93 read[i] = write[i].clone();
94 }
95 self.wrapped.transfer(read)?;
96 Ok(())
97 } 90 }
91 self.wrapped.transfer(read)?;
92 Ok(())
98 } 93 }
99 94
100 type TransferInPlaceFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 95 async fn transfer_in_place<'a>(&'a mut self, _: &'a mut [u8]) -> Result<(), Self::Error> {
101 96 todo!()
102 fn transfer_in_place<'a>(&'a mut self, _: &'a mut [u8]) -> Self::TransferInPlaceFuture<'a> {
103 async move { todo!() }
104 } 97 }
105} 98}
106 99
@@ -109,10 +102,8 @@ where
109 E: embedded_hal_1::spi::Error + 'static, 102 E: embedded_hal_1::spi::Error + 'static,
110 T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>, 103 T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
111{ 104{
112 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 105 async fn flush(&mut self) -> Result<(), Self::Error> {
113 106 Ok(())
114 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
115 async move { Ok(()) }
116 } 107 }
117} 108}
118 109
@@ -121,13 +112,9 @@ where
121 E: embedded_hal_1::spi::Error + 'static, 112 E: embedded_hal_1::spi::Error + 'static,
122 T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>, 113 T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
123{ 114{
124 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 115 async fn write(&mut self, data: &[u8]) -> Result<(), Self::Error> {
125 116 self.wrapped.write(data)?;
126 fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> { 117 Ok(())
127 async move {
128 self.wrapped.write(data)?;
129 Ok(())
130 }
131 } 118 }
132} 119}
133 120
@@ -136,13 +123,9 @@ where
136 E: embedded_hal_1::spi::Error + 'static, 123 E: embedded_hal_1::spi::Error + 'static,
137 T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>, 124 T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
138{ 125{
139 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 126 async fn read(&mut self, data: &mut [u8]) -> Result<(), Self::Error> {
140 127 self.wrapped.transfer(data)?;
141 fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> { 128 Ok(())
142 async move {
143 self.wrapped.transfer(data)?;
144 Ok(())
145 }
146 } 129 }
147} 130}
148 131
@@ -192,7 +175,7 @@ where
192 } 175 }
193 176
194 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where T: 'a; 177 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where T: 'a;
195 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { 178 fn flush(&mut self) -> Result<(), Self::Error> {
196 async move { self.wrapped.bflush() } 179 async move { self.wrapped.bflush() }
197 } 180 }
198} 181}
diff --git a/embassy-embedded-hal/src/lib.rs b/embassy-embedded-hal/src/lib.rs
index a12a3a3a0..8da042228 100644
--- a/embassy-embedded-hal/src/lib.rs
+++ b/embassy-embedded-hal/src/lib.rs
@@ -1,5 +1,9 @@
1#![cfg_attr(not(feature = "std"), no_std)] 1#![cfg_attr(not(feature = "std"), no_std)]
2#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))] 2#![cfg_attr(
3 feature = "nightly",
4 feature(type_alias_impl_trait, async_fn_in_trait, impl_trait_projections)
5)]
6#![cfg_attr(feature = "nightly", allow(incomplete_features))]
3#![warn(missing_docs)] 7#![warn(missing_docs)]
4 8
5//! Utilities to use `embedded-hal` traits with Embassy. 9//! Utilities to use `embedded-hal` traits with Embassy.
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
index 0bc6afd98..c5e1fd415 100644
--- a/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
+++ b/embassy-embedded-hal/src/shared_bus/asynch/i2c.rs
@@ -22,7 +22,6 @@
22//! let i2c_dev2 = I2cDevice::new(i2c_bus); 22//! let i2c_dev2 = I2cDevice::new(i2c_bus);
23//! let mpu = Mpu6050::new(i2c_dev2); 23//! let mpu = Mpu6050::new(i2c_dev2);
24//! ``` 24//! ```
25use core::future::Future;
26 25
27use embassy_sync::blocking_mutex::raw::RawMutex; 26use embassy_sync::blocking_mutex::raw::RawMutex;
28use embassy_sync::mutex::Mutex; 27use embassy_sync::mutex::Mutex;
@@ -55,53 +54,39 @@ where
55 M: RawMutex + 'static, 54 M: RawMutex + 'static,
56 BUS: i2c::I2c + 'static, 55 BUS: i2c::I2c + 'static,
57{ 56{
58 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 57 async fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
59 58 let mut bus = self.bus.lock().await;
60 fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { 59 bus.read(address, buffer).await.map_err(I2cDeviceError::I2c)?;
61 async move { 60 Ok(())
62 let mut bus = self.bus.lock().await;
63 bus.read(address, buffer).await.map_err(I2cDeviceError::I2c)?;
64 Ok(())
65 }
66 } 61 }
67 62
68 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 63 async fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
69 64 let mut bus = self.bus.lock().await;
70 fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { 65 bus.write(address, bytes).await.map_err(I2cDeviceError::I2c)?;
71 async move { 66 Ok(())
72 let mut bus = self.bus.lock().await;
73 bus.write(address, bytes).await.map_err(I2cDeviceError::I2c)?;
74 Ok(())
75 }
76 } 67 }
77 68
78 type WriteReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 69 async fn write_read<'a>(
79
80 fn write_read<'a>(
81 &'a mut self, 70 &'a mut self,
82 address: u8, 71 address: u8,
83 wr_buffer: &'a [u8], 72 wr_buffer: &'a [u8],
84 rd_buffer: &'a mut [u8], 73 rd_buffer: &'a mut [u8],
85 ) -> Self::WriteReadFuture<'a> { 74 ) -> Result<(), I2cDeviceError<BUS::Error>> {
86 async move { 75 let mut bus = self.bus.lock().await;
87 let mut bus = self.bus.lock().await; 76 bus.write_read(address, wr_buffer, rd_buffer)
88 bus.write_read(address, wr_buffer, rd_buffer) 77 .await
89 .await 78 .map_err(I2cDeviceError::I2c)?;
90 .map_err(I2cDeviceError::I2c)?; 79 Ok(())
91 Ok(())
92 }
93 } 80 }
94 81
95 type TransactionFuture<'a, 'b> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a, 'b: 'a; 82 async fn transaction<'a, 'b>(
96
97 fn transaction<'a, 'b>(
98 &'a mut self, 83 &'a mut self,
99 address: u8, 84 address: u8,
100 operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], 85 operations: &'a mut [embedded_hal_async::i2c::Operation<'b>],
101 ) -> Self::TransactionFuture<'a, 'b> { 86 ) -> Result<(), I2cDeviceError<BUS::Error>> {
102 let _ = address; 87 let _ = address;
103 let _ = operations; 88 let _ = operations;
104 async move { todo!() } 89 todo!()
105 } 90 }
106} 91}
107 92
@@ -136,55 +121,41 @@ where
136 M: RawMutex + 'static, 121 M: RawMutex + 'static,
137 BUS: i2c::I2c + SetConfig + 'static, 122 BUS: i2c::I2c + SetConfig + 'static,
138{ 123{
139 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 124 async fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
140 125 let mut bus = self.bus.lock().await;
141 fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { 126 bus.set_config(&self.config);
142 async move { 127 bus.read(address, buffer).await.map_err(I2cDeviceError::I2c)?;
143 let mut bus = self.bus.lock().await; 128 Ok(())
144 bus.set_config(&self.config);
145 bus.read(address, buffer).await.map_err(I2cDeviceError::I2c)?;
146 Ok(())
147 }
148 } 129 }
149 130
150 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 131 async fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
151 132 let mut bus = self.bus.lock().await;
152 fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { 133 bus.set_config(&self.config);
153 async move { 134 bus.write(address, bytes).await.map_err(I2cDeviceError::I2c)?;
154 let mut bus = self.bus.lock().await; 135 Ok(())
155 bus.set_config(&self.config);
156 bus.write(address, bytes).await.map_err(I2cDeviceError::I2c)?;
157 Ok(())
158 }
159 } 136 }
160 137
161 type WriteReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 138 async fn write_read<'a>(
162
163 fn write_read<'a>(
164 &'a mut self, 139 &'a mut self,
165 address: u8, 140 address: u8,
166 wr_buffer: &'a [u8], 141 wr_buffer: &'a [u8],
167 rd_buffer: &'a mut [u8], 142 rd_buffer: &'a mut [u8],
168 ) -> Self::WriteReadFuture<'a> { 143 ) -> Result<(), I2cDeviceError<BUS::Error>> {
169 async move { 144 let mut bus = self.bus.lock().await;
170 let mut bus = self.bus.lock().await; 145 bus.set_config(&self.config);
171 bus.set_config(&self.config); 146 bus.write_read(address, wr_buffer, rd_buffer)
172 bus.write_read(address, wr_buffer, rd_buffer) 147 .await
173 .await 148 .map_err(I2cDeviceError::I2c)?;
174 .map_err(I2cDeviceError::I2c)?; 149 Ok(())
175 Ok(())
176 }
177 } 150 }
178 151
179 type TransactionFuture<'a, 'b> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a, 'b: 'a; 152 async fn transaction<'a, 'b>(
180
181 fn transaction<'a, 'b>(
182 &'a mut self, 153 &'a mut self,
183 address: u8, 154 address: u8,
184 operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], 155 operations: &'a mut [embedded_hal_async::i2c::Operation<'b>],
185 ) -> Self::TransactionFuture<'a, 'b> { 156 ) -> Result<(), I2cDeviceError<BUS::Error>> {
186 let _ = address; 157 let _ = address;
187 let _ = operations; 158 let _ = operations;
188 async move { todo!() } 159 todo!()
189 } 160 }
190} 161}
diff --git a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
index a3814d6d0..d25716655 100644
--- a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
+++ b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs
@@ -65,33 +65,25 @@ where
65{ 65{
66 type Bus = BUS; 66 type Bus = BUS;
67 67
68 type TransactionFuture<'a, R, F, Fut> = impl Future<Output = Result<R, Self::Error>> + 'a 68 async fn transaction<R, F, Fut>(&mut self, f: F) -> Result<R, Self::Error>
69 where 69 where
70 Self: 'a, R: 'a, F: FnOnce(*mut Self::Bus) -> Fut + 'a, 70 F: FnOnce(*mut Self::Bus) -> Fut,
71 Fut: Future<Output = Result<R, <Self::Bus as ErrorType>::Error>> + 'a; 71 Fut: Future<Output = Result<R, <Self::Bus as ErrorType>::Error>>,
72
73 fn transaction<'a, R, F, Fut>(&'a mut self, f: F) -> Self::TransactionFuture<'a, R, F, Fut>
74 where
75 R: 'a,
76 F: FnOnce(*mut Self::Bus) -> Fut + 'a,
77 Fut: Future<Output = Result<R, <Self::Bus as ErrorType>::Error>> + 'a,
78 { 72 {
79 async move { 73 let mut bus = self.bus.lock().await;
80 let mut bus = self.bus.lock().await; 74 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
81 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
82 75
83 let f_res = f(&mut *bus).await; 76 let f_res = f(&mut *bus).await;
84 77
85 // On failure, it's important to still flush and deassert CS. 78 // On failure, it's important to still flush and deassert CS.
86 let flush_res = bus.flush().await; 79 let flush_res = bus.flush().await;
87 let cs_res = self.cs.set_high(); 80 let cs_res = self.cs.set_high();
88 81
89 let f_res = f_res.map_err(SpiDeviceError::Spi)?; 82 let f_res = f_res.map_err(SpiDeviceError::Spi)?;
90 flush_res.map_err(SpiDeviceError::Spi)?; 83 flush_res.map_err(SpiDeviceError::Spi)?;
91 cs_res.map_err(SpiDeviceError::Cs)?; 84 cs_res.map_err(SpiDeviceError::Cs)?;
92 85
93 Ok(f_res) 86 Ok(f_res)
94 }
95 } 87 }
96} 88}
97 89
@@ -130,33 +122,25 @@ where
130{ 122{
131 type Bus = BUS; 123 type Bus = BUS;
132 124
133 type TransactionFuture<'a, R, F, Fut> = impl Future<Output = Result<R, Self::Error>> + 'a 125 async fn transaction<R, F, Fut>(&mut self, f: F) -> Result<R, Self::Error>
134 where
135 Self: 'a, R: 'a, F: FnOnce(*mut Self::Bus) -> Fut + 'a,
136 Fut: Future<Output = Result<R, <Self::Bus as ErrorType>::Error>> + 'a;
137
138 fn transaction<'a, R, F, Fut>(&'a mut self, f: F) -> Self::TransactionFuture<'a, R, F, Fut>
139 where 126 where
140 R: 'a, 127 F: FnOnce(*mut Self::Bus) -> Fut,
141 F: FnOnce(*mut Self::Bus) -> Fut + 'a, 128 Fut: Future<Output = Result<R, <Self::Bus as ErrorType>::Error>>,
142 Fut: Future<Output = Result<R, <Self::Bus as ErrorType>::Error>> + 'a,
143 { 129 {
144 async move { 130 let mut bus = self.bus.lock().await;
145 let mut bus = self.bus.lock().await; 131 bus.set_config(&self.config);
146 bus.set_config(&self.config); 132 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
147 self.cs.set_low().map_err(SpiDeviceError::Cs)?;
148 133
149 let f_res = f(&mut *bus).await; 134 let f_res = f(&mut *bus).await;
150 135
151 // On failure, it's important to still flush and deassert CS. 136 // On failure, it's important to still flush and deassert CS.
152 let flush_res = bus.flush().await; 137 let flush_res = bus.flush().await;
153 let cs_res = self.cs.set_high(); 138 let cs_res = self.cs.set_high();
154 139
155 let f_res = f_res.map_err(SpiDeviceError::Spi)?; 140 let f_res = f_res.map_err(SpiDeviceError::Spi)?;
156 flush_res.map_err(SpiDeviceError::Spi)?; 141 flush_res.map_err(SpiDeviceError::Spi)?;
157 cs_res.map_err(SpiDeviceError::Cs)?; 142 cs_res.map_err(SpiDeviceError::Cs)?;
158 143
159 Ok(f_res) 144 Ok(f_res)
160 }
161 } 145 }
162} 146}
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index d0f51646d..c2868eb98 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -1,9 +1,15 @@
1[package] 1[package]
2name = "embassy-executor" 2name = "embassy-executor"
3version = "0.1.0" 3version = "0.1.1"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6description = "async/await executor designed for embedded usage"
7repository = "https://github.com/embassy-rs/embassy"
8categories = [
9 "embedded",
10 "no-std",
11 "asynchronous",
12]
7 13
8[package.metadata.embassy_docs] 14[package.metadata.embassy_docs]
9src_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/"
@@ -21,10 +27,13 @@ flavors = [
21 { name = "thumbv8m.main-none-eabihf", target = "thumbv8m.main-none-eabihf", features = [] }, 27 { name = "thumbv8m.main-none-eabihf", target = "thumbv8m.main-none-eabihf", features = [] },
22] 28]
23 29
30[package.metadata.docs.rs]
31features = ["std", "nightly", "defmt"]
32
24[features] 33[features]
25default = [] 34default = []
26std = ["embassy-macros/std", "critical-section/std"] 35std = ["critical-section/std"]
27wasm = ["dep:wasm-bindgen", "dep:js-sys", "embassy-macros/wasm"] 36wasm = ["dep:wasm-bindgen", "dep:js-sys"]
28 37
29# Enable nightly-only features 38# Enable nightly-only features
30nightly = [] 39nightly = []
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs
index e4cbd04b9..4c7e2f4cd 100644
--- a/embassy-executor/src/lib.rs
+++ b/embassy-executor/src/lib.rs
@@ -8,18 +8,22 @@
8pub(crate) mod fmt; 8pub(crate) mod fmt;
9 9
10#[cfg(feature = "nightly")] 10#[cfg(feature = "nightly")]
11pub use embassy_macros::{main, task}; 11pub use embassy_macros::task;
12 12
13cfg_if::cfg_if! { 13cfg_if::cfg_if! {
14 if #[cfg(cortex_m)] { 14 if #[cfg(cortex_m)] {
15 #[path="arch/cortex_m.rs"] 15 #[path="arch/cortex_m.rs"]
16 mod arch; 16 mod arch;
17 pub use arch::*; 17 pub use arch::*;
18 #[cfg(feature = "nightly")]
19 pub use embassy_macros::main_cortex_m as main;
18 } 20 }
19 else if #[cfg(target_arch="riscv32")] { 21 else if #[cfg(target_arch="riscv32")] {
20 #[path="arch/riscv32.rs"] 22 #[path="arch/riscv32.rs"]
21 mod arch; 23 mod arch;
22 pub use arch::*; 24 pub use arch::*;
25 #[cfg(feature = "nightly")]
26 pub use embassy_macros::main_riscv as main;
23 } 27 }
24 else if #[cfg(all(target_arch="xtensa", feature = "nightly"))] { 28 else if #[cfg(all(target_arch="xtensa", feature = "nightly"))] {
25 #[path="arch/xtensa.rs"] 29 #[path="arch/xtensa.rs"]
@@ -30,11 +34,15 @@ cfg_if::cfg_if! {
30 #[path="arch/wasm.rs"] 34 #[path="arch/wasm.rs"]
31 mod arch; 35 mod arch;
32 pub use arch::*; 36 pub use arch::*;
37 #[cfg(feature = "nightly")]
38 pub use embassy_macros::main_wasm as main;
33 } 39 }
34 else if #[cfg(feature="std")] { 40 else if #[cfg(feature="std")] {
35 #[path="arch/std.rs"] 41 #[path="arch/std.rs"]
36 mod arch; 42 mod arch;
37 pub use arch::*; 43 pub use arch::*;
44 #[cfg(feature = "nightly")]
45 pub use embassy_macros::main_std as main;
38 } 46 }
39} 47}
40 48
diff --git a/embassy-hal-common/src/atomic_ring_buffer.rs b/embassy-hal-common/src/atomic_ring_buffer.rs
new file mode 100644
index 000000000..c5e444306
--- /dev/null
+++ b/embassy-hal-common/src/atomic_ring_buffer.rs
@@ -0,0 +1,331 @@
1use core::slice;
2use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
3
4/// Atomic reusable ringbuffer
5///
6/// This ringbuffer implementation is designed to be stored in a `static`,
7/// therefore all methods take `&self` and not `&mut self`.
8///
9/// It is "reusable": when created it has no backing buffer, you can give it
10/// one with `init` and take it back with `deinit`, and init it again in the
11/// future if needed. This is very non-idiomatic, but helps a lot when storing
12/// it in a `static`.
13///
14/// One concurrent writer and one concurrent reader are supported, even at
15/// different execution priorities (like main and irq).
16pub struct RingBuffer {
17 buf: AtomicPtr<u8>,
18 len: AtomicUsize,
19 start: AtomicUsize,
20 end: AtomicUsize,
21}
22
23pub struct Reader<'a>(&'a RingBuffer);
24pub struct Writer<'a>(&'a RingBuffer);
25
26impl RingBuffer {
27 /// Create a new empty ringbuffer.
28 pub const fn new() -> Self {
29 Self {
30 buf: AtomicPtr::new(core::ptr::null_mut()),
31 len: AtomicUsize::new(0),
32 start: AtomicUsize::new(0),
33 end: AtomicUsize::new(0),
34 }
35 }
36
37 /// Initialize the ring buffer with a buffer.
38 ///
39 /// # Safety
40 /// - The buffer (`buf .. buf+len`) must be valid memory until `deinit` is called.
41 /// - Must not be called concurrently with any other methods.
42 pub unsafe fn init(&self, buf: *mut u8, len: usize) {
43 // Ordering: it's OK to use `Relaxed` because this is not called
44 // concurrently with other methods.
45 self.buf.store(buf, Ordering::Relaxed);
46 self.len.store(len, Ordering::Relaxed);
47 self.start.store(0, Ordering::Relaxed);
48 self.end.store(0, Ordering::Relaxed);
49 }
50
51 /// Deinitialize the ringbuffer.
52 ///
53 /// After calling this, the ringbuffer becomes empty, as if it was
54 /// just created with `new()`.
55 ///
56 /// # Safety
57 /// - Must not be called concurrently with any other methods.
58 pub unsafe fn deinit(&self) {
59 // Ordering: it's OK to use `Relaxed` because this is not called
60 // concurrently with other methods.
61 self.len.store(0, Ordering::Relaxed);
62 self.start.store(0, Ordering::Relaxed);
63 self.end.store(0, Ordering::Relaxed);
64 }
65
66 /// Create a reader.
67 ///
68 /// # Safety
69 ///
70 /// Only one reader can exist at a time.
71 pub unsafe fn reader(&self) -> Reader<'_> {
72 Reader(self)
73 }
74
75 /// Create a writer.
76 ///
77 /// # Safety
78 ///
79 /// Only one writer can exist at a time.
80 pub unsafe fn writer(&self) -> Writer<'_> {
81 Writer(self)
82 }
83
84 pub fn is_full(&self) -> bool {
85 let start = self.start.load(Ordering::Relaxed);
86 let end = self.end.load(Ordering::Relaxed);
87
88 self.wrap(end + 1) == start
89 }
90
91 pub fn is_empty(&self) -> bool {
92 let start = self.start.load(Ordering::Relaxed);
93 let end = self.end.load(Ordering::Relaxed);
94
95 start == end
96 }
97
98 fn wrap(&self, n: usize) -> usize {
99 let len = self.len.load(Ordering::Relaxed);
100
101 assert!(n <= len);
102 if n == len {
103 0
104 } else {
105 n
106 }
107 }
108}
109
110impl<'a> Writer<'a> {
111 /// Push data into the buffer in-place.
112 ///
113 /// The closure `f` is called with a free part of the buffer, it must write
114 /// some data to it and return the amount of bytes written.
115 pub fn push(&mut self, f: impl FnOnce(&mut [u8]) -> usize) -> usize {
116 let (p, n) = self.push_buf();
117 let buf = unsafe { slice::from_raw_parts_mut(p, n) };
118 let n = f(buf);
119 self.push_done(n);
120 n
121 }
122
123 /// Push one data byte.
124 ///
125 /// Returns true if pushed succesfully.
126 pub fn push_one(&mut self, val: u8) -> bool {
127 let n = self.push(|f| match f {
128 [] => 0,
129 [x, ..] => {
130 *x = val;
131 1
132 }
133 });
134 n != 0
135 }
136
137 /// Get a buffer where data can be pushed to.
138 ///
139 /// Write data to the start of the buffer, then call `push_done` with
140 /// however many bytes you've pushed.
141 ///
142 /// The buffer is suitable to DMA to.
143 ///
144 /// If the ringbuf is full, size=0 will be returned.
145 ///
146 /// The buffer stays valid as long as no other `Writer` method is called
147 /// and `init`/`deinit` aren't called on the ringbuf.
148 pub fn push_buf(&mut self) -> (*mut u8, usize) {
149 // Ordering: popping writes `start` last, so we read `start` first.
150 // Read it with Acquire ordering, so that the next accesses can't be reordered up past it.
151 let start = self.0.start.load(Ordering::Acquire);
152 let buf = self.0.buf.load(Ordering::Relaxed);
153 let len = self.0.len.load(Ordering::Relaxed);
154 let end = self.0.end.load(Ordering::Relaxed);
155
156 let n = if start <= end {
157 len - end - (start == 0) as usize
158 } else {
159 start - end - 1
160 };
161
162 trace!(" ringbuf: push_buf {:?}..{:?}", end, end + n);
163 (unsafe { buf.add(end) }, n)
164 }
165
166 pub fn push_done(&mut self, n: usize) {
167 trace!(" ringbuf: push {:?}", n);
168 let end = self.0.end.load(Ordering::Relaxed);
169
170 // Ordering: write `end` last, with Release ordering.
171 // The ordering ensures no preceding memory accesses (such as writing
172 // the actual data in the buffer) can be reordered down past it, which
173 // will guarantee the reader sees them after reading from `end`.
174 self.0.end.store(self.0.wrap(end + n), Ordering::Release);
175 }
176}
177
178impl<'a> Reader<'a> {
179 /// Pop data from the buffer in-place.
180 ///
181 /// The closure `f` is called with the next data, it must process
182 /// some data from it and return the amount of bytes processed.
183 pub fn pop(&mut self, f: impl FnOnce(&[u8]) -> usize) -> usize {
184 let (p, n) = self.pop_buf();
185 let buf = unsafe { slice::from_raw_parts(p, n) };
186 let n = f(buf);
187 self.pop_done(n);
188 n
189 }
190
191 /// Pop one data byte.
192 ///
193 /// Returns true if popped succesfully.
194 pub fn pop_one(&mut self) -> Option<u8> {
195 let mut res = None;
196 self.pop(|f| match f {
197 &[] => 0,
198 &[x, ..] => {
199 res = Some(x);
200 1
201 }
202 });
203 res
204 }
205
206 /// Get a buffer where data can be popped from.
207 ///
208 /// Read data from the start of the buffer, then call `pop_done` with
209 /// however many bytes you've processed.
210 ///
211 /// The buffer is suitable to DMA from.
212 ///
213 /// If the ringbuf is empty, size=0 will be returned.
214 ///
215 /// The buffer stays valid as long as no other `Reader` method is called
216 /// and `init`/`deinit` aren't called on the ringbuf.
217 pub fn pop_buf(&mut self) -> (*mut u8, usize) {
218 // Ordering: pushing writes `end` last, so we read `end` first.
219 // Read it with Acquire ordering, so that the next accesses can't be reordered up past it.
220 // This is needed to guarantee we "see" the data written by the writer.
221 let end = self.0.end.load(Ordering::Acquire);
222 let buf = self.0.buf.load(Ordering::Relaxed);
223 let len = self.0.len.load(Ordering::Relaxed);
224 let start = self.0.start.load(Ordering::Relaxed);
225
226 let n = if end < start { len - start } else { end - start };
227
228 trace!(" ringbuf: pop_buf {:?}..{:?}", start, start + n);
229 (unsafe { buf.add(start) }, n)
230 }
231
232 pub fn pop_done(&mut self, n: usize) {
233 trace!(" ringbuf: pop {:?}", n);
234
235 let start = self.0.start.load(Ordering::Relaxed);
236
237 // Ordering: write `start` last, with Release ordering.
238 // The ordering ensures no preceding memory accesses (such as reading
239 // the actual data) can be reordered down past it. This is necessary
240 // because writing to `start` is effectively freeing the read part of the
241 // buffer, which "gives permission" to the writer to write to it again.
242 // Therefore, all buffer accesses must be completed before this.
243 self.0.start.store(self.0.wrap(start + n), Ordering::Release);
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250
251 #[test]
252 fn push_pop() {
253 let mut b = [0; 4];
254 let rb = RingBuffer::new();
255 unsafe {
256 rb.init(b.as_mut_ptr(), 4);
257
258 assert_eq!(rb.is_empty(), true);
259 assert_eq!(rb.is_full(), false);
260
261 rb.writer().push(|buf| {
262 // If capacity is 4, we can fill it up to 3.
263 assert_eq!(3, buf.len());
264 buf[0] = 1;
265 buf[1] = 2;
266 buf[2] = 3;
267 3
268 });
269
270 assert_eq!(rb.is_empty(), false);
271 assert_eq!(rb.is_full(), true);
272
273 rb.writer().push(|buf| {
274 // If it's full, we can push 0 bytes.
275 assert_eq!(0, buf.len());
276 0
277 });
278
279 assert_eq!(rb.is_empty(), false);
280 assert_eq!(rb.is_full(), true);
281
282 rb.reader().pop(|buf| {
283 assert_eq!(3, buf.len());
284 assert_eq!(1, buf[0]);
285 1
286 });
287
288 assert_eq!(rb.is_empty(), false);
289 assert_eq!(rb.is_full(), false);
290
291 rb.reader().pop(|buf| {
292 assert_eq!(2, buf.len());
293 0
294 });
295
296 assert_eq!(rb.is_empty(), false);
297 assert_eq!(rb.is_full(), false);
298
299 rb.reader().pop(|buf| {
300 assert_eq!(2, buf.len());
301 assert_eq!(2, buf[0]);
302 assert_eq!(3, buf[1]);
303 2
304 });
305
306 assert_eq!(rb.is_empty(), true);
307 assert_eq!(rb.is_full(), false);
308
309 rb.reader().pop(|buf| {
310 assert_eq!(0, buf.len());
311 0
312 });
313
314 rb.writer().push(|buf| {
315 assert_eq!(1, buf.len());
316 buf[0] = 10;
317 1
318 });
319
320 rb.writer().push(|buf| {
321 assert_eq!(2, buf.len());
322 buf[0] = 11;
323 buf[1] = 12;
324 2
325 });
326
327 assert_eq!(rb.is_empty(), false);
328 assert_eq!(rb.is_full(), true);
329 }
330 }
331}
diff --git a/embassy-hal-common/src/lib.rs b/embassy-hal-common/src/lib.rs
index 5d2649d02..b2a35cd35 100644
--- a/embassy-hal-common/src/lib.rs
+++ b/embassy-hal-common/src/lib.rs
@@ -4,6 +4,7 @@
4// This mod MUST go first, so that the others see its macros. 4// This mod MUST go first, so that the others see its macros.
5pub(crate) mod fmt; 5pub(crate) mod fmt;
6 6
7pub mod atomic_ring_buffer;
7pub mod drop; 8pub mod drop;
8mod macros; 9mod macros;
9mod peripheral; 10mod peripheral;
diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml
index dc2004172..cbe78e592 100644
--- a/embassy-lora/Cargo.toml
+++ b/embassy-lora/Cargo.toml
@@ -32,7 +32,7 @@ embassy-time = { version = "0.1.0", path = "../embassy-time" }
32embassy-sync = { version = "0.1.0", path = "../embassy-sync" } 32embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
33embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } 33embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true }
34embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } 34embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
35embedded-hal-async = { version = "=0.1.0-alpha.3" } 35embedded-hal-async = { version = "=0.2.0-alpha.0" }
36embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common", default-features = false } 36embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common", default-features = false }
37futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } 37futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
38embedded-hal = { version = "0.2", features = ["unproven"] } 38embedded-hal = { version = "0.2", features = ["unproven"] }
diff --git a/embassy-lora/src/sx126x/mod.rs b/embassy-lora/src/sx126x/mod.rs
index ed8cb4059..b14d422a7 100644
--- a/embassy-lora/src/sx126x/mod.rs
+++ b/embassy-lora/src/sx126x/mod.rs
@@ -87,7 +87,7 @@ where
87 config.rf.spreading_factor.into(), 87 config.rf.spreading_factor.into(),
88 config.rf.bandwidth.into(), 88 config.rf.bandwidth.into(),
89 config.rf.coding_rate.into(), 89 config.rf.coding_rate.into(),
90 4, 90 8,
91 false, 91 false,
92 true, 92 true,
93 false, 93 false,
@@ -119,14 +119,14 @@ where
119 config.spreading_factor.into(), 119 config.spreading_factor.into(),
120 config.bandwidth.into(), 120 config.bandwidth.into(),
121 config.coding_rate.into(), 121 config.coding_rate.into(),
122 4, 122 8,
123 4, 123 4,
124 false, 124 false,
125 0u8, 125 0u8,
126 true, 126 true,
127 false, 127 false,
128 0, 128 0,
129 false, 129 true,
130 true, 130 true,
131 ) 131 )
132 .await?; 132 .await?;
diff --git a/embassy-macros/Cargo.toml b/embassy-macros/Cargo.toml
index 91d5ec8a3..5c612c997 100644
--- a/embassy-macros/Cargo.toml
+++ b/embassy-macros/Cargo.toml
@@ -3,6 +3,13 @@ name = "embassy-macros"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "macros for creating the entry point and tasks for embassy-executor"
7repository = "https://github.com/embassy-rs/embassy"
8categories = [
9 "embedded",
10 "no-std",
11 "asynchronous",
12]
6 13
7[dependencies] 14[dependencies]
8syn = { version = "1.0.76", features = ["full", "extra-traits"] } 15syn = { version = "1.0.76", features = ["full", "extra-traits"] }
@@ -14,8 +21,5 @@ proc-macro2 = "1.0.29"
14proc-macro = true 21proc-macro = true
15 22
16[features] 23[features]
17std = []
18wasm = []
19
20# Enabling this cause interrupt::take! to require embassy-executor 24# Enabling this cause interrupt::take! to require embassy-executor
21rtos-trace-interrupt = [] 25rtos-trace-interrupt = []
diff --git a/embassy-macros/README.md b/embassy-macros/README.md
new file mode 100644
index 000000000..d1d6f4cc4
--- /dev/null
+++ b/embassy-macros/README.md
@@ -0,0 +1,21 @@
1# embassy-macros
2
3An [Embassy](https://embassy.dev) project.
4
5Macros for creating the main entry point and tasks that can be spawned by `embassy-executor`.
6
7NOTE: The macros are re-exported by the `embassy-executor` crate which should be used instead of adding a direct dependency on the `embassy-macros` crate.
8
9## Minimum supported Rust version (MSRV)
10
11The `task` and `main` macros require the type alias impl trait (TAIT) nightly feature in order to compile.
12
13## License
14
15This work is licensed under either of
16
17- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
18 <http://www.apache.org/licenses/LICENSE-2.0>)
19- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
20
21at your option.
diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs
index ec8498f9f..d2c696c72 100644
--- a/embassy-macros/src/lib.rs
+++ b/embassy-macros/src/lib.rs
@@ -1,3 +1,4 @@
1#![doc = include_str!("../README.md")]
1extern crate proc_macro; 2extern crate proc_macro;
2 3
3use proc_macro::TokenStream; 4use proc_macro::TokenStream;
@@ -6,6 +7,36 @@ mod macros;
6mod util; 7mod util;
7use macros::*; 8use macros::*;
8 9
10/// Declares an async task that can be run by `embassy-executor`. The optional `pool_size` parameter can be used to specify how
11/// many concurrent tasks can be spawned (default is 1) for the function.
12///
13///
14/// The following restrictions apply:
15///
16/// * The function must be declared `async`.
17/// * The function must not use generics.
18/// * The optional `pool_size` attribute must be 1 or greater.
19///
20///
21/// ## Examples
22///
23/// Declaring a task taking no arguments:
24///
25/// ``` rust
26/// #[embassy_executor::task]
27/// async fn mytask() {
28/// // Function body
29/// }
30/// ```
31///
32/// Declaring a task with a given pool size:
33///
34/// ``` rust
35/// #[embassy_executor::task(pool_size = 4)]
36/// async fn mytask() {
37/// // Function body
38/// }
39/// ```
9#[proc_macro_attribute] 40#[proc_macro_attribute]
10pub fn task(args: TokenStream, item: TokenStream) -> TokenStream { 41pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
11 let args = syn::parse_macro_input!(args as syn::AttributeArgs); 42 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
@@ -14,11 +45,104 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
14 task::run(args, f).unwrap_or_else(|x| x).into() 45 task::run(args, f).unwrap_or_else(|x| x).into()
15} 46}
16 47
48/// Creates a new `executor` instance and declares an application entry point for Cortex-M spawning the corresponding function body as an async task.
49///
50/// The following restrictions apply:
51///
52/// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks.
53/// * The function must be declared `async`.
54/// * The function must not use generics.
55/// * Only a single `main` task may be declared.
56///
57/// ## Examples
58/// Spawning a task:
59///
60/// ``` rust
61/// #[embassy_executor::main]
62/// async fn main(_s: embassy_executor::Spawner) {
63/// // Function body
64/// }
65/// ```
66#[proc_macro_attribute]
67pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream {
68 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
69 let f = syn::parse_macro_input!(item as syn::ItemFn);
70 main::run(args, f, main::cortex_m()).unwrap_or_else(|x| x).into()
71}
72
73/// Creates a new `executor` instance and declares an application entry point for RISC-V spawning the corresponding function body as an async task.
74///
75/// The following restrictions apply:
76///
77/// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks.
78/// * The function must be declared `async`.
79/// * The function must not use generics.
80/// * Only a single `main` task may be declared.
81///
82/// ## Examples
83/// Spawning a task:
84///
85/// ``` rust
86/// #[embassy_executor::main]
87/// async fn main(_s: embassy_executor::Spawner) {
88/// // Function body
89/// }
90/// ```
91#[proc_macro_attribute]
92pub fn main_riscv(args: TokenStream, item: TokenStream) -> TokenStream {
93 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
94 let f = syn::parse_macro_input!(item as syn::ItemFn);
95 main::run(args, f, main::riscv()).unwrap_or_else(|x| x).into()
96}
97
98/// Creates a new `executor` instance and declares an application entry point for STD spawning the corresponding function body as an async task.
99///
100/// The following restrictions apply:
101///
102/// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks.
103/// * The function must be declared `async`.
104/// * The function must not use generics.
105/// * Only a single `main` task may be declared.
106///
107/// ## Examples
108/// Spawning a task:
109///
110/// ``` rust
111/// #[embassy_executor::main]
112/// async fn main(_s: embassy_executor::Spawner) {
113/// // Function body
114/// }
115/// ```
116#[proc_macro_attribute]
117pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream {
118 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
119 let f = syn::parse_macro_input!(item as syn::ItemFn);
120 main::run(args, f, main::std()).unwrap_or_else(|x| x).into()
121}
122
123/// Creates a new `executor` instance and declares an application entry point for WASM spawning the corresponding function body as an async task.
124///
125/// The following restrictions apply:
126///
127/// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks.
128/// * The function must be declared `async`.
129/// * The function must not use generics.
130/// * Only a single `main` task may be declared.
131///
132/// ## Examples
133/// Spawning a task:
134///
135/// ``` rust
136/// #[embassy_executor::main]
137/// async fn main(_s: embassy_executor::Spawner) {
138/// // Function body
139/// }
140/// ```
17#[proc_macro_attribute] 141#[proc_macro_attribute]
18pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { 142pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream {
19 let args = syn::parse_macro_input!(args as syn::AttributeArgs); 143 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
20 let f = syn::parse_macro_input!(item as syn::ItemFn); 144 let f = syn::parse_macro_input!(item as syn::ItemFn);
21 main::run(args, f).unwrap_or_else(|x| x).into() 145 main::run(args, f, main::wasm()).unwrap_or_else(|x| x).into()
22} 146}
23 147
24#[proc_macro_attribute] 148#[proc_macro_attribute]
diff --git a/embassy-macros/src/macros/main.rs b/embassy-macros/src/macros/main.rs
index afe9bd3e2..18f7c36c4 100644
--- a/embassy-macros/src/macros/main.rs
+++ b/embassy-macros/src/macros/main.rs
@@ -7,31 +7,34 @@ use crate::util::ctxt::Ctxt;
7#[derive(Debug, FromMeta)] 7#[derive(Debug, FromMeta)]
8struct Args {} 8struct Args {}
9 9
10pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, TokenStream> { 10pub fn riscv() -> TokenStream {
11 #[allow(unused_variables)] 11 quote! {
12 let args = Args::from_list(&args).map_err(|e| e.write_errors())?; 12 #[riscv_rt::entry]
13 13 fn main() -> ! {
14 let fargs = f.sig.inputs.clone(); 14 let mut executor = ::embassy_executor::Executor::new();
15 15 let executor = unsafe { __make_static(&mut executor) };
16 let ctxt = Ctxt::new(); 16 executor.run(|spawner| {
17 17 spawner.must_spawn(__embassy_main(spawner));
18 if f.sig.asyncness.is_none() { 18 })
19 ctxt.error_spanned_by(&f.sig, "main function must be async"); 19 }
20 }
21 if !f.sig.generics.params.is_empty() {
22 ctxt.error_spanned_by(&f.sig, "main function must not be generic");
23 } 20 }
21}
24 22
25 if fargs.len() != 1 { 23pub fn cortex_m() -> TokenStream {
26 ctxt.error_spanned_by(&f.sig, "main function must have 1 argument: the spawner."); 24 quote! {
25 #[cortex_m_rt::entry]
26 fn main() -> ! {
27 let mut executor = ::embassy_executor::Executor::new();
28 let executor = unsafe { __make_static(&mut executor) };
29 executor.run(|spawner| {
30 spawner.must_spawn(__embassy_main(spawner));
31 })
32 }
27 } 33 }
34}
28 35
29 ctxt.check()?; 36pub fn wasm() -> TokenStream {
30 37 quote! {
31 let f_body = f.block;
32
33 #[cfg(feature = "wasm")]
34 let main = quote! {
35 #[wasm_bindgen::prelude::wasm_bindgen(start)] 38 #[wasm_bindgen::prelude::wasm_bindgen(start)]
36 pub fn main() -> Result<(), wasm_bindgen::JsValue> { 39 pub fn main() -> Result<(), wasm_bindgen::JsValue> {
37 static EXECUTOR: ::embassy_executor::_export::StaticCell<::embassy_executor::Executor> = ::embassy_executor::_export::StaticCell::new(); 40 static EXECUTOR: ::embassy_executor::_export::StaticCell<::embassy_executor::Executor> = ::embassy_executor::_export::StaticCell::new();
@@ -43,10 +46,11 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke
43 46
44 Ok(()) 47 Ok(())
45 } 48 }
46 }; 49 }
50}
47 51
48 #[cfg(all(feature = "std", not(feature = "wasm")))] 52pub fn std() -> TokenStream {
49 let main = quote! { 53 quote! {
50 fn main() -> ! { 54 fn main() -> ! {
51 let mut executor = ::embassy_executor::Executor::new(); 55 let mut executor = ::embassy_executor::Executor::new();
52 let executor = unsafe { __make_static(&mut executor) }; 56 let executor = unsafe { __make_static(&mut executor) };
@@ -55,20 +59,31 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke
55 spawner.must_spawn(__embassy_main(spawner)); 59 spawner.must_spawn(__embassy_main(spawner));
56 }) 60 })
57 } 61 }
58 }; 62 }
63}
59 64
60 #[cfg(all(not(feature = "std"), not(feature = "wasm")))] 65pub fn run(args: syn::AttributeArgs, f: syn::ItemFn, main: TokenStream) -> Result<TokenStream, TokenStream> {
61 let main = quote! { 66 #[allow(unused_variables)]
62 #[cortex_m_rt::entry] 67 let args = Args::from_list(&args).map_err(|e| e.write_errors())?;
63 fn main() -> ! {
64 let mut executor = ::embassy_executor::Executor::new();
65 let executor = unsafe { __make_static(&mut executor) };
66 68
67 executor.run(|spawner| { 69 let fargs = f.sig.inputs.clone();
68 spawner.must_spawn(__embassy_main(spawner)); 70
69 }) 71 let ctxt = Ctxt::new();
70 } 72
71 }; 73 if f.sig.asyncness.is_none() {
74 ctxt.error_spanned_by(&f.sig, "main function must be async");
75 }
76 if !f.sig.generics.params.is_empty() {
77 ctxt.error_spanned_by(&f.sig, "main function must not be generic");
78 }
79
80 if fargs.len() != 1 {
81 ctxt.error_spanned_by(&f.sig, "main function must have 1 argument: the spawner.");
82 }
83
84 ctxt.check()?;
85
86 let f_body = f.block;
72 87
73 let result = quote! { 88 let result = quote! {
74 #[::embassy_executor::task()] 89 #[::embassy_executor::task()]
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index 76217075a..ac338843d 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -42,7 +42,7 @@ log = { version = "0.4.14", optional = true }
42 42
43embassy-time = { version = "0.1.0", path = "../embassy-time" } 43embassy-time = { version = "0.1.0", path = "../embassy-time" }
44embassy-sync = { version = "0.1.0", path = "../embassy-sync" } 44embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
45embedded-io = { version = "0.3.1", optional = true } 45embedded-io = { version = "0.4.0", optional = true }
46 46
47managed = { version = "0.8.0", default-features = false, features = [ "map" ] } 47managed = { version = "0.8.0", default-features = false, features = [ "map" ] }
48heapless = { version = "0.7.5", default-features = false } 48heapless = { version = "0.7.5", default-features = false }
@@ -52,12 +52,12 @@ stable_deref_trait = { version = "1.2.0", default-features = false }
52futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } 52futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
53atomic-pool = "1.0" 53atomic-pool = "1.0"
54atomic-polyfill = "1.0.1" 54atomic-polyfill = "1.0.1"
55embedded-nal-async = { version = "0.2.0", optional = true } 55embedded-nal-async = { version = "0.3.0", optional = true }
56 56
57[dependencies.smoltcp] 57[dependencies.smoltcp]
58version = "0.8.0" 58version = "0.8.0"
59git = "https://github.com/smoltcp-rs/smoltcp" 59git = "https://github.com/smoltcp-rs/smoltcp"
60rev = "ed0cf16750a42f30e31fcaf5347915592924b1e3" 60rev = "b7a7c4b1c56e8d4c2524c1e3a056c745a13cc09f"
61default-features = false 61default-features = false
62features = [ 62features = [
63 "proto-ipv4", 63 "proto-ipv4",
diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs
index c183bd58a..4bdfd7720 100644
--- a/embassy-net/src/device.rs
+++ b/embassy-net/src/device.rs
@@ -12,8 +12,6 @@ pub enum LinkState {
12 Up, 12 Up,
13} 13}
14 14
15// 'static required due to the "fake GAT" in smoltcp::phy::Device.
16// https://github.com/smoltcp-rs/smoltcp/pull/572
17pub trait Device { 15pub trait Device {
18 fn is_transmit_ready(&mut self) -> bool; 16 fn is_transmit_ready(&mut self) -> bool;
19 fn transmit(&mut self, pkt: PacketBuf); 17 fn transmit(&mut self, pkt: PacketBuf);
@@ -25,7 +23,7 @@ pub trait Device {
25 fn ethernet_address(&self) -> [u8; 6]; 23 fn ethernet_address(&self) -> [u8; 6];
26} 24}
27 25
28impl<T: ?Sized + Device> Device for &'static mut T { 26impl<T: ?Sized + Device> Device for &mut T {
29 fn is_transmit_ready(&mut self) -> bool { 27 fn is_transmit_ready(&mut self) -> bool {
30 T::is_transmit_ready(self) 28 T::is_transmit_ready(self)
31 } 29 }
@@ -63,11 +61,11 @@ impl<D: Device> DeviceAdapter<D> {
63 } 61 }
64} 62}
65 63
66impl<'a, D: Device + 'static> SmolDevice<'a> for DeviceAdapter<D> { 64impl<D: Device> SmolDevice for DeviceAdapter<D> {
67 type RxToken = RxToken; 65 type RxToken<'a> = RxToken where Self: 'a;
68 type TxToken = TxToken<'a, D>; 66 type TxToken<'a> = TxToken<'a, D> where Self: 'a;
69 67
70 fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { 68 fn receive(&mut self) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
71 let tx_pkt = PacketBox::new(Packet::new())?; 69 let tx_pkt = PacketBox::new(Packet::new())?;
72 let rx_pkt = self.device.receive()?; 70 let rx_pkt = self.device.receive()?;
73 let rx_token = RxToken { pkt: rx_pkt }; 71 let rx_token = RxToken { pkt: rx_pkt };
@@ -80,7 +78,7 @@ impl<'a, D: Device + 'static> SmolDevice<'a> for DeviceAdapter<D> {
80 } 78 }
81 79
82 /// Construct a transmit token. 80 /// Construct a transmit token.
83 fn transmit(&'a mut self) -> Option<Self::TxToken> { 81 fn transmit(&mut self) -> Option<Self::TxToken<'_>> {
84 if !self.device.is_transmit_ready() { 82 if !self.device.is_transmit_ready() {
85 return None; 83 return None;
86 } 84 }
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index 4d30550d3..edb969842 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -1,5 +1,9 @@
1#![cfg_attr(not(feature = "std"), no_std)] 1#![cfg_attr(not(feature = "std"), no_std)]
2#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))] 2#![cfg_attr(
3 feature = "nightly",
4 feature(type_alias_impl_trait, async_fn_in_trait, impl_trait_projections)
5)]
6#![cfg_attr(feature = "nightly", allow(incomplete_features))]
3 7
4// This mod MUST go first, so that the others see its macros. 8// This mod MUST go first, so that the others see its macros.
5pub(crate) mod fmt; 9pub(crate) mod fmt;
diff --git a/embassy-net/src/stack.rs b/embassy-net/src/stack.rs
index 3a7610758..5c4fb0442 100644
--- a/embassy-net/src/stack.rs
+++ b/embassy-net/src/stack.rs
@@ -1,4 +1,4 @@
1use core::cell::UnsafeCell; 1use core::cell::RefCell;
2use core::future::{poll_fn, Future}; 2use core::future::{poll_fn, Future};
3use core::task::{Context, Poll}; 3use core::task::{Context, Poll};
4 4
@@ -62,8 +62,8 @@ pub enum ConfigStrategy {
62} 62}
63 63
64pub struct Stack<D: Device> { 64pub struct Stack<D: Device> {
65 pub(crate) socket: UnsafeCell<SocketStack>, 65 pub(crate) socket: RefCell<SocketStack>,
66 inner: UnsafeCell<Inner<D>>, 66 inner: RefCell<Inner<D>>,
67} 67}
68 68
69struct Inner<D: Device> { 69struct Inner<D: Device> {
@@ -81,8 +81,6 @@ pub(crate) struct SocketStack {
81 next_local_port: u16, 81 next_local_port: u16,
82} 82}
83 83
84unsafe impl<D: Device> Send for Stack<D> {}
85
86impl<D: Device + 'static> Stack<D> { 84impl<D: Device + 'static> Stack<D> {
87 pub fn new<const ADDR: usize, const SOCK: usize, const NEIGH: usize>( 85 pub fn new<const ADDR: usize, const SOCK: usize, const NEIGH: usize>(
88 device: D, 86 device: D,
@@ -143,40 +141,38 @@ impl<D: Device + 'static> Stack<D> {
143 } 141 }
144 142
145 Self { 143 Self {
146 socket: UnsafeCell::new(socket), 144 socket: RefCell::new(socket),
147 inner: UnsafeCell::new(inner), 145 inner: RefCell::new(inner),
148 } 146 }
149 } 147 }
150 148
151 /// SAFETY: must not call reentrantly. 149 fn with<R>(&self, f: impl FnOnce(&SocketStack, &Inner<D>) -> R) -> R {
152 unsafe fn with<R>(&self, f: impl FnOnce(&SocketStack, &Inner<D>) -> R) -> R { 150 f(&*self.socket.borrow(), &*self.inner.borrow())
153 f(&*self.socket.get(), &*self.inner.get())
154 } 151 }
155 152
156 /// SAFETY: must not call reentrantly. 153 fn with_mut<R>(&self, f: impl FnOnce(&mut SocketStack, &mut Inner<D>) -> R) -> R {
157 unsafe fn with_mut<R>(&self, f: impl FnOnce(&mut SocketStack, &mut Inner<D>) -> R) -> R { 154 f(&mut *self.socket.borrow_mut(), &mut *self.inner.borrow_mut())
158 f(&mut *self.socket.get(), &mut *self.inner.get())
159 } 155 }
160 156
161 pub fn ethernet_address(&self) -> [u8; 6] { 157 pub fn ethernet_address(&self) -> [u8; 6] {
162 unsafe { self.with(|_s, i| i.device.device.ethernet_address()) } 158 self.with(|_s, i| i.device.device.ethernet_address())
163 } 159 }
164 160
165 pub fn is_link_up(&self) -> bool { 161 pub fn is_link_up(&self) -> bool {
166 unsafe { self.with(|_s, i| i.link_up) } 162 self.with(|_s, i| i.link_up)
167 } 163 }
168 164
169 pub fn is_config_up(&self) -> bool { 165 pub fn is_config_up(&self) -> bool {
170 unsafe { self.with(|_s, i| i.config.is_some()) } 166 self.with(|_s, i| i.config.is_some())
171 } 167 }
172 168
173 pub fn config(&self) -> Option<Config> { 169 pub fn config(&self) -> Option<Config> {
174 unsafe { self.with(|_s, i| i.config.clone()) } 170 self.with(|_s, i| i.config.clone())
175 } 171 }
176 172
177 pub async fn run(&self) -> ! { 173 pub async fn run(&self) -> ! {
178 poll_fn(|cx| { 174 poll_fn(|cx| {
179 unsafe { self.with_mut(|s, i| i.poll(cx, s)) } 175 self.with_mut(|s, i| i.poll(cx, s));
180 Poll::<()>::Pending 176 Poll::<()>::Pending
181 }) 177 })
182 .await; 178 .await;
@@ -270,21 +266,12 @@ impl<D: Device + 'static> Inner<D> {
270 None => {} 266 None => {}
271 Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s), 267 Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s),
272 Some(dhcpv4::Event::Configured(config)) => { 268 Some(dhcpv4::Event::Configured(config)) => {
273 let mut dns_servers = Vec::new(); 269 let config = Config {
274 for s in &config.dns_servers { 270 address: config.address,
275 if let Some(addr) = s { 271 gateway: config.router,
276 dns_servers.push(addr.clone()).unwrap(); 272 dns_servers: config.dns_servers,
277 } 273 };
278 } 274 self.apply_config(s, config)
279
280 self.apply_config(
281 s,
282 Config {
283 address: config.address,
284 gateway: config.router,
285 dns_servers,
286 },
287 )
288 } 275 }
289 } 276 }
290 } else if old_link_up { 277 } else if old_link_up {
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs
index f3bd2361c..73cf2d4e4 100644
--- a/embassy-net/src/tcp.rs
+++ b/embassy-net/src/tcp.rs
@@ -1,4 +1,4 @@
1use core::cell::UnsafeCell; 1use core::cell::RefCell;
2use core::future::poll_fn; 2use core::future::poll_fn;
3use core::mem; 3use core::mem;
4use core::task::Poll; 4use core::task::Poll;
@@ -68,8 +68,7 @@ impl<'a> TcpWriter<'a> {
68 68
69impl<'a> TcpSocket<'a> { 69impl<'a> TcpSocket<'a> {
70 pub fn new<D: Device>(stack: &'a Stack<D>, rx_buffer: &'a mut [u8], tx_buffer: &'a mut [u8]) -> Self { 70 pub fn new<D: Device>(stack: &'a Stack<D>, rx_buffer: &'a mut [u8], tx_buffer: &'a mut [u8]) -> Self {
71 // safety: not accessed reentrantly. 71 let s = &mut *stack.socket.borrow_mut();
72 let s = unsafe { &mut *stack.socket.get() };
73 let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; 72 let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) };
74 let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; 73 let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) };
75 let handle = s.sockets.add(tcp::Socket::new( 74 let handle = s.sockets.add(tcp::Socket::new(
@@ -93,17 +92,18 @@ impl<'a> TcpSocket<'a> {
93 where 92 where
94 T: Into<IpEndpoint>, 93 T: Into<IpEndpoint>,
95 { 94 {
96 // safety: not accessed reentrantly. 95 let local_port = self.io.stack.borrow_mut().get_local_port();
97 let local_port = unsafe { &mut *self.io.stack.get() }.get_local_port();
98 96
99 // safety: not accessed reentrantly. 97 match {
100 match unsafe { self.io.with_mut(|s, i| s.connect(i, remote_endpoint, local_port)) } { 98 self.io
99 .with_mut(|s, i| s.connect(i.context(), remote_endpoint, local_port))
100 } {
101 Ok(()) => {} 101 Ok(()) => {}
102 Err(tcp::ConnectError::InvalidState) => return Err(ConnectError::InvalidState), 102 Err(tcp::ConnectError::InvalidState) => return Err(ConnectError::InvalidState),
103 Err(tcp::ConnectError::Unaddressable) => return Err(ConnectError::NoRoute), 103 Err(tcp::ConnectError::Unaddressable) => return Err(ConnectError::NoRoute),
104 } 104 }
105 105
106 poll_fn(|cx| unsafe { 106 poll_fn(|cx| {
107 self.io.with_mut(|s, _| match s.state() { 107 self.io.with_mut(|s, _| match s.state() {
108 tcp::State::Closed | tcp::State::TimeWait => Poll::Ready(Err(ConnectError::ConnectionReset)), 108 tcp::State::Closed | tcp::State::TimeWait => Poll::Ready(Err(ConnectError::ConnectionReset)),
109 tcp::State::Listen => unreachable!(), 109 tcp::State::Listen => unreachable!(),
@@ -121,14 +121,13 @@ impl<'a> TcpSocket<'a> {
121 where 121 where
122 T: Into<IpListenEndpoint>, 122 T: Into<IpListenEndpoint>,
123 { 123 {
124 // safety: not accessed reentrantly. 124 match self.io.with_mut(|s, _| s.listen(local_endpoint)) {
125 match unsafe { self.io.with_mut(|s, _| s.listen(local_endpoint)) } {
126 Ok(()) => {} 125 Ok(()) => {}
127 Err(tcp::ListenError::InvalidState) => return Err(AcceptError::InvalidState), 126 Err(tcp::ListenError::InvalidState) => return Err(AcceptError::InvalidState),
128 Err(tcp::ListenError::Unaddressable) => return Err(AcceptError::InvalidPort), 127 Err(tcp::ListenError::Unaddressable) => return Err(AcceptError::InvalidPort),
129 } 128 }
130 129
131 poll_fn(|cx| unsafe { 130 poll_fn(|cx| {
132 self.io.with_mut(|s, _| match s.state() { 131 self.io.with_mut(|s, _| match s.state() {
133 tcp::State::Listen | tcp::State::SynSent | tcp::State::SynReceived => { 132 tcp::State::Listen | tcp::State::SynSent | tcp::State::SynReceived => {
134 s.register_send_waker(cx.waker()); 133 s.register_send_waker(cx.waker());
@@ -149,51 +148,49 @@ impl<'a> TcpSocket<'a> {
149 } 148 }
150 149
151 pub fn set_timeout(&mut self, duration: Option<Duration>) { 150 pub fn set_timeout(&mut self, duration: Option<Duration>) {
152 unsafe { self.io.with_mut(|s, _| s.set_timeout(duration)) } 151 self.io.with_mut(|s, _| s.set_timeout(duration))
153 } 152 }
154 153
155 pub fn set_keep_alive(&mut self, interval: Option<Duration>) { 154 pub fn set_keep_alive(&mut self, interval: Option<Duration>) {
156 unsafe { self.io.with_mut(|s, _| s.set_keep_alive(interval)) } 155 self.io.with_mut(|s, _| s.set_keep_alive(interval))
157 } 156 }
158 157
159 pub fn set_hop_limit(&mut self, hop_limit: Option<u8>) { 158 pub fn set_hop_limit(&mut self, hop_limit: Option<u8>) {
160 unsafe { self.io.with_mut(|s, _| s.set_hop_limit(hop_limit)) } 159 self.io.with_mut(|s, _| s.set_hop_limit(hop_limit))
161 } 160 }
162 161
163 pub fn local_endpoint(&self) -> Option<IpEndpoint> { 162 pub fn local_endpoint(&self) -> Option<IpEndpoint> {
164 unsafe { self.io.with(|s, _| s.local_endpoint()) } 163 self.io.with(|s, _| s.local_endpoint())
165 } 164 }
166 165
167 pub fn remote_endpoint(&self) -> Option<IpEndpoint> { 166 pub fn remote_endpoint(&self) -> Option<IpEndpoint> {
168 unsafe { self.io.with(|s, _| s.remote_endpoint()) } 167 self.io.with(|s, _| s.remote_endpoint())
169 } 168 }
170 169
171 pub fn state(&self) -> tcp::State { 170 pub fn state(&self) -> tcp::State {
172 unsafe { self.io.with(|s, _| s.state()) } 171 self.io.with(|s, _| s.state())
173 } 172 }
174 173
175 pub fn close(&mut self) { 174 pub fn close(&mut self) {
176 unsafe { self.io.with_mut(|s, _| s.close()) } 175 self.io.with_mut(|s, _| s.close())
177 } 176 }
178 177
179 pub fn abort(&mut self) { 178 pub fn abort(&mut self) {
180 unsafe { self.io.with_mut(|s, _| s.abort()) } 179 self.io.with_mut(|s, _| s.abort())
181 } 180 }
182 181
183 pub fn may_send(&self) -> bool { 182 pub fn may_send(&self) -> bool {
184 unsafe { self.io.with(|s, _| s.may_send()) } 183 self.io.with(|s, _| s.may_send())
185 } 184 }
186 185
187 pub fn may_recv(&self) -> bool { 186 pub fn may_recv(&self) -> bool {
188 unsafe { self.io.with(|s, _| s.may_recv()) } 187 self.io.with(|s, _| s.may_recv())
189 } 188 }
190} 189}
191 190
192impl<'a> Drop for TcpSocket<'a> { 191impl<'a> Drop for TcpSocket<'a> {
193 fn drop(&mut self) { 192 fn drop(&mut self) {
194 // safety: not accessed reentrantly. 193 self.io.stack.borrow_mut().sockets.remove(self.io.handle);
195 let s = unsafe { &mut *self.io.stack.get() };
196 s.sockets.remove(self.io.handle);
197 } 194 }
198} 195}
199 196
@@ -201,21 +198,19 @@ impl<'a> Drop for TcpSocket<'a> {
201 198
202#[derive(Copy, Clone)] 199#[derive(Copy, Clone)]
203struct TcpIo<'a> { 200struct TcpIo<'a> {
204 stack: &'a UnsafeCell<SocketStack>, 201 stack: &'a RefCell<SocketStack>,
205 handle: SocketHandle, 202 handle: SocketHandle,
206} 203}
207 204
208impl<'d> TcpIo<'d> { 205impl<'d> TcpIo<'d> {
209 /// SAFETY: must not call reentrantly. 206 fn with<R>(&self, f: impl FnOnce(&tcp::Socket, &Interface) -> R) -> R {
210 unsafe fn with<R>(&self, f: impl FnOnce(&tcp::Socket, &Interface) -> R) -> R { 207 let s = &*self.stack.borrow();
211 let s = &*self.stack.get();
212 let socket = s.sockets.get::<tcp::Socket>(self.handle); 208 let socket = s.sockets.get::<tcp::Socket>(self.handle);
213 f(socket, &s.iface) 209 f(socket, &s.iface)
214 } 210 }
215 211
216 /// SAFETY: must not call reentrantly. 212 fn with_mut<R>(&mut self, f: impl FnOnce(&mut tcp::Socket, &mut Interface) -> R) -> R {
217 unsafe fn with_mut<R>(&mut self, f: impl FnOnce(&mut tcp::Socket, &mut Interface) -> R) -> R { 213 let s = &mut *self.stack.borrow_mut();
218 let s = &mut *self.stack.get();
219 let socket = s.sockets.get_mut::<tcp::Socket>(self.handle); 214 let socket = s.sockets.get_mut::<tcp::Socket>(self.handle);
220 let res = f(socket, &mut s.iface); 215 let res = f(socket, &mut s.iface);
221 s.waker.wake(); 216 s.waker.wake();
@@ -223,7 +218,7 @@ impl<'d> TcpIo<'d> {
223 } 218 }
224 219
225 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { 220 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
226 poll_fn(move |cx| unsafe { 221 poll_fn(move |cx| {
227 // CAUTION: smoltcp semantics around EOF are different to what you'd expect 222 // CAUTION: smoltcp semantics around EOF are different to what you'd expect
228 // from posix-like IO, so we have to tweak things here. 223 // from posix-like IO, so we have to tweak things here.
229 self.with_mut(|s, _| match s.recv_slice(buf) { 224 self.with_mut(|s, _| match s.recv_slice(buf) {
@@ -244,7 +239,7 @@ impl<'d> TcpIo<'d> {
244 } 239 }
245 240
246 async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> { 241 async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
247 poll_fn(move |cx| unsafe { 242 poll_fn(move |cx| {
248 self.with_mut(|s, _| match s.send_slice(buf) { 243 self.with_mut(|s, _| match s.send_slice(buf) {
249 // Not ready to send (no space in the tx buffer) 244 // Not ready to send (no space in the tx buffer)
250 Ok(0) => { 245 Ok(0) => {
@@ -271,8 +266,6 @@ impl<'d> TcpIo<'d> {
271 266
272#[cfg(feature = "nightly")] 267#[cfg(feature = "nightly")]
273mod embedded_io_impls { 268mod embedded_io_impls {
274 use core::future::Future;
275
276 use super::*; 269 use super::*;
277 270
278 impl embedded_io::Error for ConnectError { 271 impl embedded_io::Error for ConnectError {
@@ -292,30 +285,18 @@ mod embedded_io_impls {
292 } 285 }
293 286
294 impl<'d> embedded_io::asynch::Read for TcpSocket<'d> { 287 impl<'d> embedded_io::asynch::Read for TcpSocket<'d> {
295 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 288 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
296 where 289 self.io.read(buf).await
297 Self: 'a;
298
299 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
300 self.io.read(buf)
301 } 290 }
302 } 291 }
303 292
304 impl<'d> embedded_io::asynch::Write for TcpSocket<'d> { 293 impl<'d> embedded_io::asynch::Write for TcpSocket<'d> {
305 type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 294 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
306 where 295 self.io.write(buf).await
307 Self: 'a;
308
309 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
310 self.io.write(buf)
311 } 296 }
312 297
313 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a 298 async fn flush(&mut self) -> Result<(), Self::Error> {
314 where 299 self.io.flush().await
315 Self: 'a;
316
317 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
318 self.io.flush()
319 } 300 }
320 } 301 }
321 302
@@ -324,12 +305,8 @@ mod embedded_io_impls {
324 } 305 }
325 306
326 impl<'d> embedded_io::asynch::Read for TcpReader<'d> { 307 impl<'d> embedded_io::asynch::Read for TcpReader<'d> {
327 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 308 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
328 where 309 self.io.read(buf).await
329 Self: 'a;
330
331 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
332 self.io.read(buf)
333 } 310 }
334 } 311 }
335 312
@@ -338,27 +315,19 @@ mod embedded_io_impls {
338 } 315 }
339 316
340 impl<'d> embedded_io::asynch::Write for TcpWriter<'d> { 317 impl<'d> embedded_io::asynch::Write for TcpWriter<'d> {
341 type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 318 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
342 where 319 self.io.write(buf).await
343 Self: 'a;
344
345 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
346 self.io.write(buf)
347 } 320 }
348 321
349 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a 322 async fn flush(&mut self) -> Result<(), Self::Error> {
350 where 323 self.io.flush().await
351 Self: 'a;
352
353 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
354 self.io.flush()
355 } 324 }
356 } 325 }
357} 326}
358 327
359#[cfg(all(feature = "unstable-traits", feature = "nightly"))] 328#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
360pub mod client { 329pub mod client {
361 use core::future::Future; 330 use core::cell::UnsafeCell;
362 use core::mem::MaybeUninit; 331 use core::mem::MaybeUninit;
363 use core::ptr::NonNull; 332 use core::ptr::NonNull;
364 333
@@ -385,28 +354,29 @@ pub mod client {
385 { 354 {
386 type Error = Error; 355 type Error = Error;
387 type Connection<'m> = TcpConnection<'m, N, TX_SZ, RX_SZ> where Self: 'm; 356 type Connection<'m> = TcpConnection<'m, N, TX_SZ, RX_SZ> where Self: 'm;
388 type ConnectFuture<'m> = impl Future<Output = Result<Self::Connection<'m>, Self::Error>> + 'm 357
389 where 358 async fn connect<'a>(
390 Self: 'm; 359 &'a self,
391 360 remote: embedded_nal_async::SocketAddr,
392 fn connect<'m>(&'m self, remote: embedded_nal_async::SocketAddr) -> Self::ConnectFuture<'m> { 361 ) -> Result<Self::Connection<'a>, Self::Error>
393 async move { 362 where
394 let addr: crate::IpAddress = match remote.ip() { 363 Self: 'a,
395 IpAddr::V4(addr) => crate::IpAddress::Ipv4(crate::Ipv4Address::from_bytes(&addr.octets())), 364 {
396 #[cfg(feature = "proto-ipv6")] 365 let addr: crate::IpAddress = match remote.ip() {
397 IpAddr::V6(addr) => crate::IpAddress::Ipv6(crate::Ipv6Address::from_bytes(&addr.octets())), 366 IpAddr::V4(addr) => crate::IpAddress::Ipv4(crate::Ipv4Address::from_bytes(&addr.octets())),
398 #[cfg(not(feature = "proto-ipv6"))] 367 #[cfg(feature = "proto-ipv6")]
399 IpAddr::V6(_) => panic!("ipv6 support not enabled"), 368 IpAddr::V6(addr) => crate::IpAddress::Ipv6(crate::Ipv6Address::from_bytes(&addr.octets())),
400 }; 369 #[cfg(not(feature = "proto-ipv6"))]
401 let remote_endpoint = (addr, remote.port()); 370 IpAddr::V6(_) => panic!("ipv6 support not enabled"),
402 let mut socket = TcpConnection::new(&self.stack, self.state)?; 371 };
403 socket 372 let remote_endpoint = (addr, remote.port());
404 .socket 373 let mut socket = TcpConnection::new(&self.stack, self.state)?;
405 .connect(remote_endpoint) 374 socket
406 .await 375 .socket
407 .map_err(|_| Error::ConnectionReset)?; 376 .connect(remote_endpoint)
408 Ok(socket) 377 .await
409 } 378 .map_err(|_| Error::ConnectionReset)?;
379 Ok(socket)
410 } 380 }
411 } 381 }
412 382
@@ -445,32 +415,20 @@ pub mod client {
445 impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_io::asynch::Read 415 impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_io::asynch::Read
446 for TcpConnection<'d, N, TX_SZ, RX_SZ> 416 for TcpConnection<'d, N, TX_SZ, RX_SZ>
447 { 417 {
448 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 418 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
449 where 419 self.socket.read(buf).await
450 Self: 'a;
451
452 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
453 self.socket.read(buf)
454 } 420 }
455 } 421 }
456 422
457 impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_io::asynch::Write 423 impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_io::asynch::Write
458 for TcpConnection<'d, N, TX_SZ, RX_SZ> 424 for TcpConnection<'d, N, TX_SZ, RX_SZ>
459 { 425 {
460 type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 426 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
461 where 427 self.socket.write(buf).await
462 Self: 'a;
463
464 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
465 self.socket.write(buf)
466 } 428 }
467 429
468 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a 430 async fn flush(&mut self) -> Result<(), Self::Error> {
469 where 431 self.socket.flush().await
470 Self: 'a;
471
472 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
473 self.socket.flush()
474 } 432 }
475 } 433 }
476 434
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs
index f2e33493c..4ddad77d4 100644
--- a/embassy-net/src/udp.rs
+++ b/embassy-net/src/udp.rs
@@ -1,4 +1,4 @@
1use core::cell::UnsafeCell; 1use core::cell::RefCell;
2use core::future::poll_fn; 2use core::future::poll_fn;
3use core::mem; 3use core::mem;
4use core::task::Poll; 4use core::task::Poll;
@@ -27,7 +27,7 @@ pub enum Error {
27} 27}
28 28
29pub struct UdpSocket<'a> { 29pub struct UdpSocket<'a> {
30 stack: &'a UnsafeCell<SocketStack>, 30 stack: &'a RefCell<SocketStack>,
31 handle: SocketHandle, 31 handle: SocketHandle,
32} 32}
33 33
@@ -39,8 +39,7 @@ impl<'a> UdpSocket<'a> {
39 tx_meta: &'a mut [PacketMetadata], 39 tx_meta: &'a mut [PacketMetadata],
40 tx_buffer: &'a mut [u8], 40 tx_buffer: &'a mut [u8],
41 ) -> Self { 41 ) -> Self {
42 // safety: not accessed reentrantly. 42 let s = &mut *stack.socket.borrow_mut();
43 let s = unsafe { &mut *stack.socket.get() };
44 43
45 let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) }; 44 let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) };
46 let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; 45 let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) };
@@ -63,30 +62,26 @@ impl<'a> UdpSocket<'a> {
63 { 62 {
64 let mut endpoint = endpoint.into(); 63 let mut endpoint = endpoint.into();
65 64
66 // safety: not accessed reentrantly.
67 if endpoint.port == 0 { 65 if endpoint.port == 0 {
68 // If user didn't specify port allocate a dynamic port. 66 // If user didn't specify port allocate a dynamic port.
69 endpoint.port = unsafe { &mut *self.stack.get() }.get_local_port(); 67 endpoint.port = self.stack.borrow_mut().get_local_port();
70 } 68 }
71 69
72 // safety: not accessed reentrantly. 70 match self.with_mut(|s, _| s.bind(endpoint)) {
73 match unsafe { self.with_mut(|s, _| s.bind(endpoint)) } {
74 Ok(()) => Ok(()), 71 Ok(()) => Ok(()),
75 Err(udp::BindError::InvalidState) => Err(BindError::InvalidState), 72 Err(udp::BindError::InvalidState) => Err(BindError::InvalidState),
76 Err(udp::BindError::Unaddressable) => Err(BindError::NoRoute), 73 Err(udp::BindError::Unaddressable) => Err(BindError::NoRoute),
77 } 74 }
78 } 75 }
79 76
80 /// SAFETY: must not call reentrantly. 77 fn with<R>(&self, f: impl FnOnce(&udp::Socket, &Interface) -> R) -> R {
81 unsafe fn with<R>(&self, f: impl FnOnce(&udp::Socket, &Interface) -> R) -> R { 78 let s = &*self.stack.borrow();
82 let s = &*self.stack.get();
83 let socket = s.sockets.get::<udp::Socket>(self.handle); 79 let socket = s.sockets.get::<udp::Socket>(self.handle);
84 f(socket, &s.iface) 80 f(socket, &s.iface)
85 } 81 }
86 82
87 /// SAFETY: must not call reentrantly. 83 fn with_mut<R>(&self, f: impl FnOnce(&mut udp::Socket, &mut Interface) -> R) -> R {
88 unsafe fn with_mut<R>(&self, f: impl FnOnce(&mut udp::Socket, &mut Interface) -> R) -> R { 84 let s = &mut *self.stack.borrow_mut();
89 let s = &mut *self.stack.get();
90 let socket = s.sockets.get_mut::<udp::Socket>(self.handle); 85 let socket = s.sockets.get_mut::<udp::Socket>(self.handle);
91 let res = f(socket, &mut s.iface); 86 let res = f(socket, &mut s.iface);
92 s.waker.wake(); 87 s.waker.wake();
@@ -94,7 +89,7 @@ impl<'a> UdpSocket<'a> {
94 } 89 }
95 90
96 pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint), Error> { 91 pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint), Error> {
97 poll_fn(move |cx| unsafe { 92 poll_fn(move |cx| {
98 self.with_mut(|s, _| match s.recv_slice(buf) { 93 self.with_mut(|s, _| match s.recv_slice(buf) {
99 Ok(x) => Poll::Ready(Ok(x)), 94 Ok(x) => Poll::Ready(Ok(x)),
100 // No data ready 95 // No data ready
@@ -113,7 +108,7 @@ impl<'a> UdpSocket<'a> {
113 T: Into<IpEndpoint>, 108 T: Into<IpEndpoint>,
114 { 109 {
115 let remote_endpoint = remote_endpoint.into(); 110 let remote_endpoint = remote_endpoint.into();
116 poll_fn(move |cx| unsafe { 111 poll_fn(move |cx| {
117 self.with_mut(|s, _| match s.send_slice(buf, remote_endpoint) { 112 self.with_mut(|s, _| match s.send_slice(buf, remote_endpoint) {
118 // Entire datagram has been sent 113 // Entire datagram has been sent
119 Ok(()) => Poll::Ready(Ok(())), 114 Ok(()) => Poll::Ready(Ok(())),
@@ -128,30 +123,28 @@ impl<'a> UdpSocket<'a> {
128 } 123 }
129 124
130 pub fn endpoint(&self) -> IpListenEndpoint { 125 pub fn endpoint(&self) -> IpListenEndpoint {
131 unsafe { self.with(|s, _| s.endpoint()) } 126 self.with(|s, _| s.endpoint())
132 } 127 }
133 128
134 pub fn is_open(&self) -> bool { 129 pub fn is_open(&self) -> bool {
135 unsafe { self.with(|s, _| s.is_open()) } 130 self.with(|s, _| s.is_open())
136 } 131 }
137 132
138 pub fn close(&mut self) { 133 pub fn close(&mut self) {
139 unsafe { self.with_mut(|s, _| s.close()) } 134 self.with_mut(|s, _| s.close())
140 } 135 }
141 136
142 pub fn may_send(&self) -> bool { 137 pub fn may_send(&self) -> bool {
143 unsafe { self.with(|s, _| s.can_send()) } 138 self.with(|s, _| s.can_send())
144 } 139 }
145 140
146 pub fn may_recv(&self) -> bool { 141 pub fn may_recv(&self) -> bool {
147 unsafe { self.with(|s, _| s.can_recv()) } 142 self.with(|s, _| s.can_recv())
148 } 143 }
149} 144}
150 145
151impl Drop for UdpSocket<'_> { 146impl Drop for UdpSocket<'_> {
152 fn drop(&mut self) { 147 fn drop(&mut self) {
153 // safety: not accessed reentrantly. 148 self.stack.borrow_mut().sockets.remove(self.handle);
154 let s = unsafe { &mut *self.stack.get() };
155 s.sockets.remove(self.handle);
156 } 149 }
157} 150}
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 67b6bec40..6b06d5d05 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -75,8 +75,8 @@ embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optiona
75 75
76embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 76embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
77embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} 77embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true}
78embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true} 78embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true}
79embedded-io = { version = "0.3.1", features = ["async"], optional = true } 79embedded-io = { version = "0.4.0", features = ["async"], optional = true }
80 80
81defmt = { version = "0.3", optional = true } 81defmt = { version = "0.3", optional = true }
82log = { version = "0.4.14", optional = true } 82log = { version = "0.4.14", optional = true }
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index 9c8fe65f4..ea25236f0 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -15,7 +15,7 @@
15 15
16use core::cell::RefCell; 16use core::cell::RefCell;
17use core::cmp::min; 17use core::cmp::min;
18use core::future::{poll_fn, Future}; 18use core::future::poll_fn;
19use core::sync::atomic::{compiler_fence, Ordering}; 19use core::sync::atomic::{compiler_fence, Ordering};
20use core::task::Poll; 20use core::task::Poll;
21 21
@@ -341,32 +341,20 @@ impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUar
341} 341}
342 342
343impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarte<'d, U, T> { 343impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarte<'d, U, T> {
344 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 344 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
345 where 345 self.inner_read(buf).await
346 Self: 'a;
347
348 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
349 self.inner_read(buf)
350 } 346 }
351} 347}
352 348
353impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarteRx<'u, 'd, U, T> { 349impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarteRx<'u, 'd, U, T> {
354 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 350 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
355 where 351 self.inner.inner_read(buf).await
356 Self: 'a;
357
358 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
359 self.inner.inner_read(buf)
360 } 352 }
361} 353}
362 354
363impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarte<'d, U, T> { 355impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarte<'d, U, T> {
364 type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a 356 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
365 where 357 self.inner_fill_buf().await
366 Self: 'a;
367
368 fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> {
369 self.inner_fill_buf()
370 } 358 }
371 359
372 fn consume(&mut self, amt: usize) { 360 fn consume(&mut self, amt: usize) {
@@ -375,12 +363,8 @@ impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for Bu
375} 363}
376 364
377impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarteRx<'u, 'd, U, T> { 365impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarteRx<'u, 'd, U, T> {
378 type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a 366 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
379 where 367 self.inner.inner_fill_buf().await
380 Self: 'a;
381
382 fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> {
383 self.inner.inner_fill_buf()
384 } 368 }
385 369
386 fn consume(&mut self, amt: usize) { 370 fn consume(&mut self, amt: usize) {
@@ -389,38 +373,22 @@ impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRea
389} 373}
390 374
391impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarte<'d, U, T> { 375impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarte<'d, U, T> {
392 type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 376 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
393 where 377 self.inner_write(buf).await
394 Self: 'a;
395
396 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
397 self.inner_write(buf)
398 } 378 }
399 379
400 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a 380 async fn flush(&mut self) -> Result<(), Self::Error> {
401 where 381 self.inner_flush().await
402 Self: 'a;
403
404 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
405 self.inner_flush()
406 } 382 }
407} 383}
408 384
409impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarteTx<'u, 'd, U, T> { 385impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarteTx<'u, 'd, U, T> {
410 type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 386 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
411 where 387 self.inner.inner_write(buf).await
412 Self: 'a;
413
414 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
415 self.inner.inner_write(buf)
416 } 388 }
417 389
418 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a 390 async fn flush(&mut self) -> Result<(), Self::Error> {
419 where 391 self.inner.inner_flush().await
420 Self: 'a;
421
422 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
423 self.inner.inner_flush()
424 } 392 }
425} 393}
426 394
diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs
index dec31a84c..bf4019c13 100644
--- a/embassy-nrf/src/chips/nrf52805.rs
+++ b/embassy-nrf/src/chips/nrf52805.rs
@@ -131,8 +131,12 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
131 131
132impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); 132impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0);
133 133
134impl_spis!(SPI0, SPIS0, SPIM0_SPIS0_SPI0);
135
134impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); 136impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0);
135 137
138impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0);
139
136impl_timer!(TIMER0, TIMER0, TIMER0); 140impl_timer!(TIMER0, TIMER0, TIMER0);
137impl_timer!(TIMER1, TIMER1, TIMER1); 141impl_timer!(TIMER1, TIMER1, TIMER1);
138impl_timer!(TIMER2, TIMER2, TIMER2); 142impl_timer!(TIMER2, TIMER2, TIMER2);
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs
index e57a4a383..6c28a3bea 100644
--- a/embassy-nrf/src/chips/nrf52810.rs
+++ b/embassy-nrf/src/chips/nrf52810.rs
@@ -137,8 +137,12 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
137 137
138impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); 138impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0);
139 139
140impl_spis!(SPI0, SPIS0, SPIM0_SPIS0_SPI0);
141
140impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); 142impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0);
141 143
144impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0);
145
142impl_pwm!(PWM0, PWM0, PWM0); 146impl_pwm!(PWM0, PWM0, PWM0);
143 147
144impl_timer!(TIMER0, TIMER0, TIMER0); 148impl_timer!(TIMER0, TIMER0, TIMER0);
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs
index 918404cf1..e7214cf5c 100644
--- a/embassy-nrf/src/chips/nrf52811.rs
+++ b/embassy-nrf/src/chips/nrf52811.rs
@@ -138,8 +138,13 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
138impl_spim!(TWISPI0, SPIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); 138impl_spim!(TWISPI0, SPIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
139impl_spim!(SPI1, SPIM1, SPIM1_SPIS1_SPI1); 139impl_spim!(SPI1, SPIM1, SPIM1_SPIS1_SPI1);
140 140
141impl_spis!(TWISPI0, SPIS0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
142impl_spis!(SPI1, SPIS1, SPIM1_SPIS1_SPI1);
143
141impl_twim!(TWISPI0, TWIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); 144impl_twim!(TWISPI0, TWIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
142 145
146impl_twis!(TWISPI0, TWIS0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
147
143impl_pwm!(PWM0, PWM0, PWM0); 148impl_pwm!(PWM0, PWM0, PWM0);
144 149
145impl_timer!(TIMER0, TIMER0, TIMER0); 150impl_timer!(TIMER0, TIMER0, TIMER0);
diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs
index dba033b0f..21d1d16cc 100644
--- a/embassy-nrf/src/chips/nrf52820.rs
+++ b/embassy-nrf/src/chips/nrf52820.rs
@@ -136,9 +136,15 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
136impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 136impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
137impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 137impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
138 138
139impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
140impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
141
139impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 142impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
140impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 143impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
141 144
145impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
146impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
147
142impl_timer!(TIMER0, TIMER0, TIMER0); 148impl_timer!(TIMER0, TIMER0, TIMER0);
143impl_timer!(TIMER1, TIMER1, TIMER1); 149impl_timer!(TIMER1, TIMER1, TIMER1);
144impl_timer!(TIMER2, TIMER2, TIMER2); 150impl_timer!(TIMER2, TIMER2, TIMER2);
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs
index 81e66c193..152dad4e3 100644
--- a/embassy-nrf/src/chips/nrf52832.rs
+++ b/embassy-nrf/src/chips/nrf52832.rs
@@ -138,6 +138,9 @@ embassy_hal_common::peripherals! {
138 138
139 // QDEC 139 // QDEC
140 QDEC, 140 QDEC,
141
142 // I2S
143 I2S,
141} 144}
142 145
143impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); 146impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
@@ -146,9 +149,16 @@ impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
146impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 149impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
147impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); 150impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2);
148 151
152impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
153impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
154impl_spis!(SPI2, SPIS2, SPIM2_SPIS2_SPI2);
155
149impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 156impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
150impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 157impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
151 158
159impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
160impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
161
152impl_pwm!(PWM0, PWM0, PWM0); 162impl_pwm!(PWM0, PWM0, PWM0);
153impl_pwm!(PWM1, PWM1, PWM1); 163impl_pwm!(PWM1, PWM1, PWM1);
154impl_pwm!(PWM2, PWM2, PWM2); 164impl_pwm!(PWM2, PWM2, PWM2);
@@ -234,6 +244,8 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5);
234impl_saadc_input!(P0_30, ANALOG_INPUT6); 244impl_saadc_input!(P0_30, ANALOG_INPUT6);
235impl_saadc_input!(P0_31, ANALOG_INPUT7); 245impl_saadc_input!(P0_31, ANALOG_INPUT7);
236 246
247impl_i2s!(I2S, I2S, I2S);
248
237pub mod irqs { 249pub mod irqs {
238 use embassy_cortex_m::interrupt::_export::declare; 250 use embassy_cortex_m::interrupt::_export::declare;
239 251
@@ -274,6 +286,6 @@ pub mod irqs {
274 declare!(PWM2); 286 declare!(PWM2);
275 declare!(SPIM2_SPIS2_SPI2); 287 declare!(SPIM2_SPIS2_SPI2);
276 declare!(RTC2); 288 declare!(RTC2);
277 declare!(I2S);
278 declare!(FPU); 289 declare!(FPU);
290 declare!(I2S);
279} 291}
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs
index 92499e3c9..a99ca6343 100644
--- a/embassy-nrf/src/chips/nrf52833.rs
+++ b/embassy-nrf/src/chips/nrf52833.rs
@@ -161,6 +161,9 @@ embassy_hal_common::peripherals! {
161 161
162 // PDM 162 // PDM
163 PDM, 163 PDM,
164
165 // I2S
166 I2S,
164} 167}
165 168
166#[cfg(feature = "nightly")] 169#[cfg(feature = "nightly")]
@@ -174,9 +177,16 @@ impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
174impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); 177impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2);
175impl_spim!(SPI3, SPIM3, SPIM3); 178impl_spim!(SPI3, SPIM3, SPIM3);
176 179
180impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
181impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
182impl_spis!(SPI2, SPIS2, SPIM2_SPIS2_SPI2);
183
177impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 184impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
178impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 185impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
179 186
187impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
188impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
189
180impl_pwm!(PWM0, PWM0, PWM0); 190impl_pwm!(PWM0, PWM0, PWM0);
181impl_pwm!(PWM1, PWM1, PWM1); 191impl_pwm!(PWM1, PWM1, PWM1);
182impl_pwm!(PWM2, PWM2, PWM2); 192impl_pwm!(PWM2, PWM2, PWM2);
@@ -280,6 +290,8 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5);
280impl_saadc_input!(P0_30, ANALOG_INPUT6); 290impl_saadc_input!(P0_30, ANALOG_INPUT6);
281impl_saadc_input!(P0_31, ANALOG_INPUT7); 291impl_saadc_input!(P0_31, ANALOG_INPUT7);
282 292
293impl_i2s!(I2S, I2S, I2S);
294
283pub mod irqs { 295pub mod irqs {
284 use embassy_cortex_m::interrupt::_export::declare; 296 use embassy_cortex_m::interrupt::_export::declare;
285 297
@@ -320,10 +332,10 @@ pub mod irqs {
320 declare!(PWM2); 332 declare!(PWM2);
321 declare!(SPIM2_SPIS2_SPI2); 333 declare!(SPIM2_SPIS2_SPI2);
322 declare!(RTC2); 334 declare!(RTC2);
323 declare!(I2S);
324 declare!(FPU); 335 declare!(FPU);
325 declare!(USBD); 336 declare!(USBD);
326 declare!(UARTE1); 337 declare!(UARTE1);
327 declare!(PWM3); 338 declare!(PWM3);
328 declare!(SPIM3); 339 declare!(SPIM3);
340 declare!(I2S);
329} 341}
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs
index 4beadfba8..4f7463be2 100644
--- a/embassy-nrf/src/chips/nrf52840.rs
+++ b/embassy-nrf/src/chips/nrf52840.rs
@@ -164,6 +164,9 @@ embassy_hal_common::peripherals! {
164 164
165 // PDM 165 // PDM
166 PDM, 166 PDM,
167
168 // I2S
169 I2S,
167} 170}
168 171
169#[cfg(feature = "nightly")] 172#[cfg(feature = "nightly")]
@@ -177,9 +180,16 @@ impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
177impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); 180impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2);
178impl_spim!(SPI3, SPIM3, SPIM3); 181impl_spim!(SPI3, SPIM3, SPIM3);
179 182
183impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
184impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
185impl_spis!(SPI2, SPIS2, SPIM2_SPIS2_SPI2);
186
180impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 187impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
181impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); 188impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
182 189
190impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
191impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
192
183impl_pwm!(PWM0, PWM0, PWM0); 193impl_pwm!(PWM0, PWM0, PWM0);
184impl_pwm!(PWM1, PWM1, PWM1); 194impl_pwm!(PWM1, PWM1, PWM1);
185impl_pwm!(PWM2, PWM2, PWM2); 195impl_pwm!(PWM2, PWM2, PWM2);
@@ -285,6 +295,8 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5);
285impl_saadc_input!(P0_30, ANALOG_INPUT6); 295impl_saadc_input!(P0_30, ANALOG_INPUT6);
286impl_saadc_input!(P0_31, ANALOG_INPUT7); 296impl_saadc_input!(P0_31, ANALOG_INPUT7);
287 297
298impl_i2s!(I2S, I2S, I2S);
299
288pub mod irqs { 300pub mod irqs {
289 use embassy_cortex_m::interrupt::_export::declare; 301 use embassy_cortex_m::interrupt::_export::declare;
290 302
@@ -325,7 +337,6 @@ pub mod irqs {
325 declare!(PWM2); 337 declare!(PWM2);
326 declare!(SPIM2_SPIS2_SPI2); 338 declare!(SPIM2_SPIS2_SPI2);
327 declare!(RTC2); 339 declare!(RTC2);
328 declare!(I2S);
329 declare!(FPU); 340 declare!(FPU);
330 declare!(USBD); 341 declare!(USBD);
331 declare!(UARTE1); 342 declare!(UARTE1);
@@ -333,4 +344,5 @@ pub mod irqs {
333 declare!(CRYPTOCELL); 344 declare!(CRYPTOCELL);
334 declare!(PWM3); 345 declare!(PWM3);
335 declare!(SPIM3); 346 declare!(SPIM3);
347 declare!(I2S);
336} 348}
diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs
index e20edcdf3..4575f09ff 100644
--- a/embassy-nrf/src/chips/nrf5340_app.rs
+++ b/embassy-nrf/src/chips/nrf5340_app.rs
@@ -366,11 +366,21 @@ impl_spim!(UARTETWISPI1, SPIM1, SERIAL1);
366impl_spim!(UARTETWISPI2, SPIM2, SERIAL2); 366impl_spim!(UARTETWISPI2, SPIM2, SERIAL2);
367impl_spim!(UARTETWISPI3, SPIM3, SERIAL3); 367impl_spim!(UARTETWISPI3, SPIM3, SERIAL3);
368 368
369impl_spis!(UARTETWISPI0, SPIS0, SERIAL0);
370impl_spis!(UARTETWISPI1, SPIS1, SERIAL1);
371impl_spis!(UARTETWISPI2, SPIS2, SERIAL2);
372impl_spis!(UARTETWISPI3, SPIS3, SERIAL3);
373
369impl_twim!(UARTETWISPI0, TWIM0, SERIAL0); 374impl_twim!(UARTETWISPI0, TWIM0, SERIAL0);
370impl_twim!(UARTETWISPI1, TWIM1, SERIAL1); 375impl_twim!(UARTETWISPI1, TWIM1, SERIAL1);
371impl_twim!(UARTETWISPI2, TWIM2, SERIAL2); 376impl_twim!(UARTETWISPI2, TWIM2, SERIAL2);
372impl_twim!(UARTETWISPI3, TWIM3, SERIAL3); 377impl_twim!(UARTETWISPI3, TWIM3, SERIAL3);
373 378
379impl_twis!(UARTETWISPI0, TWIS0, SERIAL0);
380impl_twis!(UARTETWISPI1, TWIS1, SERIAL1);
381impl_twis!(UARTETWISPI2, TWIS2, SERIAL2);
382impl_twis!(UARTETWISPI3, TWIS3, SERIAL3);
383
374impl_pwm!(PWM0, PWM0, PWM0); 384impl_pwm!(PWM0, PWM0, PWM0);
375impl_pwm!(PWM1, PWM1, PWM1); 385impl_pwm!(PWM1, PWM1, PWM1);
376impl_pwm!(PWM2, PWM2, PWM2); 386impl_pwm!(PWM2, PWM2, PWM2);
diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs
index 8c292e52b..54827238a 100644
--- a/embassy-nrf/src/chips/nrf5340_net.rs
+++ b/embassy-nrf/src/chips/nrf5340_net.rs
@@ -243,7 +243,9 @@ embassy_hal_common::peripherals! {
243 243
244impl_uarte!(UARTETWISPI0, UARTE0, SERIAL0); 244impl_uarte!(UARTETWISPI0, UARTE0, SERIAL0);
245impl_spim!(UARTETWISPI0, SPIM0, SERIAL0); 245impl_spim!(UARTETWISPI0, SPIM0, SERIAL0);
246impl_spis!(UARTETWISPI0, SPIS0, SERIAL0);
246impl_twim!(UARTETWISPI0, TWIM0, SERIAL0); 247impl_twim!(UARTETWISPI0, TWIM0, SERIAL0);
248impl_twis!(UARTETWISPI0, TWIS0, SERIAL0);
247 249
248impl_timer!(TIMER0, TIMER0, TIMER0); 250impl_timer!(TIMER0, TIMER0, TIMER0);
249impl_timer!(TIMER1, TIMER1, TIMER1); 251impl_timer!(TIMER1, TIMER1, TIMER1);
diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs
index 5c00b65a2..472ee6772 100644
--- a/embassy-nrf/src/chips/nrf9160.rs
+++ b/embassy-nrf/src/chips/nrf9160.rs
@@ -280,11 +280,21 @@ impl_spim!(UARTETWISPI1, SPIM1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1);
280impl_spim!(UARTETWISPI2, SPIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); 280impl_spim!(UARTETWISPI2, SPIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2);
281impl_spim!(UARTETWISPI3, SPIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); 281impl_spim!(UARTETWISPI3, SPIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3);
282 282
283impl_spis!(UARTETWISPI0, SPIS0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0);
284impl_spis!(UARTETWISPI1, SPIS1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1);
285impl_spis!(UARTETWISPI2, SPIS2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2);
286impl_spis!(UARTETWISPI3, SPIS3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3);
287
283impl_twim!(UARTETWISPI0, TWIM0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); 288impl_twim!(UARTETWISPI0, TWIM0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0);
284impl_twim!(UARTETWISPI1, TWIM1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); 289impl_twim!(UARTETWISPI1, TWIM1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1);
285impl_twim!(UARTETWISPI2, TWIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); 290impl_twim!(UARTETWISPI2, TWIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2);
286impl_twim!(UARTETWISPI3, TWIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); 291impl_twim!(UARTETWISPI3, TWIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3);
287 292
293impl_twis!(UARTETWISPI0, TWIS0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0);
294impl_twis!(UARTETWISPI1, TWIS1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1);
295impl_twis!(UARTETWISPI2, TWIS2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2);
296impl_twis!(UARTETWISPI3, TWIS3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3);
297
288impl_pwm!(PWM0, PWM0, PWM0); 298impl_pwm!(PWM0, PWM0, PWM0);
289impl_pwm!(PWM1, PWM1, PWM1); 299impl_pwm!(PWM1, PWM1, PWM1);
290impl_pwm!(PWM2, PWM2, PWM2); 300impl_pwm!(PWM2, PWM2, PWM2);
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index 25ad90496..7467dbc60 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -2,7 +2,7 @@ use core::convert::Infallible;
2use core::future::{poll_fn, Future}; 2use core::future::{poll_fn, Future};
3use core::task::{Context, Poll}; 3use core::task::{Context, Poll};
4 4
5use embassy_hal_common::{impl_peripheral, Peripheral, PeripheralRef}; 5use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef};
6use embassy_sync::waitqueue::AtomicWaker; 6use embassy_sync::waitqueue::AtomicWaker;
7 7
8use crate::gpio::sealed::Pin as _; 8use crate::gpio::sealed::Pin as _;
@@ -148,7 +148,7 @@ impl Iterator for BitIter {
148 148
149/// GPIOTE channel driver in input mode 149/// GPIOTE channel driver in input mode
150pub struct InputChannel<'d, C: Channel, T: GpioPin> { 150pub struct InputChannel<'d, C: Channel, T: GpioPin> {
151 ch: C, 151 ch: PeripheralRef<'d, C>,
152 pin: Input<'d, T>, 152 pin: Input<'d, T>,
153} 153}
154 154
@@ -162,7 +162,9 @@ impl<'d, C: Channel, T: GpioPin> Drop for InputChannel<'d, C, T> {
162} 162}
163 163
164impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { 164impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> {
165 pub fn new(ch: C, pin: Input<'d, T>, polarity: InputChannelPolarity) -> Self { 165 pub fn new(ch: impl Peripheral<P = C> + 'd, pin: Input<'d, T>, polarity: InputChannelPolarity) -> Self {
166 into_ref!(ch);
167
166 let g = regs(); 168 let g = regs();
167 let num = ch.number(); 169 let num = ch.number();
168 170
@@ -215,7 +217,7 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> {
215 217
216/// GPIOTE channel driver in output mode 218/// GPIOTE channel driver in output mode
217pub struct OutputChannel<'d, C: Channel, T: GpioPin> { 219pub struct OutputChannel<'d, C: Channel, T: GpioPin> {
218 ch: C, 220 ch: PeripheralRef<'d, C>,
219 _pin: Output<'d, T>, 221 _pin: Output<'d, T>,
220} 222}
221 223
@@ -229,7 +231,8 @@ impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> {
229} 231}
230 232
231impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { 233impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> {
232 pub fn new(ch: C, pin: Output<'d, T>, polarity: OutputChannelPolarity) -> Self { 234 pub fn new(ch: impl Peripheral<P = C> + 'd, pin: Output<'d, T>, polarity: OutputChannelPolarity) -> Self {
235 into_ref!(ch);
233 let g = regs(); 236 let g = regs();
234 let num = ch.number(); 237 let num = ch.number();
235 238
@@ -470,71 +473,49 @@ mod eh1 {
470 473
471#[cfg(all(feature = "unstable-traits", feature = "nightly"))] 474#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
472mod eha { 475mod eha {
473 use futures::FutureExt;
474
475 use super::*; 476 use super::*;
476 477
477 impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Input<'d, T> { 478 impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Input<'d, T> {
478 type WaitForHighFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 479 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
479 480 Ok(self.wait_for_high().await)
480 fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> {
481 self.wait_for_high().map(Ok)
482 } 481 }
483 482
484 type WaitForLowFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 483 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
485 484 Ok(self.wait_for_low().await)
486 fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> {
487 self.wait_for_low().map(Ok)
488 } 485 }
489 486
490 type WaitForRisingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 487 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
491 488 Ok(self.wait_for_rising_edge().await)
492 fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> {
493 self.wait_for_rising_edge().map(Ok)
494 } 489 }
495 490
496 type WaitForFallingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 491 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
497 492 Ok(self.wait_for_falling_edge().await)
498 fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> {
499 self.wait_for_falling_edge().map(Ok)
500 } 493 }
501 494
502 type WaitForAnyEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 495 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
503 496 Ok(self.wait_for_any_edge().await)
504 fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> {
505 self.wait_for_any_edge().map(Ok)
506 } 497 }
507 } 498 }
508 499
509 impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Flex<'d, T> { 500 impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Flex<'d, T> {
510 type WaitForHighFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 501 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
511 502 Ok(self.wait_for_high().await)
512 fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> {
513 self.wait_for_high().map(Ok)
514 } 503 }
515 504
516 type WaitForLowFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 505 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
517 506 Ok(self.wait_for_low().await)
518 fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> {
519 self.wait_for_low().map(Ok)
520 } 507 }
521 508
522 type WaitForRisingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 509 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
523 510 Ok(self.wait_for_rising_edge().await)
524 fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> {
525 self.wait_for_rising_edge().map(Ok)
526 } 511 }
527 512
528 type WaitForFallingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 513 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
529 514 Ok(self.wait_for_falling_edge().await)
530 fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> {
531 self.wait_for_falling_edge().map(Ok)
532 } 515 }
533 516
534 type WaitForAnyEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 517 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
535 518 Ok(self.wait_for_any_edge().await)
536 fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> {
537 self.wait_for_any_edge().map(Ok)
538 } 519 }
539 } 520 }
540} 521}
diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs
new file mode 100644
index 000000000..7e9507751
--- /dev/null
+++ b/embassy-nrf/src/i2s.rs
@@ -0,0 +1,1141 @@
1#![macro_use]
2
3//! Support for I2S audio
4
5use core::future::poll_fn;
6use core::marker::PhantomData;
7use core::mem::size_of;
8use core::ops::{Deref, DerefMut};
9use core::sync::atomic::{compiler_fence, Ordering};
10use core::task::Poll;
11
12use embassy_cortex_m::interrupt::InterruptExt;
13use embassy_hal_common::drop::OnDrop;
14use embassy_hal_common::{into_ref, PeripheralRef};
15
16use crate::gpio::{AnyPin, Pin as GpioPin};
17use crate::interrupt::Interrupt;
18use crate::pac::i2s::RegisterBlock;
19use crate::util::{slice_in_ram_or, slice_ptr_parts};
20use crate::{Peripheral, EASY_DMA_SIZE};
21
22pub type DoubleBuffering<S, const NS: usize> = MultiBuffering<S, 2, NS>;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26#[non_exhaustive]
27pub enum Error {
28 BufferTooLong,
29 BufferZeroLength,
30 BufferNotInDataMemory,
31 BufferMisaligned,
32 BufferLengthMisaligned,
33}
34
35/// I2S configuration.
36#[derive(Clone)]
37#[non_exhaustive]
38pub struct Config {
39 pub sample_width: SampleWidth,
40 pub align: Align,
41 pub format: Format,
42 pub channels: Channels,
43}
44
45impl Config {
46 pub fn sample_width(mut self, sample_width: SampleWidth) -> Self {
47 self.sample_width = sample_width;
48 self
49 }
50
51 pub fn align(mut self, align: Align) -> Self {
52 self.align = align;
53 self
54 }
55
56 pub fn format(mut self, format: Format) -> Self {
57 self.format = format;
58 self
59 }
60
61 pub fn channels(mut self, channels: Channels) -> Self {
62 self.channels = channels;
63 self
64 }
65}
66
67impl Default for Config {
68 fn default() -> Self {
69 Self {
70 sample_width: SampleWidth::_16bit,
71 align: Align::Left,
72 format: Format::I2S,
73 channels: Channels::Stereo,
74 }
75 }
76}
77
78/// I2S Mode
79#[derive(Debug, Eq, PartialEq, Clone, Copy)]
80pub struct MasterClock {
81 freq: MckFreq,
82 ratio: Ratio,
83}
84
85impl MasterClock {
86 pub fn new(freq: MckFreq, ratio: Ratio) -> Self {
87 Self { freq, ratio }
88 }
89}
90
91impl MasterClock {
92 pub fn sample_rate(&self) -> u32 {
93 self.freq.to_frequency() / self.ratio.to_divisor()
94 }
95}
96
97/// Master clock generator frequency.
98#[derive(Debug, Eq, PartialEq, Clone, Copy)]
99pub enum MckFreq {
100 _32MDiv8,
101 _32MDiv10,
102 _32MDiv11,
103 _32MDiv15,
104 _32MDiv16,
105 _32MDiv21,
106 _32MDiv23,
107 _32MDiv30,
108 _32MDiv31,
109 _32MDiv32,
110 _32MDiv42,
111 _32MDiv63,
112 _32MDiv125,
113}
114
115impl MckFreq {
116 const REGISTER_VALUES: &'static [u32] = &[
117 0x20000000, 0x18000000, 0x16000000, 0x11000000, 0x10000000, 0x0C000000, 0x0B000000, 0x08800000, 0x08400000,
118 0x08000000, 0x06000000, 0x04100000, 0x020C0000,
119 ];
120
121 const FREQUENCIES: &'static [u32] = &[
122 4000000, 3200000, 2909090, 2133333, 2000000, 1523809, 1391304, 1066666, 1032258, 1000000, 761904, 507936,
123 256000,
124 ];
125
126 /// Return the value that needs to be written to the register.
127 pub fn to_register_value(&self) -> u32 {
128 Self::REGISTER_VALUES[usize::from(*self)]
129 }
130
131 /// Return the master clock frequency.
132 pub fn to_frequency(&self) -> u32 {
133 Self::FREQUENCIES[usize::from(*self)]
134 }
135}
136
137impl From<MckFreq> for usize {
138 fn from(variant: MckFreq) -> Self {
139 variant as _
140 }
141}
142
143/// Master clock frequency ratio
144///
145/// Sample Rate = LRCK = MCK / Ratio
146///
147#[derive(Debug, Eq, PartialEq, Clone, Copy)]
148pub enum Ratio {
149 _32x,
150 _48x,
151 _64x,
152 _96x,
153 _128x,
154 _192x,
155 _256x,
156 _384x,
157 _512x,
158}
159
160impl Ratio {
161 const RATIOS: &'static [u32] = &[32, 48, 64, 96, 128, 192, 256, 384, 512];
162
163 /// Return the value that needs to be written to the register.
164 pub fn to_register_value(&self) -> u8 {
165 usize::from(*self) as u8
166 }
167
168 pub fn to_divisor(&self) -> u32 {
169 Self::RATIOS[usize::from(*self)]
170 }
171}
172
173impl From<Ratio> for usize {
174 fn from(variant: Ratio) -> Self {
175 variant as _
176 }
177}
178
179/// Approximate sample rates.
180///
181/// Those are common sample rates that can not be configured without an small error.
182///
183/// For custom master clock configuration, please refer to [MasterClock].
184#[derive(Clone, Copy)]
185pub enum ApproxSampleRate {
186 _11025,
187 _16000,
188 _22050,
189 _32000,
190 _44100,
191 _48000,
192}
193
194impl From<ApproxSampleRate> for MasterClock {
195 fn from(value: ApproxSampleRate) -> Self {
196 match value {
197 // error = 86
198 ApproxSampleRate::_11025 => MasterClock::new(MckFreq::_32MDiv15, Ratio::_192x),
199 // error = 127
200 ApproxSampleRate::_16000 => MasterClock::new(MckFreq::_32MDiv21, Ratio::_96x),
201 // error = 172
202 ApproxSampleRate::_22050 => MasterClock::new(MckFreq::_32MDiv15, Ratio::_96x),
203 // error = 254
204 ApproxSampleRate::_32000 => MasterClock::new(MckFreq::_32MDiv21, Ratio::_48x),
205 // error = 344
206 ApproxSampleRate::_44100 => MasterClock::new(MckFreq::_32MDiv15, Ratio::_48x),
207 // error = 381
208 ApproxSampleRate::_48000 => MasterClock::new(MckFreq::_32MDiv21, Ratio::_32x),
209 }
210 }
211}
212
213impl ApproxSampleRate {
214 pub fn sample_rate(&self) -> u32 {
215 MasterClock::from(*self).sample_rate()
216 }
217}
218
219/// Exact sample rates.
220///
221/// Those are non standard sample rates that can be configured without error.
222///
223/// For custom master clock configuration, please refer to [Mode].
224#[derive(Clone, Copy)]
225pub enum ExactSampleRate {
226 _8000,
227 _10582,
228 _12500,
229 _15625,
230 _15873,
231 _25000,
232 _31250,
233 _50000,
234 _62500,
235 _100000,
236 _125000,
237}
238
239impl ExactSampleRate {
240 pub fn sample_rate(&self) -> u32 {
241 MasterClock::from(*self).sample_rate()
242 }
243}
244
245impl From<ExactSampleRate> for MasterClock {
246 fn from(value: ExactSampleRate) -> Self {
247 match value {
248 ExactSampleRate::_8000 => MasterClock::new(MckFreq::_32MDiv125, Ratio::_32x),
249 ExactSampleRate::_10582 => MasterClock::new(MckFreq::_32MDiv63, Ratio::_48x),
250 ExactSampleRate::_12500 => MasterClock::new(MckFreq::_32MDiv10, Ratio::_256x),
251 ExactSampleRate::_15625 => MasterClock::new(MckFreq::_32MDiv32, Ratio::_64x),
252 ExactSampleRate::_15873 => MasterClock::new(MckFreq::_32MDiv63, Ratio::_32x),
253 ExactSampleRate::_25000 => MasterClock::new(MckFreq::_32MDiv10, Ratio::_128x),
254 ExactSampleRate::_31250 => MasterClock::new(MckFreq::_32MDiv32, Ratio::_32x),
255 ExactSampleRate::_50000 => MasterClock::new(MckFreq::_32MDiv10, Ratio::_64x),
256 ExactSampleRate::_62500 => MasterClock::new(MckFreq::_32MDiv16, Ratio::_32x),
257 ExactSampleRate::_100000 => MasterClock::new(MckFreq::_32MDiv10, Ratio::_32x),
258 ExactSampleRate::_125000 => MasterClock::new(MckFreq::_32MDiv8, Ratio::_32x),
259 }
260 }
261}
262
263/// Sample width.
264#[derive(Debug, Eq, PartialEq, Clone, Copy)]
265pub enum SampleWidth {
266 _8bit,
267 _16bit,
268 _24bit,
269}
270
271impl From<SampleWidth> for u8 {
272 fn from(variant: SampleWidth) -> Self {
273 variant as _
274 }
275}
276
277/// Channel used for the most significant sample value in a frame.
278#[derive(Debug, Eq, PartialEq, Clone, Copy)]
279pub enum Align {
280 Left,
281 Right,
282}
283
284impl From<Align> for bool {
285 fn from(variant: Align) -> Self {
286 match variant {
287 Align::Left => false,
288 Align::Right => true,
289 }
290 }
291}
292
293/// Frame format.
294#[derive(Debug, Eq, PartialEq, Clone, Copy)]
295pub enum Format {
296 I2S,
297 Aligned,
298}
299
300impl From<Format> for bool {
301 fn from(variant: Format) -> Self {
302 match variant {
303 Format::I2S => false,
304 Format::Aligned => true,
305 }
306 }
307}
308
309/// Channels
310#[derive(Debug, Eq, PartialEq, Clone, Copy)]
311pub enum Channels {
312 Stereo,
313 MonoLeft,
314 MonoRight,
315}
316
317impl From<Channels> for u8 {
318 fn from(variant: Channels) -> Self {
319 variant as _
320 }
321}
322
323/// Interface to the I2S peripheral using EasyDMA to offload the transmission and reception workload.
324pub struct I2S<'d, T: Instance> {
325 i2s: PeripheralRef<'d, T>,
326 irq: PeripheralRef<'d, T::Interrupt>,
327 mck: Option<PeripheralRef<'d, AnyPin>>,
328 sck: PeripheralRef<'d, AnyPin>,
329 lrck: PeripheralRef<'d, AnyPin>,
330 sdin: Option<PeripheralRef<'d, AnyPin>>,
331 sdout: Option<PeripheralRef<'d, AnyPin>>,
332 master_clock: Option<MasterClock>,
333 config: Config,
334}
335
336impl<'d, T: Instance> I2S<'d, T> {
337 /// Create a new I2S in master mode
338 pub fn master(
339 i2s: impl Peripheral<P = T> + 'd,
340 irq: impl Peripheral<P = T::Interrupt> + 'd,
341 mck: impl Peripheral<P = impl GpioPin> + 'd,
342 sck: impl Peripheral<P = impl GpioPin> + 'd,
343 lrck: impl Peripheral<P = impl GpioPin> + 'd,
344 master_clock: MasterClock,
345 config: Config,
346 ) -> Self {
347 into_ref!(i2s, irq, mck, sck, lrck);
348 Self {
349 i2s,
350 irq,
351 mck: Some(mck.map_into()),
352 sck: sck.map_into(),
353 lrck: lrck.map_into(),
354 sdin: None,
355 sdout: None,
356 master_clock: Some(master_clock),
357 config,
358 }
359 }
360
361 /// Create a new I2S in slave mode
362 pub fn slave(
363 i2s: impl Peripheral<P = T> + 'd,
364 irq: impl Peripheral<P = T::Interrupt> + 'd,
365 sck: impl Peripheral<P = impl GpioPin> + 'd,
366 lrck: impl Peripheral<P = impl GpioPin> + 'd,
367 config: Config,
368 ) -> Self {
369 into_ref!(i2s, irq, sck, lrck);
370 Self {
371 i2s,
372 irq,
373 mck: None,
374 sck: sck.map_into(),
375 lrck: lrck.map_into(),
376 sdin: None,
377 sdout: None,
378 master_clock: None,
379 config,
380 }
381 }
382
383 /// I2S output only
384 pub fn output<S: Sample, const NB: usize, const NS: usize>(
385 mut self,
386 sdout: impl Peripheral<P = impl GpioPin> + 'd,
387 buffers: MultiBuffering<S, NB, NS>,
388 ) -> OutputStream<'d, T, S, NB, NS> {
389 self.sdout = Some(sdout.into_ref().map_into());
390 OutputStream {
391 _p: self.build(),
392 buffers,
393 }
394 }
395
396 /// I2S input only
397 pub fn input<S: Sample, const NB: usize, const NS: usize>(
398 mut self,
399 sdin: impl Peripheral<P = impl GpioPin> + 'd,
400 buffers: MultiBuffering<S, NB, NS>,
401 ) -> InputStream<'d, T, S, NB, NS> {
402 self.sdin = Some(sdin.into_ref().map_into());
403 InputStream {
404 _p: self.build(),
405 buffers,
406 }
407 }
408
409 /// I2S full duplex (input and output)
410 pub fn full_duplex<S: Sample, const NB: usize, const NS: usize>(
411 mut self,
412 sdin: impl Peripheral<P = impl GpioPin> + 'd,
413 sdout: impl Peripheral<P = impl GpioPin> + 'd,
414 buffers_out: MultiBuffering<S, NB, NS>,
415 buffers_in: MultiBuffering<S, NB, NS>,
416 ) -> FullDuplexStream<'d, T, S, NB, NS> {
417 self.sdout = Some(sdout.into_ref().map_into());
418 self.sdin = Some(sdin.into_ref().map_into());
419
420 FullDuplexStream {
421 _p: self.build(),
422 buffers_out,
423 buffers_in,
424 }
425 }
426
427 fn build(self) -> PeripheralRef<'d, T> {
428 self.apply_config();
429 self.select_pins();
430 self.setup_interrupt();
431
432 let device = Device::<T>::new();
433 device.enable();
434
435 self.i2s
436 }
437
438 fn apply_config(&self) {
439 let c = &T::regs().config;
440 match &self.master_clock {
441 Some(MasterClock { freq, ratio }) => {
442 c.mode.write(|w| w.mode().master());
443 c.mcken.write(|w| w.mcken().enabled());
444 c.mckfreq
445 .write(|w| unsafe { w.mckfreq().bits(freq.to_register_value()) });
446 c.ratio.write(|w| unsafe { w.ratio().bits(ratio.to_register_value()) });
447 }
448 None => {
449 c.mode.write(|w| w.mode().slave());
450 }
451 };
452
453 c.swidth
454 .write(|w| unsafe { w.swidth().bits(self.config.sample_width.into()) });
455 c.align.write(|w| w.align().bit(self.config.align.into()));
456 c.format.write(|w| w.format().bit(self.config.format.into()));
457 c.channels
458 .write(|w| unsafe { w.channels().bits(self.config.channels.into()) });
459 }
460
461 fn select_pins(&self) {
462 let psel = &T::regs().psel;
463
464 if let Some(mck) = &self.mck {
465 psel.mck.write(|w| {
466 unsafe { w.bits(mck.psel_bits()) };
467 w.connect().connected()
468 });
469 }
470
471 psel.sck.write(|w| {
472 unsafe { w.bits(self.sck.psel_bits()) };
473 w.connect().connected()
474 });
475
476 psel.lrck.write(|w| {
477 unsafe { w.bits(self.lrck.psel_bits()) };
478 w.connect().connected()
479 });
480
481 if let Some(sdin) = &self.sdin {
482 psel.sdin.write(|w| {
483 unsafe { w.bits(sdin.psel_bits()) };
484 w.connect().connected()
485 });
486 }
487
488 if let Some(sdout) = &self.sdout {
489 psel.sdout.write(|w| {
490 unsafe { w.bits(sdout.psel_bits()) };
491 w.connect().connected()
492 });
493 }
494 }
495
496 fn setup_interrupt(&self) {
497 self.irq.set_handler(Self::on_interrupt);
498 self.irq.unpend();
499 self.irq.enable();
500
501 let device = Device::<T>::new();
502 device.disable_tx_ptr_interrupt();
503 device.disable_rx_ptr_interrupt();
504 device.disable_stopped_interrupt();
505
506 device.reset_tx_ptr_event();
507 device.reset_rx_ptr_event();
508 device.reset_stopped_event();
509
510 device.enable_tx_ptr_interrupt();
511 device.enable_rx_ptr_interrupt();
512 device.enable_stopped_interrupt();
513 }
514
515 fn on_interrupt(_: *mut ()) {
516 let device = Device::<T>::new();
517 let s = T::state();
518
519 if device.is_tx_ptr_updated() {
520 trace!("TX INT");
521 s.tx_waker.wake();
522 device.disable_tx_ptr_interrupt();
523 }
524
525 if device.is_rx_ptr_updated() {
526 trace!("RX INT");
527 s.rx_waker.wake();
528 device.disable_rx_ptr_interrupt();
529 }
530
531 if device.is_stopped() {
532 trace!("STOPPED INT");
533 s.stop_waker.wake();
534 device.disable_stopped_interrupt();
535 }
536 }
537
538 async fn stop() {
539 compiler_fence(Ordering::SeqCst);
540
541 let device = Device::<T>::new();
542 device.stop();
543
544 T::state().started.store(false, Ordering::Relaxed);
545
546 poll_fn(|cx| {
547 T::state().stop_waker.register(cx.waker());
548
549 if device.is_stopped() {
550 trace!("STOP: Ready");
551 device.reset_stopped_event();
552 Poll::Ready(())
553 } else {
554 trace!("STOP: Pending");
555 Poll::Pending
556 }
557 })
558 .await;
559
560 device.disable();
561 }
562
563 async fn send_from_ram<S>(buffer_ptr: *const [S]) -> Result<(), Error>
564 where
565 S: Sample,
566 {
567 trace!("SEND: {}", buffer_ptr as *const S as u32);
568
569 slice_in_ram_or(buffer_ptr, Error::BufferNotInDataMemory)?;
570
571 compiler_fence(Ordering::SeqCst);
572
573 let device = Device::<T>::new();
574
575 device.update_tx(buffer_ptr)?;
576
577 Self::wait_tx_ptr_update().await;
578
579 compiler_fence(Ordering::SeqCst);
580
581 Ok(())
582 }
583
584 async fn wait_tx_ptr_update() {
585 let drop = OnDrop::new(move || {
586 trace!("TX DROP: Stopping");
587
588 let device = Device::<T>::new();
589 device.disable_tx_ptr_interrupt();
590 device.reset_tx_ptr_event();
591 device.disable_tx();
592
593 // TX is stopped almost instantly, spinning is fine.
594 while !device.is_tx_ptr_updated() {}
595
596 trace!("TX DROP: Stopped");
597 });
598
599 poll_fn(|cx| {
600 T::state().tx_waker.register(cx.waker());
601
602 let device = Device::<T>::new();
603 if device.is_tx_ptr_updated() {
604 trace!("TX POLL: Ready");
605 device.reset_tx_ptr_event();
606 device.enable_tx_ptr_interrupt();
607 Poll::Ready(())
608 } else {
609 trace!("TX POLL: Pending");
610 Poll::Pending
611 }
612 })
613 .await;
614
615 drop.defuse();
616 }
617
618 async fn receive_from_ram<S>(buffer_ptr: *mut [S]) -> Result<(), Error>
619 where
620 S: Sample,
621 {
622 trace!("RECEIVE: {}", buffer_ptr as *const S as u32);
623
624 // NOTE: RAM slice check for rx is not necessary, as a mutable
625 // slice can only be built from data located in RAM.
626
627 compiler_fence(Ordering::SeqCst);
628
629 let device = Device::<T>::new();
630
631 device.update_rx(buffer_ptr)?;
632
633 Self::wait_rx_ptr_update().await;
634
635 compiler_fence(Ordering::SeqCst);
636
637 Ok(())
638 }
639
640 async fn wait_rx_ptr_update() {
641 let drop = OnDrop::new(move || {
642 trace!("RX DROP: Stopping");
643
644 let device = Device::<T>::new();
645 device.disable_rx_ptr_interrupt();
646 device.reset_rx_ptr_event();
647 device.disable_rx();
648
649 // TX is stopped almost instantly, spinning is fine.
650 while !device.is_rx_ptr_updated() {}
651
652 trace!("RX DROP: Stopped");
653 });
654
655 poll_fn(|cx| {
656 T::state().rx_waker.register(cx.waker());
657
658 let device = Device::<T>::new();
659 if device.is_rx_ptr_updated() {
660 trace!("RX POLL: Ready");
661 device.reset_rx_ptr_event();
662 device.enable_rx_ptr_interrupt();
663 Poll::Ready(())
664 } else {
665 trace!("RX POLL: Pending");
666 Poll::Pending
667 }
668 })
669 .await;
670
671 drop.defuse();
672 }
673}
674
675/// I2S output
676pub struct OutputStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> {
677 _p: PeripheralRef<'d, T>,
678 buffers: MultiBuffering<S, NB, NS>,
679}
680
681impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream<'d, T, S, NB, NS> {
682 /// Get a mutable reference to the current buffer.
683 pub fn buffer(&mut self) -> &mut [S] {
684 self.buffers.get_mut()
685 }
686
687 /// Prepare the initial buffer and start the I2S transfer.
688 pub async fn start(&mut self) -> Result<(), Error>
689 where
690 S: Sample,
691 {
692 let device = Device::<T>::new();
693
694 let s = T::state();
695 if s.started.load(Ordering::Relaxed) {
696 self.stop().await;
697 }
698
699 device.enable();
700 device.enable_tx();
701
702 device.update_tx(self.buffers.switch())?;
703
704 s.started.store(true, Ordering::Relaxed);
705
706 device.start();
707
708 I2S::<T>::wait_tx_ptr_update().await;
709
710 Ok(())
711 }
712
713 /// Stops the I2S transfer and waits until it has stopped.
714 #[inline(always)]
715 pub async fn stop(&self) {
716 I2S::<T>::stop().await
717 }
718
719 /// Sends the current buffer for transmission in the DMA.
720 /// Switches to use the next available buffer.
721 pub async fn send(&mut self) -> Result<(), Error>
722 where
723 S: Sample,
724 {
725 I2S::<T>::send_from_ram(self.buffers.switch()).await
726 }
727}
728
729/// I2S input
730pub struct InputStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> {
731 _p: PeripheralRef<'d, T>,
732 buffers: MultiBuffering<S, NB, NS>,
733}
734
735impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<'d, T, S, NB, NS> {
736 /// Get a mutable reference to the current buffer.
737 pub fn buffer(&mut self) -> &mut [S] {
738 self.buffers.get_mut()
739 }
740
741 /// Prepare the initial buffer and start the I2S transfer.
742 pub async fn start(&mut self) -> Result<(), Error>
743 where
744 S: Sample,
745 {
746 let device = Device::<T>::new();
747
748 let s = T::state();
749 if s.started.load(Ordering::Relaxed) {
750 self.stop().await;
751 }
752
753 device.enable();
754 device.enable_rx();
755
756 device.update_rx(self.buffers.switch())?;
757
758 s.started.store(true, Ordering::Relaxed);
759
760 device.start();
761
762 I2S::<T>::wait_rx_ptr_update().await;
763
764 Ok(())
765 }
766
767 /// Stops the I2S transfer and waits until it has stopped.
768 #[inline(always)]
769 pub async fn stop(&self) {
770 I2S::<T>::stop().await
771 }
772
773 /// Sets the current buffer for reception from the DMA.
774 /// Switches to use the next available buffer.
775 #[allow(unused_mut)]
776 pub async fn receive(&mut self) -> Result<(), Error>
777 where
778 S: Sample,
779 {
780 I2S::<T>::receive_from_ram(self.buffers.switch_mut()).await
781 }
782}
783
784/// I2S full duplex stream (input & output)
785pub struct FullDuplexStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> {
786 _p: PeripheralRef<'d, T>,
787 buffers_out: MultiBuffering<S, NB, NS>,
788 buffers_in: MultiBuffering<S, NB, NS>,
789}
790
791impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStream<'d, T, S, NB, NS> {
792 /// Get the current output and input buffers.
793 pub fn buffers(&mut self) -> (&mut [S], &[S]) {
794 (self.buffers_out.get_mut(), self.buffers_in.get())
795 }
796
797 /// Prepare the initial buffers and start the I2S transfer.
798 pub async fn start(&mut self) -> Result<(), Error>
799 where
800 S: Sample,
801 {
802 let device = Device::<T>::new();
803
804 let s = T::state();
805 if s.started.load(Ordering::Relaxed) {
806 self.stop().await;
807 }
808
809 device.enable();
810 device.enable_tx();
811 device.enable_rx();
812
813 device.update_tx(self.buffers_out.switch())?;
814 device.update_rx(self.buffers_in.switch_mut())?;
815
816 s.started.store(true, Ordering::Relaxed);
817
818 device.start();
819
820 I2S::<T>::wait_tx_ptr_update().await;
821 I2S::<T>::wait_rx_ptr_update().await;
822
823 Ok(())
824 }
825
826 /// Stops the I2S transfer and waits until it has stopped.
827 #[inline(always)]
828 pub async fn stop(&self) {
829 I2S::<T>::stop().await
830 }
831
832 /// Sets the current buffers for output and input for transmission/reception from the DMA.
833 /// Switch to use the next available buffers for output/input.
834 pub async fn send_and_receive(&mut self) -> Result<(), Error>
835 where
836 S: Sample,
837 {
838 I2S::<T>::send_from_ram(self.buffers_out.switch()).await?;
839 I2S::<T>::receive_from_ram(self.buffers_in.switch_mut()).await?;
840 Ok(())
841 }
842}
843
844/// Helper encapsulating common I2S device operations.
845struct Device<T>(&'static RegisterBlock, PhantomData<T>);
846
847impl<T: Instance> Device<T> {
848 fn new() -> Self {
849 Self(T::regs(), PhantomData)
850 }
851
852 #[inline(always)]
853 pub fn enable(&self) {
854 trace!("ENABLED");
855 self.0.enable.write(|w| w.enable().enabled());
856 }
857
858 #[inline(always)]
859 pub fn disable(&self) {
860 trace!("DISABLED");
861 self.0.enable.write(|w| w.enable().disabled());
862 }
863
864 #[inline(always)]
865 fn enable_tx(&self) {
866 trace!("TX ENABLED");
867 self.0.config.txen.write(|w| w.txen().enabled());
868 }
869
870 #[inline(always)]
871 fn disable_tx(&self) {
872 trace!("TX DISABLED");
873 self.0.config.txen.write(|w| w.txen().disabled());
874 }
875
876 #[inline(always)]
877 fn enable_rx(&self) {
878 trace!("RX ENABLED");
879 self.0.config.rxen.write(|w| w.rxen().enabled());
880 }
881
882 #[inline(always)]
883 fn disable_rx(&self) {
884 trace!("RX DISABLED");
885 self.0.config.rxen.write(|w| w.rxen().disabled());
886 }
887
888 #[inline(always)]
889 fn start(&self) {
890 trace!("START");
891 self.0.tasks_start.write(|w| unsafe { w.bits(1) });
892 }
893
894 #[inline(always)]
895 fn stop(&self) {
896 self.0.tasks_stop.write(|w| unsafe { w.bits(1) });
897 }
898
899 #[inline(always)]
900 fn is_stopped(&self) -> bool {
901 self.0.events_stopped.read().bits() != 0
902 }
903
904 #[inline(always)]
905 fn reset_stopped_event(&self) {
906 trace!("STOPPED EVENT: Reset");
907 self.0.events_stopped.reset();
908 }
909
910 #[inline(always)]
911 fn disable_stopped_interrupt(&self) {
912 trace!("STOPPED INTERRUPT: Disabled");
913 self.0.intenclr.write(|w| w.stopped().clear());
914 }
915
916 #[inline(always)]
917 fn enable_stopped_interrupt(&self) {
918 trace!("STOPPED INTERRUPT: Enabled");
919 self.0.intenset.write(|w| w.stopped().set());
920 }
921
922 #[inline(always)]
923 fn reset_tx_ptr_event(&self) {
924 trace!("TX PTR EVENT: Reset");
925 self.0.events_txptrupd.reset();
926 }
927
928 #[inline(always)]
929 fn reset_rx_ptr_event(&self) {
930 trace!("RX PTR EVENT: Reset");
931 self.0.events_rxptrupd.reset();
932 }
933
934 #[inline(always)]
935 fn disable_tx_ptr_interrupt(&self) {
936 trace!("TX PTR INTERRUPT: Disabled");
937 self.0.intenclr.write(|w| w.txptrupd().clear());
938 }
939
940 #[inline(always)]
941 fn disable_rx_ptr_interrupt(&self) {
942 trace!("RX PTR INTERRUPT: Disabled");
943 self.0.intenclr.write(|w| w.rxptrupd().clear());
944 }
945
946 #[inline(always)]
947 fn enable_tx_ptr_interrupt(&self) {
948 trace!("TX PTR INTERRUPT: Enabled");
949 self.0.intenset.write(|w| w.txptrupd().set());
950 }
951
952 #[inline(always)]
953 fn enable_rx_ptr_interrupt(&self) {
954 trace!("RX PTR INTERRUPT: Enabled");
955 self.0.intenset.write(|w| w.rxptrupd().set());
956 }
957
958 #[inline(always)]
959 fn is_tx_ptr_updated(&self) -> bool {
960 self.0.events_txptrupd.read().bits() != 0
961 }
962
963 #[inline(always)]
964 fn is_rx_ptr_updated(&self) -> bool {
965 self.0.events_rxptrupd.read().bits() != 0
966 }
967
968 #[inline]
969 fn update_tx<S>(&self, buffer_ptr: *const [S]) -> Result<(), Error> {
970 let (ptr, maxcnt) = Self::validated_dma_parts(buffer_ptr)?;
971 self.0.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) });
972 self.0.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr) });
973 Ok(())
974 }
975
976 #[inline]
977 fn update_rx<S>(&self, buffer_ptr: *const [S]) -> Result<(), Error> {
978 let (ptr, maxcnt) = Self::validated_dma_parts(buffer_ptr)?;
979 self.0.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) });
980 self.0.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr) });
981 Ok(())
982 }
983
984 fn validated_dma_parts<S>(buffer_ptr: *const [S]) -> Result<(u32, u32), Error> {
985 let (ptr, len) = slice_ptr_parts(buffer_ptr);
986 let ptr = ptr as u32;
987 let bytes_len = len * size_of::<S>();
988 let maxcnt = (bytes_len / size_of::<u32>()) as u32;
989
990 trace!("PTR={}, MAXCNT={}", ptr, maxcnt);
991
992 if ptr % 4 != 0 {
993 Err(Error::BufferMisaligned)
994 } else if bytes_len % 4 != 0 {
995 Err(Error::BufferLengthMisaligned)
996 } else if maxcnt as usize > EASY_DMA_SIZE {
997 Err(Error::BufferTooLong)
998 } else {
999 Ok((ptr, maxcnt))
1000 }
1001 }
1002}
1003
1004/// Sample details
1005pub trait Sample: Sized + Copy + Default {
1006 const WIDTH: usize;
1007 const SCALE: Self;
1008}
1009
1010impl Sample for i8 {
1011 const WIDTH: usize = 8;
1012 const SCALE: Self = 1 << (Self::WIDTH - 1);
1013}
1014
1015impl Sample for i16 {
1016 const WIDTH: usize = 16;
1017 const SCALE: Self = 1 << (Self::WIDTH - 1);
1018}
1019
1020impl Sample for i32 {
1021 const WIDTH: usize = 24;
1022 const SCALE: Self = 1 << (Self::WIDTH - 1);
1023}
1024
1025/// A 4-bytes aligned buffer.
1026#[derive(Clone, Copy)]
1027#[repr(align(4))]
1028pub struct AlignedBuffer<T: Sample, const N: usize>([T; N]);
1029
1030impl<T: Sample, const N: usize> AlignedBuffer<T, N> {
1031 pub fn new(array: [T; N]) -> Self {
1032 Self(array)
1033 }
1034}
1035
1036impl<T: Sample, const N: usize> Default for AlignedBuffer<T, N> {
1037 fn default() -> Self {
1038 Self([T::default(); N])
1039 }
1040}
1041
1042impl<T: Sample, const N: usize> Deref for AlignedBuffer<T, N> {
1043 type Target = [T];
1044 fn deref(&self) -> &Self::Target {
1045 self.0.as_slice()
1046 }
1047}
1048
1049impl<T: Sample, const N: usize> DerefMut for AlignedBuffer<T, N> {
1050 fn deref_mut(&mut self) -> &mut Self::Target {
1051 self.0.as_mut_slice()
1052 }
1053}
1054
1055pub struct MultiBuffering<S: Sample, const NB: usize, const NS: usize> {
1056 buffers: [AlignedBuffer<S, NS>; NB],
1057 index: usize,
1058}
1059
1060impl<S: Sample, const NB: usize, const NS: usize> MultiBuffering<S, NB, NS> {
1061 pub fn new() -> Self {
1062 assert!(NB > 1);
1063 Self {
1064 buffers: [AlignedBuffer::<S, NS>::default(); NB],
1065 index: 0,
1066 }
1067 }
1068
1069 fn get(&self) -> &[S] {
1070 &self.buffers[self.index]
1071 }
1072
1073 fn get_mut(&mut self) -> &mut [S] {
1074 &mut self.buffers[self.index]
1075 }
1076
1077 /// Advance to use the next buffer and return a non mutable pointer to the previous one.
1078 fn switch(&mut self) -> *const [S] {
1079 let prev_index = self.index;
1080 self.index = (self.index + 1) % NB;
1081 self.buffers[prev_index].deref() as *const [S]
1082 }
1083
1084 /// Advance to use the next buffer and return a mutable pointer to the previous one.
1085 fn switch_mut(&mut self) -> *mut [S] {
1086 let prev_index = self.index;
1087 self.index = (self.index + 1) % NB;
1088 self.buffers[prev_index].deref_mut() as *mut [S]
1089 }
1090}
1091
1092pub(crate) mod sealed {
1093 use core::sync::atomic::AtomicBool;
1094
1095 use embassy_sync::waitqueue::AtomicWaker;
1096
1097 /// Peripheral static state
1098 pub struct State {
1099 pub started: AtomicBool,
1100 pub rx_waker: AtomicWaker,
1101 pub tx_waker: AtomicWaker,
1102 pub stop_waker: AtomicWaker,
1103 }
1104
1105 impl State {
1106 pub const fn new() -> Self {
1107 Self {
1108 started: AtomicBool::new(false),
1109 rx_waker: AtomicWaker::new(),
1110 tx_waker: AtomicWaker::new(),
1111 stop_waker: AtomicWaker::new(),
1112 }
1113 }
1114 }
1115
1116 pub trait Instance {
1117 fn regs() -> &'static crate::pac::i2s::RegisterBlock;
1118 fn state() -> &'static State;
1119 }
1120}
1121
1122pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
1123 type Interrupt: Interrupt;
1124}
1125
1126macro_rules! impl_i2s {
1127 ($type:ident, $pac_type:ident, $irq:ident) => {
1128 impl crate::i2s::sealed::Instance for peripherals::$type {
1129 fn regs() -> &'static crate::pac::i2s::RegisterBlock {
1130 unsafe { &*pac::$pac_type::ptr() }
1131 }
1132 fn state() -> &'static crate::i2s::sealed::State {
1133 static STATE: crate::i2s::sealed::State = crate::i2s::sealed::State::new();
1134 &STATE
1135 }
1136 }
1137 impl crate::i2s::Instance for peripherals::$type {
1138 type Interrupt = crate::interrupt::$irq;
1139 }
1140 };
1141}
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index cac55071c..1dd0e7905 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -43,7 +43,11 @@
43//! mutable slices always reside in RAM. 43//! mutable slices always reside in RAM.
44 44
45#![no_std] 45#![no_std]
46#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))] 46#![cfg_attr(
47 feature = "nightly",
48 feature(type_alias_impl_trait, async_fn_in_trait, impl_trait_projections)
49)]
50#![cfg_attr(feature = "nightly", allow(incomplete_features))]
47 51
48#[cfg(not(any( 52#[cfg(not(any(
49 feature = "nrf51", 53 feature = "nrf51",
@@ -74,6 +78,8 @@ pub mod buffered_uarte;
74pub mod gpio; 78pub mod gpio;
75#[cfg(feature = "gpiote")] 79#[cfg(feature = "gpiote")]
76pub mod gpiote; 80pub mod gpiote;
81#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
82pub mod i2s;
77pub mod nvmc; 83pub mod nvmc;
78#[cfg(any( 84#[cfg(any(
79 feature = "nrf52810", 85 feature = "nrf52810",
@@ -95,10 +101,12 @@ pub mod rng;
95#[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))] 101#[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))]
96pub mod saadc; 102pub mod saadc;
97pub mod spim; 103pub mod spim;
104pub mod spis;
98#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 105#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
99pub mod temp; 106pub mod temp;
100pub mod timer; 107pub mod timer;
101pub mod twim; 108pub mod twim;
109pub mod twis;
102pub mod uarte; 110pub mod uarte;
103#[cfg(any( 111#[cfg(any(
104 feature = "_nrf5340-app", 112 feature = "_nrf5340-app",
@@ -266,5 +274,12 @@ pub fn init(config: config::Config) -> Peripherals {
266 #[cfg(feature = "_time-driver")] 274 #[cfg(feature = "_time-driver")]
267 time_driver::init(config.time_interrupt_priority); 275 time_driver::init(config.time_interrupt_priority);
268 276
277 // Disable UARTE (enabled by default for some reason)
278 #[cfg(feature = "_nrf9160")]
279 unsafe {
280 (*pac::UARTE0::ptr()).enable.write(|w| w.enable().disabled());
281 (*pac::UARTE1::ptr()).enable.write(|w| w.enable().disabled());
282 }
283
269 peripherals 284 peripherals
270} 285}
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index d821d2353..7bb4e39f7 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -477,45 +477,34 @@ mod eh1 {
477 477
478#[cfg(all(feature = "unstable-traits", feature = "nightly"))] 478#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
479mod eha { 479mod eha {
480 use core::future::Future;
481 480
482 use super::*; 481 use super::*;
483 482
484 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusFlush for Spim<'d, T> { 483 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusFlush for Spim<'d, T> {
485 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 484 async fn flush(&mut self) -> Result<(), Error> {
486 485 Ok(())
487 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
488 async move { Ok(()) }
489 } 486 }
490 } 487 }
491 488
492 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusRead<u8> for Spim<'d, T> { 489 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusRead<u8> for Spim<'d, T> {
493 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 490 async fn read(&mut self, words: &mut [u8]) -> Result<(), Error> {
494 491 self.read(words).await
495 fn read<'a>(&'a mut self, words: &'a mut [u8]) -> Self::ReadFuture<'a> {
496 self.read(words)
497 } 492 }
498 } 493 }
499 494
500 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusWrite<u8> for Spim<'d, T> { 495 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusWrite<u8> for Spim<'d, T> {
501 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 496 async fn write(&mut self, data: &[u8]) -> Result<(), Error> {
502 497 self.write(data).await
503 fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> {
504 self.write(data)
505 } 498 }
506 } 499 }
507 500
508 impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spim<'d, T> { 501 impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spim<'d, T> {
509 type TransferFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 502 async fn transfer(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> {
510 503 self.transfer(rx, tx).await
511 fn transfer<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::TransferFuture<'a> {
512 self.transfer(rx, tx)
513 } 504 }
514 505
515 type TransferInPlaceFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 506 async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> {
516 507 self.transfer_in_place(words).await
517 fn transfer_in_place<'a>(&'a mut self, words: &'a mut [u8]) -> Self::TransferInPlaceFuture<'a> {
518 self.transfer_in_place(words)
519 } 508 }
520 } 509 }
521} 510}
diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs
new file mode 100644
index 000000000..44af61a19
--- /dev/null
+++ b/embassy-nrf/src/spis.rs
@@ -0,0 +1,539 @@
1#![macro_use]
2use core::future::poll_fn;
3use core::sync::atomic::{compiler_fence, Ordering};
4use core::task::Poll;
5
6use embassy_embedded_hal::SetConfig;
7use embassy_hal_common::{into_ref, PeripheralRef};
8pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
9
10use crate::chip::FORCE_COPY_BUFFER_SIZE;
11use crate::gpio::sealed::Pin as _;
12use crate::gpio::{self, AnyPin, Pin as GpioPin};
13use crate::interrupt::{Interrupt, InterruptExt};
14use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
15use crate::{pac, Peripheral};
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18#[cfg_attr(feature = "defmt", derive(defmt::Format))]
19#[non_exhaustive]
20pub enum Error {
21 TxBufferTooLong,
22 RxBufferTooLong,
23 /// EasyDMA can only read from data memory, read only buffers in flash will fail.
24 DMABufferNotInDataMemory,
25}
26
27/// Interface for the SPIS peripheral using EasyDMA to offload the transmission and reception workload.
28///
29/// For more details about EasyDMA, consult the module documentation.
30pub struct Spis<'d, T: Instance> {
31 _p: PeripheralRef<'d, T>,
32}
33
34#[non_exhaustive]
35pub struct Config {
36 pub mode: Mode,
37 pub orc: u8,
38 pub def: u8,
39 pub auto_acquire: bool,
40}
41
42impl Default for Config {
43 fn default() -> Self {
44 Self {
45 mode: MODE_0,
46 orc: 0x00,
47 def: 0x00,
48 auto_acquire: true,
49 }
50 }
51}
52
53impl<'d, T: Instance> Spis<'d, T> {
54 pub fn new(
55 spis: impl Peripheral<P = T> + 'd,
56 irq: impl Peripheral<P = T::Interrupt> + 'd,
57 cs: impl Peripheral<P = impl GpioPin> + 'd,
58 sck: impl Peripheral<P = impl GpioPin> + 'd,
59 miso: impl Peripheral<P = impl GpioPin> + 'd,
60 mosi: impl Peripheral<P = impl GpioPin> + 'd,
61 config: Config,
62 ) -> Self {
63 into_ref!(cs, sck, miso, mosi);
64 Self::new_inner(
65 spis,
66 irq,
67 cs.map_into(),
68 sck.map_into(),
69 Some(miso.map_into()),
70 Some(mosi.map_into()),
71 config,
72 )
73 }
74
75 pub fn new_txonly(
76 spis: impl Peripheral<P = T> + 'd,
77 irq: impl Peripheral<P = T::Interrupt> + 'd,
78 cs: impl Peripheral<P = impl GpioPin> + 'd,
79 sck: impl Peripheral<P = impl GpioPin> + 'd,
80 miso: impl Peripheral<P = impl GpioPin> + 'd,
81 config: Config,
82 ) -> Self {
83 into_ref!(cs, sck, miso);
84 Self::new_inner(
85 spis,
86 irq,
87 cs.map_into(),
88 sck.map_into(),
89 Some(miso.map_into()),
90 None,
91 config,
92 )
93 }
94
95 pub fn new_rxonly(
96 spis: impl Peripheral<P = T> + 'd,
97 irq: impl Peripheral<P = T::Interrupt> + 'd,
98 cs: impl Peripheral<P = impl GpioPin> + 'd,
99 sck: impl Peripheral<P = impl GpioPin> + 'd,
100 mosi: impl Peripheral<P = impl GpioPin> + 'd,
101 config: Config,
102 ) -> Self {
103 into_ref!(cs, sck, mosi);
104 Self::new_inner(
105 spis,
106 irq,
107 cs.map_into(),
108 sck.map_into(),
109 None,
110 Some(mosi.map_into()),
111 config,
112 )
113 }
114
115 fn new_inner(
116 spis: impl Peripheral<P = T> + 'd,
117 irq: impl Peripheral<P = T::Interrupt> + 'd,
118 cs: PeripheralRef<'d, AnyPin>,
119 sck: PeripheralRef<'d, AnyPin>,
120 miso: Option<PeripheralRef<'d, AnyPin>>,
121 mosi: Option<PeripheralRef<'d, AnyPin>>,
122 config: Config,
123 ) -> Self {
124 compiler_fence(Ordering::SeqCst);
125
126 into_ref!(spis, irq, cs, sck);
127
128 let r = T::regs();
129
130 // Configure pins.
131 sck.conf().write(|w| w.input().connect().drive().h0h1());
132 r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) });
133 cs.conf().write(|w| w.input().connect().drive().h0h1());
134 r.psel.csn.write(|w| unsafe { w.bits(cs.psel_bits()) });
135 if let Some(mosi) = &mosi {
136 mosi.conf().write(|w| w.input().connect().drive().h0h1());
137 r.psel.mosi.write(|w| unsafe { w.bits(mosi.psel_bits()) });
138 }
139 if let Some(miso) = &miso {
140 miso.conf().write(|w| w.dir().output().drive().h0h1());
141 r.psel.miso.write(|w| unsafe { w.bits(miso.psel_bits()) });
142 }
143
144 // Enable SPIS instance.
145 r.enable.write(|w| w.enable().enabled());
146
147 // Configure mode.
148 let mode = config.mode;
149 r.config.write(|w| {
150 match mode {
151 MODE_0 => {
152 w.order().msb_first();
153 w.cpol().active_high();
154 w.cpha().leading();
155 }
156 MODE_1 => {
157 w.order().msb_first();
158 w.cpol().active_high();
159 w.cpha().trailing();
160 }
161 MODE_2 => {
162 w.order().msb_first();
163 w.cpol().active_low();
164 w.cpha().leading();
165 }
166 MODE_3 => {
167 w.order().msb_first();
168 w.cpol().active_low();
169 w.cpha().trailing();
170 }
171 }
172
173 w
174 });
175
176 // Set over-read character.
177 let orc = config.orc;
178 r.orc.write(|w| unsafe { w.orc().bits(orc) });
179
180 // Set default character.
181 let def = config.def;
182 r.def.write(|w| unsafe { w.def().bits(def) });
183
184 // Configure auto-acquire on 'transfer end' event.
185 if config.auto_acquire {
186 r.shorts.write(|w| w.end_acquire().bit(true));
187 }
188
189 // Disable all events interrupts.
190 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
191
192 irq.set_handler(Self::on_interrupt);
193 irq.unpend();
194 irq.enable();
195
196 Self { _p: spis }
197 }
198
199 fn on_interrupt(_: *mut ()) {
200 let r = T::regs();
201 let s = T::state();
202
203 if r.events_end.read().bits() != 0 {
204 s.waker.wake();
205 r.intenclr.write(|w| w.end().clear());
206 }
207
208 if r.events_acquired.read().bits() != 0 {
209 s.waker.wake();
210 r.intenclr.write(|w| w.acquired().clear());
211 }
212 }
213
214 fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
215 slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?;
216 // NOTE: RAM slice check for rx is not necessary, as a mutable
217 // slice can only be built from data located in RAM.
218
219 compiler_fence(Ordering::SeqCst);
220
221 let r = T::regs();
222
223 // Set up the DMA write.
224 let (ptr, len) = slice_ptr_parts(tx);
225 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
226 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
227
228 // Set up the DMA read.
229 let (ptr, len) = slice_ptr_parts_mut(rx);
230 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
231 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
232
233 // Reset end event.
234 r.events_end.reset();
235
236 // Release the semaphore.
237 r.tasks_release.write(|w| unsafe { w.bits(1) });
238
239 Ok(())
240 }
241
242 fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(usize, usize), Error> {
243 compiler_fence(Ordering::SeqCst);
244 let r = T::regs();
245
246 // Acquire semaphore.
247 if r.semstat.read().bits() != 1 {
248 r.events_acquired.reset();
249 r.tasks_acquire.write(|w| unsafe { w.bits(1) });
250 // Wait until CPU has acquired the semaphore.
251 while r.semstat.read().bits() != 1 {}
252 }
253
254 self.prepare(rx, tx)?;
255
256 // Wait for 'end' event.
257 while r.events_end.read().bits() == 0 {}
258
259 let n_rx = r.rxd.amount.read().bits() as usize;
260 let n_tx = r.txd.amount.read().bits() as usize;
261
262 compiler_fence(Ordering::SeqCst);
263
264 Ok((n_rx, n_tx))
265 }
266
267 fn blocking_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(usize, usize), Error> {
268 match self.blocking_inner_from_ram(rx, tx) {
269 Ok(n) => Ok(n),
270 Err(Error::DMABufferNotInDataMemory) => {
271 trace!("Copying SPIS tx buffer into RAM for DMA");
272 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()];
273 tx_ram_buf.copy_from_slice(tx);
274 self.blocking_inner_from_ram(rx, tx_ram_buf)
275 }
276 Err(error) => Err(error),
277 }
278 }
279
280 async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(usize, usize), Error> {
281 let r = T::regs();
282 let s = T::state();
283
284 // Clear status register.
285 r.status.write(|w| w.overflow().clear().overread().clear());
286
287 // Acquire semaphore.
288 if r.semstat.read().bits() != 1 {
289 // Reset and enable the acquire event.
290 r.events_acquired.reset();
291 r.intenset.write(|w| w.acquired().set());
292
293 // Request acquiring the SPIS semaphore.
294 r.tasks_acquire.write(|w| unsafe { w.bits(1) });
295
296 // Wait until CPU has acquired the semaphore.
297 poll_fn(|cx| {
298 s.waker.register(cx.waker());
299 if r.events_acquired.read().bits() == 1 {
300 r.events_acquired.reset();
301 return Poll::Ready(());
302 }
303 Poll::Pending
304 })
305 .await;
306 }
307
308 self.prepare(rx, tx)?;
309
310 // Wait for 'end' event.
311 r.intenset.write(|w| w.end().set());
312 poll_fn(|cx| {
313 s.waker.register(cx.waker());
314 if r.events_end.read().bits() != 0 {
315 r.events_end.reset();
316 return Poll::Ready(());
317 }
318 Poll::Pending
319 })
320 .await;
321
322 let n_rx = r.rxd.amount.read().bits() as usize;
323 let n_tx = r.txd.amount.read().bits() as usize;
324
325 compiler_fence(Ordering::SeqCst);
326
327 Ok((n_rx, n_tx))
328 }
329
330 async fn async_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(usize, usize), Error> {
331 match self.async_inner_from_ram(rx, tx).await {
332 Ok(n) => Ok(n),
333 Err(Error::DMABufferNotInDataMemory) => {
334 trace!("Copying SPIS tx buffer into RAM for DMA");
335 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()];
336 tx_ram_buf.copy_from_slice(tx);
337 self.async_inner_from_ram(rx, tx_ram_buf).await
338 }
339 Err(error) => Err(error),
340 }
341 }
342
343 /// Reads data from the SPI bus without sending anything. Blocks until `cs` is deasserted.
344 /// Returns number of bytes read.
345 pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<usize, Error> {
346 self.blocking_inner(data, &[]).map(|n| n.0)
347 }
348
349 /// Simultaneously sends and receives data. Blocks until the transmission is completed.
350 /// If necessary, the write buffer will be copied into RAM (see struct description for detail).
351 /// Returns number of bytes transferred `(n_rx, n_tx)`.
352 pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(usize, usize), Error> {
353 self.blocking_inner(read, write)
354 }
355
356 /// Same as [`blocking_transfer`](Spis::blocking_transfer) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
357 /// Returns number of bytes transferred `(n_rx, n_tx)`.
358 pub fn blocking_transfer_from_ram(&mut self, read: &mut [u8], write: &[u8]) -> Result<(usize, usize), Error> {
359 self.blocking_inner_from_ram(read, write)
360 }
361
362 /// Simultaneously sends and receives data.
363 /// Places the received data into the same buffer and blocks until the transmission is completed.
364 /// Returns number of bytes transferred.
365 pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<usize, Error> {
366 self.blocking_inner_from_ram(data, data).map(|n| n.0)
367 }
368
369 /// Sends data, discarding any received data. Blocks until the transmission is completed.
370 /// If necessary, the write buffer will be copied into RAM (see struct description for detail).
371 /// Returns number of bytes written.
372 pub fn blocking_write(&mut self, data: &[u8]) -> Result<usize, Error> {
373 self.blocking_inner(&mut [], data).map(|n| n.1)
374 }
375
376 /// Same as [`blocking_write`](Spis::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
377 /// Returns number of bytes written.
378 pub fn blocking_write_from_ram(&mut self, data: &[u8]) -> Result<usize, Error> {
379 self.blocking_inner_from_ram(&mut [], data).map(|n| n.1)
380 }
381
382 /// Reads data from the SPI bus without sending anything.
383 /// Returns number of bytes read.
384 pub async fn read(&mut self, data: &mut [u8]) -> Result<usize, Error> {
385 self.async_inner(data, &[]).await.map(|n| n.0)
386 }
387
388 /// Simultaneously sends and receives data.
389 /// If necessary, the write buffer will be copied into RAM (see struct description for detail).
390 /// Returns number of bytes transferred `(n_rx, n_tx)`.
391 pub async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(usize, usize), Error> {
392 self.async_inner(read, write).await
393 }
394
395 /// Same as [`transfer`](Spis::transfer) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
396 /// Returns number of bytes transferred `(n_rx, n_tx)`.
397 pub async fn transfer_from_ram(&mut self, read: &mut [u8], write: &[u8]) -> Result<(usize, usize), Error> {
398 self.async_inner_from_ram(read, write).await
399 }
400
401 /// Simultaneously sends and receives data. Places the received data into the same buffer.
402 /// Returns number of bytes transferred.
403 pub async fn transfer_in_place(&mut self, data: &mut [u8]) -> Result<usize, Error> {
404 self.async_inner_from_ram(data, data).await.map(|n| n.0)
405 }
406
407 /// Sends data, discarding any received data.
408 /// If necessary, the write buffer will be copied into RAM (see struct description for detail).
409 /// Returns number of bytes written.
410 pub async fn write(&mut self, data: &[u8]) -> Result<usize, Error> {
411 self.async_inner(&mut [], data).await.map(|n| n.1)
412 }
413
414 /// Same as [`write`](Spis::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
415 /// Returns number of bytes written.
416 pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<usize, Error> {
417 self.async_inner_from_ram(&mut [], data).await.map(|n| n.1)
418 }
419
420 /// Checks if last transaction overread.
421 pub fn is_overread(&mut self) -> bool {
422 T::regs().status.read().overread().is_present()
423 }
424
425 /// Checks if last transaction overflowed.
426 pub fn is_overflow(&mut self) -> bool {
427 T::regs().status.read().overflow().is_present()
428 }
429}
430
431impl<'d, T: Instance> Drop for Spis<'d, T> {
432 fn drop(&mut self) {
433 trace!("spis drop");
434
435 // Disable
436 let r = T::regs();
437 r.enable.write(|w| w.enable().disabled());
438
439 gpio::deconfigure_pin(r.psel.sck.read().bits());
440 gpio::deconfigure_pin(r.psel.csn.read().bits());
441 gpio::deconfigure_pin(r.psel.miso.read().bits());
442 gpio::deconfigure_pin(r.psel.mosi.read().bits());
443
444 trace!("spis drop: done");
445 }
446}
447
448pub(crate) mod sealed {
449 use embassy_sync::waitqueue::AtomicWaker;
450
451 use super::*;
452
453 pub struct State {
454 pub waker: AtomicWaker,
455 }
456
457 impl State {
458 pub const fn new() -> Self {
459 Self {
460 waker: AtomicWaker::new(),
461 }
462 }
463 }
464
465 pub trait Instance {
466 fn regs() -> &'static pac::spis0::RegisterBlock;
467 fn state() -> &'static State;
468 }
469}
470
471pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
472 type Interrupt: Interrupt;
473}
474
475macro_rules! impl_spis {
476 ($type:ident, $pac_type:ident, $irq:ident) => {
477 impl crate::spis::sealed::Instance for peripherals::$type {
478 fn regs() -> &'static pac::spis0::RegisterBlock {
479 unsafe { &*pac::$pac_type::ptr() }
480 }
481 fn state() -> &'static crate::spis::sealed::State {
482 static STATE: crate::spis::sealed::State = crate::spis::sealed::State::new();
483 &STATE
484 }
485 }
486 impl crate::spis::Instance for peripherals::$type {
487 type Interrupt = crate::interrupt::$irq;
488 }
489 };
490}
491
492// ====================
493
494impl<'d, T: Instance> SetConfig for Spis<'d, T> {
495 type Config = Config;
496 fn set_config(&mut self, config: &Self::Config) {
497 let r = T::regs();
498 // Configure mode.
499 let mode = config.mode;
500 r.config.write(|w| {
501 match mode {
502 MODE_0 => {
503 w.order().msb_first();
504 w.cpol().active_high();
505 w.cpha().leading();
506 }
507 MODE_1 => {
508 w.order().msb_first();
509 w.cpol().active_high();
510 w.cpha().trailing();
511 }
512 MODE_2 => {
513 w.order().msb_first();
514 w.cpol().active_low();
515 w.cpha().leading();
516 }
517 MODE_3 => {
518 w.order().msb_first();
519 w.cpol().active_low();
520 w.cpha().trailing();
521 }
522 }
523
524 w
525 });
526
527 // Set over-read character.
528 let orc = config.orc;
529 r.orc.write(|w| unsafe { w.orc().bits(orc) });
530
531 // Set default character.
532 let def = config.def;
533 r.def.write(|w| unsafe { w.def().bits(def) });
534
535 // Configure auto-acquire on 'transfer end' event.
536 let auto_acquire = config.auto_acquire;
537 r.shorts.write(|w| w.end_acquire().bit(auto_acquire));
538 }
539}
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index 8d6171fac..4eafd18c2 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -841,39 +841,31 @@ mod eh1 {
841mod eha { 841mod eha {
842 use super::*; 842 use super::*;
843 impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> { 843 impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> {
844 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 844 async fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Result<(), Error> {
845 845 self.read(address, buffer).await
846 fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
847 self.read(address, buffer)
848 } 846 }
849 847
850 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 848 async fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Result<(), Error> {
851 849 self.write(address, bytes).await
852 fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> {
853 self.write(address, bytes)
854 } 850 }
855 851
856 type WriteReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 852 async fn write_read<'a>(
857
858 fn write_read<'a>(
859 &'a mut self, 853 &'a mut self,
860 address: u8, 854 address: u8,
861 wr_buffer: &'a [u8], 855 wr_buffer: &'a [u8],
862 rd_buffer: &'a mut [u8], 856 rd_buffer: &'a mut [u8],
863 ) -> Self::WriteReadFuture<'a> { 857 ) -> Result<(), Error> {
864 self.write_read(address, wr_buffer, rd_buffer) 858 self.write_read(address, wr_buffer, rd_buffer).await
865 } 859 }
866 860
867 type TransactionFuture<'a, 'b> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a, 'b: 'a; 861 async fn transaction<'a, 'b>(
868
869 fn transaction<'a, 'b>(
870 &'a mut self, 862 &'a mut self,
871 address: u8, 863 address: u8,
872 operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], 864 operations: &'a mut [embedded_hal_async::i2c::Operation<'b>],
873 ) -> Self::TransactionFuture<'a, 'b> { 865 ) -> Result<(), Error> {
874 let _ = address; 866 let _ = address;
875 let _ = operations; 867 let _ = operations;
876 async move { todo!() } 868 todo!()
877 } 869 }
878 } 870 }
879} 871}
diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs
new file mode 100644
index 000000000..4091b017e
--- /dev/null
+++ b/embassy-nrf/src/twis.rs
@@ -0,0 +1,759 @@
1#![macro_use]
2
3//! HAL interface to the TWIS peripheral.
4//!
5//! See product specification:
6//!
7//! - nRF52832: Section 33
8//! - nRF52840: Section 6.31
9use core::future::{poll_fn, Future};
10use core::sync::atomic::compiler_fence;
11use core::sync::atomic::Ordering::SeqCst;
12use core::task::Poll;
13
14use embassy_hal_common::{into_ref, PeripheralRef};
15use embassy_sync::waitqueue::AtomicWaker;
16#[cfg(feature = "time")]
17use embassy_time::{Duration, Instant};
18
19use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
20use crate::gpio::Pin as GpioPin;
21use crate::interrupt::{Interrupt, InterruptExt};
22use crate::util::slice_in_ram_or;
23use crate::{gpio, pac, Peripheral};
24
25#[non_exhaustive]
26pub struct Config {
27 pub address0: u8,
28 pub address1: Option<u8>,
29 pub orc: u8,
30 pub sda_high_drive: bool,
31 pub sda_pullup: bool,
32 pub scl_high_drive: bool,
33 pub scl_pullup: bool,
34}
35
36impl Default for Config {
37 fn default() -> Self {
38 Self {
39 address0: 0x55,
40 address1: None,
41 orc: 0x00,
42 scl_high_drive: false,
43 sda_pullup: false,
44 sda_high_drive: false,
45 scl_pullup: false,
46 }
47 }
48}
49
50#[derive(Debug, Copy, Clone, Eq, PartialEq)]
51#[cfg_attr(feature = "defmt", derive(defmt::Format))]
52enum Status {
53 Read,
54 Write,
55}
56
57#[derive(Debug, Copy, Clone, Eq, PartialEq)]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59#[non_exhaustive]
60pub enum Error {
61 TxBufferTooLong,
62 RxBufferTooLong,
63 DataNack,
64 Bus,
65 DMABufferNotInDataMemory,
66 Overflow,
67 OverRead,
68 Timeout,
69}
70
71#[derive(Debug, Copy, Clone, Eq, PartialEq)]
72#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73pub enum Command {
74 Read,
75 WriteRead(usize),
76 Write(usize),
77}
78
79/// Interface to a TWIS instance using EasyDMA to offload the transmission and reception workload.
80///
81/// For more details about EasyDMA, consult the module documentation.
82pub struct Twis<'d, T: Instance> {
83 _p: PeripheralRef<'d, T>,
84}
85
86impl<'d, T: Instance> Twis<'d, T> {
87 pub fn new(
88 twis: impl Peripheral<P = T> + 'd,
89 irq: impl Peripheral<P = T::Interrupt> + 'd,
90 sda: impl Peripheral<P = impl GpioPin> + 'd,
91 scl: impl Peripheral<P = impl GpioPin> + 'd,
92 config: Config,
93 ) -> Self {
94 into_ref!(twis, irq, sda, scl);
95
96 let r = T::regs();
97
98 // Configure pins
99 sda.conf().write(|w| {
100 w.dir().input();
101 w.input().connect();
102 if config.sda_high_drive {
103 w.drive().h0d1();
104 } else {
105 w.drive().s0d1();
106 }
107 if config.sda_pullup {
108 w.pull().pullup();
109 }
110 w
111 });
112 scl.conf().write(|w| {
113 w.dir().input();
114 w.input().connect();
115 if config.scl_high_drive {
116 w.drive().h0d1();
117 } else {
118 w.drive().s0d1();
119 }
120 if config.scl_pullup {
121 w.pull().pullup();
122 }
123 w
124 });
125
126 // Select pins.
127 r.psel.sda.write(|w| unsafe { w.bits(sda.psel_bits()) });
128 r.psel.scl.write(|w| unsafe { w.bits(scl.psel_bits()) });
129
130 // Enable TWIS instance.
131 r.enable.write(|w| w.enable().enabled());
132
133 // Disable all events interrupts
134 r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
135
136 // Set address
137 r.address[0].write(|w| unsafe { w.address().bits(config.address0) });
138 r.config.write(|w| w.address0().enabled());
139 if let Some(address1) = config.address1 {
140 r.address[1].write(|w| unsafe { w.address().bits(address1) });
141 r.config.modify(|_r, w| w.address1().enabled());
142 }
143
144 // Set over-read character
145 r.orc.write(|w| unsafe { w.orc().bits(config.orc) });
146
147 // Generate suspend on read event
148 r.shorts.write(|w| w.read_suspend().enabled());
149
150 irq.set_handler(Self::on_interrupt);
151 irq.unpend();
152 irq.enable();
153
154 Self { _p: twis }
155 }
156
157 fn on_interrupt(_: *mut ()) {
158 let r = T::regs();
159 let s = T::state();
160
161 if r.events_read.read().bits() != 0 || r.events_write.read().bits() != 0 {
162 s.waker.wake();
163 r.intenclr.modify(|_r, w| w.read().clear().write().clear());
164 }
165 if r.events_stopped.read().bits() != 0 {
166 s.waker.wake();
167 r.intenclr.modify(|_r, w| w.stopped().clear());
168 }
169 if r.events_error.read().bits() != 0 {
170 s.waker.wake();
171 r.intenclr.modify(|_r, w| w.error().clear());
172 }
173 }
174
175 /// Set TX buffer, checking that it is in RAM and has suitable length.
176 unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
177 slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?;
178
179 if buffer.len() > EASY_DMA_SIZE {
180 return Err(Error::TxBufferTooLong);
181 }
182
183 let r = T::regs();
184
185 r.txd.ptr.write(|w|
186 // We're giving the register a pointer to the stack. Since we're
187 // waiting for the I2C transaction to end before this stack pointer
188 // becomes invalid, there's nothing wrong here.
189 //
190 // The PTR field is a full 32 bits wide and accepts the full range
191 // of values.
192 w.ptr().bits(buffer.as_ptr() as u32));
193 r.txd.maxcnt.write(|w|
194 // We're giving it the length of the buffer, so no danger of
195 // accessing invalid memory. We have verified that the length of the
196 // buffer fits in an `u8`, so the cast to `u8` is also fine.
197 //
198 // The MAXCNT field is 8 bits wide and accepts the full range of
199 // values.
200 w.maxcnt().bits(buffer.len() as _));
201
202 Ok(())
203 }
204
205 /// Set RX buffer, checking that it has suitable length.
206 unsafe fn set_rx_buffer(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
207 // NOTE: RAM slice check is not necessary, as a mutable
208 // slice can only be built from data located in RAM.
209
210 if buffer.len() > EASY_DMA_SIZE {
211 return Err(Error::RxBufferTooLong);
212 }
213
214 let r = T::regs();
215
216 r.rxd.ptr.write(|w|
217 // We're giving the register a pointer to the stack. Since we're
218 // waiting for the I2C transaction to end before this stack pointer
219 // becomes invalid, there's nothing wrong here.
220 //
221 // The PTR field is a full 32 bits wide and accepts the full range
222 // of values.
223 w.ptr().bits(buffer.as_mut_ptr() as u32));
224 r.rxd.maxcnt.write(|w|
225 // We're giving it the length of the buffer, so no danger of
226 // accessing invalid memory. We have verified that the length of the
227 // buffer fits in an `u8`, so the cast to the type of maxcnt
228 // is also fine.
229 //
230 // Note that that nrf52840 maxcnt is a wider
231 // type than a u8, so we use a `_` cast rather than a `u8` cast.
232 // The MAXCNT field is thus at least 8 bits wide and accepts the
233 // full range of values that fit in a `u8`.
234 w.maxcnt().bits(buffer.len() as _));
235
236 Ok(())
237 }
238
239 fn clear_errorsrc(&mut self) {
240 let r = T::regs();
241 r.errorsrc
242 .write(|w| w.overflow().bit(true).overread().bit(true).dnack().bit(true));
243 }
244
245 /// Returns matched address for latest command.
246 pub fn address_match(&self) -> u8 {
247 let r = T::regs();
248 r.address[r.match_.read().bits() as usize].read().address().bits()
249 }
250
251 /// Returns the index of the address matched in the latest command.
252 pub fn address_match_index(&self) -> usize {
253 T::regs().match_.read().bits() as _
254 }
255
256 /// Wait for read, write, stop or error
257 fn blocking_listen_wait(&mut self) -> Result<Status, Error> {
258 let r = T::regs();
259 loop {
260 if r.events_error.read().bits() != 0 {
261 r.events_error.reset();
262 r.tasks_stop.write(|w| unsafe { w.bits(1) });
263 while r.events_stopped.read().bits() == 0 {}
264 return Err(Error::Overflow);
265 }
266 if r.events_stopped.read().bits() != 0 {
267 r.events_stopped.reset();
268 return Err(Error::Bus);
269 }
270 if r.events_read.read().bits() != 0 {
271 r.events_read.reset();
272 return Ok(Status::Read);
273 }
274 if r.events_write.read().bits() != 0 {
275 r.events_write.reset();
276 return Ok(Status::Write);
277 }
278 }
279 }
280
281 /// Wait for stop, repeated start or error
282 fn blocking_listen_wait_end(&mut self, status: Status) -> Result<Command, Error> {
283 let r = T::regs();
284 loop {
285 // stop if an error occured
286 if r.events_error.read().bits() != 0 {
287 r.events_error.reset();
288 r.tasks_stop.write(|w| unsafe { w.bits(1) });
289 return Err(Error::Overflow);
290 } else if r.events_stopped.read().bits() != 0 {
291 r.events_stopped.reset();
292 return match status {
293 Status::Read => Ok(Command::Read),
294 Status::Write => {
295 let n = r.rxd.amount.read().bits() as usize;
296 Ok(Command::Write(n))
297 }
298 };
299 } else if r.events_read.read().bits() != 0 {
300 r.events_read.reset();
301 let n = r.rxd.amount.read().bits() as usize;
302 return Ok(Command::WriteRead(n));
303 }
304 }
305 }
306
307 /// Wait for stop or error
308 fn blocking_wait(&mut self) -> Result<usize, Error> {
309 let r = T::regs();
310 loop {
311 // stop if an error occured
312 if r.events_error.read().bits() != 0 {
313 r.events_error.reset();
314 r.tasks_stop.write(|w| unsafe { w.bits(1) });
315 let errorsrc = r.errorsrc.read();
316 if errorsrc.overread().is_detected() {
317 return Err(Error::OverRead);
318 } else if errorsrc.dnack().is_received() {
319 return Err(Error::DataNack);
320 } else {
321 return Err(Error::Bus);
322 }
323 } else if r.events_stopped.read().bits() != 0 {
324 r.events_stopped.reset();
325 let n = r.txd.amount.read().bits() as usize;
326 return Ok(n);
327 }
328 }
329 }
330
331 /// Wait for stop or error with timeout
332 #[cfg(feature = "time")]
333 fn blocking_wait_timeout(&mut self, timeout: Duration) -> Result<usize, Error> {
334 let r = T::regs();
335 let deadline = Instant::now() + timeout;
336 loop {
337 // stop if an error occured
338 if r.events_error.read().bits() != 0 {
339 r.events_error.reset();
340 r.tasks_stop.write(|w| unsafe { w.bits(1) });
341 let errorsrc = r.errorsrc.read();
342 if errorsrc.overread().is_detected() {
343 return Err(Error::OverRead);
344 } else if errorsrc.dnack().is_received() {
345 return Err(Error::DataNack);
346 } else {
347 return Err(Error::Bus);
348 }
349 } else if r.events_stopped.read().bits() != 0 {
350 r.events_stopped.reset();
351 let n = r.txd.amount.read().bits() as usize;
352 return Ok(n);
353 } else if Instant::now() > deadline {
354 r.tasks_stop.write(|w| unsafe { w.bits(1) });
355 return Err(Error::Timeout);
356 }
357 }
358 }
359
360 /// Wait for read, write, stop or error with timeout
361 #[cfg(feature = "time")]
362 fn blocking_listen_wait_timeout(&mut self, timeout: Duration) -> Result<Status, Error> {
363 let r = T::regs();
364 let deadline = Instant::now() + timeout;
365 loop {
366 if r.events_error.read().bits() != 0 {
367 r.events_error.reset();
368 r.tasks_stop.write(|w| unsafe { w.bits(1) });
369 while r.events_stopped.read().bits() == 0 {}
370 return Err(Error::Overflow);
371 }
372 if r.events_stopped.read().bits() != 0 {
373 r.events_stopped.reset();
374 return Err(Error::Bus);
375 }
376 if r.events_read.read().bits() != 0 {
377 r.events_read.reset();
378 return Ok(Status::Read);
379 }
380 if r.events_write.read().bits() != 0 {
381 r.events_write.reset();
382 return Ok(Status::Write);
383 }
384 if Instant::now() > deadline {
385 r.tasks_stop.write(|w| unsafe { w.bits(1) });
386 return Err(Error::Timeout);
387 }
388 }
389 }
390
391 /// Wait for stop, repeated start or error with timeout
392 #[cfg(feature = "time")]
393 fn blocking_listen_wait_end_timeout(&mut self, status: Status, timeout: Duration) -> Result<Command, Error> {
394 let r = T::regs();
395 let deadline = Instant::now() + timeout;
396 loop {
397 // stop if an error occured
398 if r.events_error.read().bits() != 0 {
399 r.events_error.reset();
400 r.tasks_stop.write(|w| unsafe { w.bits(1) });
401 return Err(Error::Overflow);
402 } else if r.events_stopped.read().bits() != 0 {
403 r.events_stopped.reset();
404 return match status {
405 Status::Read => Ok(Command::Read),
406 Status::Write => {
407 let n = r.rxd.amount.read().bits() as usize;
408 Ok(Command::Write(n))
409 }
410 };
411 } else if r.events_read.read().bits() != 0 {
412 r.events_read.reset();
413 let n = r.rxd.amount.read().bits() as usize;
414 return Ok(Command::WriteRead(n));
415 } else if Instant::now() > deadline {
416 r.tasks_stop.write(|w| unsafe { w.bits(1) });
417 return Err(Error::Timeout);
418 }
419 }
420 }
421
422 /// Wait for stop or error
423 fn async_wait(&mut self) -> impl Future<Output = Result<usize, Error>> {
424 poll_fn(move |cx| {
425 let r = T::regs();
426 let s = T::state();
427
428 s.waker.register(cx.waker());
429
430 // stop if an error occured
431 if r.events_error.read().bits() != 0 {
432 r.events_error.reset();
433 r.tasks_stop.write(|w| unsafe { w.bits(1) });
434 let errorsrc = r.errorsrc.read();
435 if errorsrc.overread().is_detected() {
436 return Poll::Ready(Err(Error::OverRead));
437 } else if errorsrc.dnack().is_received() {
438 return Poll::Ready(Err(Error::DataNack));
439 } else {
440 return Poll::Ready(Err(Error::Bus));
441 }
442 } else if r.events_stopped.read().bits() != 0 {
443 r.events_stopped.reset();
444 let n = r.txd.amount.read().bits() as usize;
445 return Poll::Ready(Ok(n));
446 }
447
448 Poll::Pending
449 })
450 }
451
452 /// Wait for read or write
453 fn async_listen_wait(&mut self) -> impl Future<Output = Result<Status, Error>> {
454 poll_fn(move |cx| {
455 let r = T::regs();
456 let s = T::state();
457
458 s.waker.register(cx.waker());
459
460 // stop if an error occured
461 if r.events_error.read().bits() != 0 {
462 r.events_error.reset();
463 r.tasks_stop.write(|w| unsafe { w.bits(1) });
464 return Poll::Ready(Err(Error::Overflow));
465 } else if r.events_read.read().bits() != 0 {
466 r.events_read.reset();
467 return Poll::Ready(Ok(Status::Read));
468 } else if r.events_write.read().bits() != 0 {
469 r.events_write.reset();
470 return Poll::Ready(Ok(Status::Write));
471 } else if r.events_stopped.read().bits() != 0 {
472 r.events_stopped.reset();
473 return Poll::Ready(Err(Error::Bus));
474 }
475 Poll::Pending
476 })
477 }
478
479 /// Wait for stop, repeated start or error
480 fn async_listen_wait_end(&mut self, status: Status) -> impl Future<Output = Result<Command, Error>> {
481 poll_fn(move |cx| {
482 let r = T::regs();
483 let s = T::state();
484
485 s.waker.register(cx.waker());
486
487 // stop if an error occured
488 if r.events_error.read().bits() != 0 {
489 r.events_error.reset();
490 r.tasks_stop.write(|w| unsafe { w.bits(1) });
491 return Poll::Ready(Err(Error::Overflow));
492 } else if r.events_stopped.read().bits() != 0 {
493 r.events_stopped.reset();
494 return match status {
495 Status::Read => Poll::Ready(Ok(Command::Read)),
496 Status::Write => {
497 let n = r.rxd.amount.read().bits() as usize;
498 Poll::Ready(Ok(Command::Write(n)))
499 }
500 };
501 } else if r.events_read.read().bits() != 0 {
502 r.events_read.reset();
503 let n = r.rxd.amount.read().bits() as usize;
504 return Poll::Ready(Ok(Command::WriteRead(n)));
505 }
506 Poll::Pending
507 })
508 }
509
510 fn setup_respond_from_ram(&mut self, buffer: &[u8], inten: bool) -> Result<(), Error> {
511 let r = T::regs();
512
513 compiler_fence(SeqCst);
514
515 // Set up the DMA write.
516 unsafe { self.set_tx_buffer(buffer)? };
517
518 // Clear events
519 r.events_stopped.reset();
520 r.events_error.reset();
521 self.clear_errorsrc();
522
523 if inten {
524 r.intenset.write(|w| w.stopped().set().error().set());
525 } else {
526 r.intenclr.write(|w| w.stopped().clear().error().clear());
527 }
528
529 // Start write operation.
530 r.tasks_preparetx.write(|w| unsafe { w.bits(1) });
531 r.tasks_resume.write(|w| unsafe { w.bits(1) });
532 Ok(())
533 }
534
535 fn setup_respond(&mut self, wr_buffer: &[u8], inten: bool) -> Result<(), Error> {
536 match self.setup_respond_from_ram(wr_buffer, inten) {
537 Ok(_) => Ok(()),
538 Err(Error::DMABufferNotInDataMemory) => {
539 trace!("Copying TWIS tx buffer into RAM for DMA");
540 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
541 tx_ram_buf.copy_from_slice(wr_buffer);
542 self.setup_respond_from_ram(&tx_ram_buf, inten)
543 }
544 Err(error) => Err(error),
545 }
546 }
547
548 fn setup_listen(&mut self, buffer: &mut [u8], inten: bool) -> Result<(), Error> {
549 let r = T::regs();
550 compiler_fence(SeqCst);
551
552 // Set up the DMA read.
553 unsafe { self.set_rx_buffer(buffer)? };
554
555 // Clear events
556 r.events_read.reset();
557 r.events_write.reset();
558 r.events_stopped.reset();
559 r.events_error.reset();
560 self.clear_errorsrc();
561
562 if inten {
563 r.intenset
564 .write(|w| w.stopped().set().error().set().read().set().write().set());
565 } else {
566 r.intenclr
567 .write(|w| w.stopped().clear().error().clear().read().clear().write().clear());
568 }
569
570 // Start read operation.
571 r.tasks_preparerx.write(|w| unsafe { w.bits(1) });
572
573 Ok(())
574 }
575
576 fn setup_listen_end(&mut self, inten: bool) -> Result<(), Error> {
577 let r = T::regs();
578 compiler_fence(SeqCst);
579
580 // Clear events
581 r.events_read.reset();
582 r.events_write.reset();
583 r.events_stopped.reset();
584 r.events_error.reset();
585 self.clear_errorsrc();
586
587 if inten {
588 r.intenset.write(|w| w.stopped().set().error().set().read().set());
589 } else {
590 r.intenclr.write(|w| w.stopped().clear().error().clear().read().clear());
591 }
592
593 Ok(())
594 }
595
596 /// Wait for commands from an I2C master.
597 /// `buffer` is provided in case master does a 'write' and is unused for 'read'.
598 /// The buffer must have a length of at most 255 bytes on the nRF52832
599 /// and at most 65535 bytes on the nRF52840.
600 /// To know which one of the addresses were matched, call `address_match` or `address_match_index`
601 pub fn blocking_listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> {
602 self.setup_listen(buffer, false)?;
603 let status = self.blocking_listen_wait()?;
604 if status == Status::Write {
605 self.setup_listen_end(false)?;
606 let command = self.blocking_listen_wait_end(status)?;
607 return Ok(command);
608 }
609 Ok(Command::Read)
610 }
611
612 /// Respond to an I2C master READ command.
613 /// Returns the number of bytes written.
614 /// The buffer must have a length of at most 255 bytes on the nRF52832
615 /// and at most 65535 bytes on the nRF52840.
616 pub fn blocking_respond_to_read(&mut self, buffer: &[u8]) -> Result<usize, Error> {
617 self.setup_respond(buffer, false)?;
618 self.blocking_wait()
619 }
620
621 /// Same as [`blocking_respond_to_read`](Twis::blocking_respond_to_read) but will fail instead of copying data into RAM.
622 /// Consult the module level documentation to learn more.
623 pub fn blocking_respond_to_read_from_ram(&mut self, buffer: &[u8]) -> Result<usize, Error> {
624 self.setup_respond_from_ram(buffer, false)?;
625 self.blocking_wait()
626 }
627
628 // ===========================================
629
630 /// Wait for commands from an I2C master, with timeout.
631 /// `buffer` is provided in case master does a 'write' and is unused for 'read'.
632 /// The buffer must have a length of at most 255 bytes on the nRF52832
633 /// and at most 65535 bytes on the nRF52840.
634 /// To know which one of the addresses were matched, call `address_match` or `address_match_index`
635 #[cfg(feature = "time")]
636 pub fn blocking_listen_timeout(&mut self, buffer: &mut [u8], timeout: Duration) -> Result<Command, Error> {
637 self.setup_listen(buffer, false)?;
638 let status = self.blocking_listen_wait_timeout(timeout)?;
639 if status == Status::Write {
640 self.setup_listen_end(false)?;
641 let command = self.blocking_listen_wait_end_timeout(status, timeout)?;
642 return Ok(command);
643 }
644 Ok(Command::Read)
645 }
646
647 /// Respond to an I2C master READ command with timeout.
648 /// Returns the number of bytes written.
649 /// See [`blocking_respond_to_read`].
650 #[cfg(feature = "time")]
651 pub fn blocking_respond_to_read_timeout(&mut self, buffer: &[u8], timeout: Duration) -> Result<usize, Error> {
652 self.setup_respond(buffer, false)?;
653 self.blocking_wait_timeout(timeout)
654 }
655
656 /// Same as [`blocking_respond_to_read_timeout`](Twis::blocking_respond_to_read_timeout) but will fail instead of copying data into RAM.
657 /// Consult the module level documentation to learn more.
658 #[cfg(feature = "time")]
659 pub fn blocking_respond_to_read_from_ram_timeout(
660 &mut self,
661 buffer: &[u8],
662 timeout: Duration,
663 ) -> Result<usize, Error> {
664 self.setup_respond_from_ram(buffer, false)?;
665 self.blocking_wait_timeout(timeout)
666 }
667
668 // ===========================================
669
670 /// Wait asynchronously for commands from an I2C master.
671 /// `buffer` is provided in case master does a 'write' and is unused for 'read'.
672 /// The buffer must have a length of at most 255 bytes on the nRF52832
673 /// and at most 65535 bytes on the nRF52840.
674 /// To know which one of the addresses were matched, call `address_match` or `address_match_index`
675 pub async fn listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> {
676 self.setup_listen(buffer, true)?;
677 let status = self.async_listen_wait().await?;
678 if status == Status::Write {
679 self.setup_listen_end(true)?;
680 let command = self.async_listen_wait_end(status).await?;
681 return Ok(command);
682 }
683 Ok(Command::Read)
684 }
685
686 /// Respond to an I2C master READ command, asynchronously.
687 /// Returns the number of bytes written.
688 /// The buffer must have a length of at most 255 bytes on the nRF52832
689 /// and at most 65535 bytes on the nRF52840.
690 pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result<usize, Error> {
691 self.setup_respond(buffer, true)?;
692 self.async_wait().await
693 }
694
695 /// Same as [`respond_to_read`](Twis::respond_to_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
696 pub async fn respond_to_read_from_ram(&mut self, buffer: &[u8]) -> Result<usize, Error> {
697 self.setup_respond_from_ram(buffer, true)?;
698 self.async_wait().await
699 }
700}
701
702impl<'a, T: Instance> Drop for Twis<'a, T> {
703 fn drop(&mut self) {
704 trace!("twis drop");
705
706 // TODO: check for abort
707
708 // disable!
709 let r = T::regs();
710 r.enable.write(|w| w.enable().disabled());
711
712 gpio::deconfigure_pin(r.psel.sda.read().bits());
713 gpio::deconfigure_pin(r.psel.scl.read().bits());
714
715 trace!("twis drop: done");
716 }
717}
718
719pub(crate) mod sealed {
720 use super::*;
721
722 pub struct State {
723 pub waker: AtomicWaker,
724 }
725
726 impl State {
727 pub const fn new() -> Self {
728 Self {
729 waker: AtomicWaker::new(),
730 }
731 }
732 }
733
734 pub trait Instance {
735 fn regs() -> &'static pac::twis0::RegisterBlock;
736 fn state() -> &'static State;
737 }
738}
739
740pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
741 type Interrupt: Interrupt;
742}
743
744macro_rules! impl_twis {
745 ($type:ident, $pac_type:ident, $irq:ident) => {
746 impl crate::twis::sealed::Instance for peripherals::$type {
747 fn regs() -> &'static pac::twis0::RegisterBlock {
748 unsafe { &*pac::$pac_type::ptr() }
749 }
750 fn state() -> &'static crate::twis::sealed::State {
751 static STATE: crate::twis::sealed::State = crate::twis::sealed::State::new();
752 &STATE
753 }
754 }
755 impl crate::twis::Instance for peripherals::$type {
756 type Interrupt = crate::interrupt::$irq;
757 }
758 };
759}
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index 636d6c7a3..63df1b682 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -986,7 +986,7 @@ mod eha {
986 986
987 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 987 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
988 988
989 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { 989 fn flush(&mut self) -> Result<(), Self::Error> {
990 async move { Ok(()) } 990 async move { Ok(()) }
991 } 991 }
992 } 992 }
@@ -1000,7 +1000,7 @@ mod eha {
1000 1000
1001 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 1001 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
1002 1002
1003 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { 1003 fn flush(&mut self) -> Result<(), Self::Error> {
1004 async move { Ok(()) } 1004 async move { Ok(()) }
1005 } 1005 }
1006 } 1006 }
@@ -1012,4 +1012,26 @@ mod eha {
1012 self.read(buffer) 1012 self.read(buffer)
1013 } 1013 }
1014 } 1014 }
1015
1016 impl<'d, U: Instance, T: TimerInstance> embedded_hal_async::serial::Read for UarteWithIdle<'d, U, T> {
1017 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
1018
1019 fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
1020 self.read(buffer)
1021 }
1022 }
1023
1024 impl<'d, U: Instance, T: TimerInstance> embedded_hal_async::serial::Write for UarteWithIdle<'d, U, T> {
1025 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
1026
1027 fn write<'a>(&'a mut self, buffer: &'a [u8]) -> Self::WriteFuture<'a> {
1028 self.write(buffer)
1029 }
1030
1031 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
1032
1033 fn flush(&mut self) -> Result<(), Self::Error> {
1034 async move { Ok(()) }
1035 }
1036 }
1015} 1037}
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs
index eb1472fa5..ed4d5cf35 100644
--- a/embassy-nrf/src/usb.rs
+++ b/embassy-nrf/src/usb.rs
@@ -1,6 +1,6 @@
1#![macro_use] 1#![macro_use]
2 2
3use core::future::{poll_fn, Future}; 3use core::future::poll_fn;
4use core::marker::PhantomData; 4use core::marker::PhantomData;
5use core::mem::MaybeUninit; 5use core::mem::MaybeUninit;
6use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; 6use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering};
@@ -28,11 +28,7 @@ static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0);
28/// here provides a hook into determining whether it is. 28/// here provides a hook into determining whether it is.
29pub trait UsbSupply { 29pub trait UsbSupply {
30 fn is_usb_detected(&self) -> bool; 30 fn is_usb_detected(&self) -> bool;
31 31 async fn wait_power_ready(&mut self) -> Result<(), ()>;
32 type UsbPowerReadyFuture<'a>: Future<Output = Result<(), ()>> + 'a
33 where
34 Self: 'a;
35 fn wait_power_ready(&mut self) -> Self::UsbPowerReadyFuture<'_>;
36} 32}
37 33
38pub struct Driver<'d, T: Instance, P: UsbSupply> { 34pub struct Driver<'d, T: Instance, P: UsbSupply> {
@@ -102,8 +98,7 @@ impl UsbSupply for PowerUsb {
102 regs.usbregstatus.read().vbusdetect().is_vbus_present() 98 regs.usbregstatus.read().vbusdetect().is_vbus_present()
103 } 99 }
104 100
105 type UsbPowerReadyFuture<'a> = impl Future<Output = Result<(), ()>> + 'a where Self: 'a; 101 async fn wait_power_ready(&mut self) -> Result<(), ()> {
106 fn wait_power_ready(&mut self) -> Self::UsbPowerReadyFuture<'_> {
107 poll_fn(move |cx| { 102 poll_fn(move |cx| {
108 POWER_WAKER.register(cx.waker()); 103 POWER_WAKER.register(cx.waker());
109 let regs = unsafe { &*pac::POWER::ptr() }; 104 let regs = unsafe { &*pac::POWER::ptr() };
@@ -116,6 +111,7 @@ impl UsbSupply for PowerUsb {
116 Poll::Pending 111 Poll::Pending
117 } 112 }
118 }) 113 })
114 .await
119 } 115 }
120} 116}
121 117
@@ -147,8 +143,7 @@ impl UsbSupply for &SignalledSupply {
147 self.usb_detected.load(Ordering::Relaxed) 143 self.usb_detected.load(Ordering::Relaxed)
148 } 144 }
149 145
150 type UsbPowerReadyFuture<'a> = impl Future<Output = Result<(), ()>> + 'a where Self: 'a; 146 async fn wait_power_ready(&mut self) -> Result<(), ()> {
151 fn wait_power_ready(&mut self) -> Self::UsbPowerReadyFuture<'_> {
152 poll_fn(move |cx| { 147 poll_fn(move |cx| {
153 POWER_WAKER.register(cx.waker()); 148 POWER_WAKER.register(cx.waker());
154 149
@@ -160,6 +155,7 @@ impl UsbSupply for &SignalledSupply {
160 Poll::Pending 155 Poll::Pending
161 } 156 }
162 }) 157 })
158 .await
163 } 159 }
164} 160}
165 161
@@ -289,61 +285,52 @@ pub struct Bus<'d, T: Instance, P: UsbSupply> {
289} 285}
290 286
291impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> { 287impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
292 type EnableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; 288 async fn enable(&mut self) {
293 type DisableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; 289 let regs = T::regs();
294 type PollFuture<'a> = impl Future<Output = Event> + 'a where Self: 'a;
295 type RemoteWakeupFuture<'a> = impl Future<Output = Result<(), Unsupported>> + 'a where Self: 'a;
296
297 fn enable(&mut self) -> Self::EnableFuture<'_> {
298 async move {
299 let regs = T::regs();
300
301 errata::pre_enable();
302
303 regs.enable.write(|w| w.enable().enabled());
304
305 // Wait until the peripheral is ready.
306 regs.intenset.write(|w| w.usbevent().set_bit());
307 poll_fn(|cx| {
308 BUS_WAKER.register(cx.waker());
309 if regs.eventcause.read().ready().is_ready() {
310 Poll::Ready(())
311 } else {
312 Poll::Pending
313 }
314 })
315 .await;
316 regs.eventcause.write(|w| w.ready().clear_bit_by_one());
317
318 errata::post_enable();
319 290
320 unsafe { NVIC::unmask(pac::Interrupt::USBD) }; 291 errata::pre_enable();
321 292
322 regs.intenset.write(|w| { 293 regs.enable.write(|w| w.enable().enabled());
323 w.usbreset().set_bit();
324 w.usbevent().set_bit();
325 w.epdata().set_bit();
326 w
327 });
328 294
329 if self.usb_supply.wait_power_ready().await.is_ok() { 295 // Wait until the peripheral is ready.
330 // Enable the USB pullup, allowing enumeration. 296 regs.intenset.write(|w| w.usbevent().set_bit());
331 regs.usbpullup.write(|w| w.connect().enabled()); 297 poll_fn(|cx| {
332 trace!("enabled"); 298 BUS_WAKER.register(cx.waker());
299 if regs.eventcause.read().ready().is_ready() {
300 Poll::Ready(())
333 } else { 301 } else {
334 trace!("usb power not ready due to usb removal"); 302 Poll::Pending
335 } 303 }
304 })
305 .await;
306 regs.eventcause.write(|w| w.ready().clear_bit_by_one());
307
308 errata::post_enable();
309
310 unsafe { NVIC::unmask(pac::Interrupt::USBD) };
311
312 regs.intenset.write(|w| {
313 w.usbreset().set_bit();
314 w.usbevent().set_bit();
315 w.epdata().set_bit();
316 w
317 });
318
319 if self.usb_supply.wait_power_ready().await.is_ok() {
320 // Enable the USB pullup, allowing enumeration.
321 regs.usbpullup.write(|w| w.connect().enabled());
322 trace!("enabled");
323 } else {
324 trace!("usb power not ready due to usb removal");
336 } 325 }
337 } 326 }
338 327
339 fn disable(&mut self) -> Self::DisableFuture<'_> { 328 async fn disable(&mut self) {
340 async move { 329 let regs = T::regs();
341 let regs = T::regs(); 330 regs.enable.write(|x| x.enable().disabled());
342 regs.enable.write(|x| x.enable().disabled());
343 }
344 } 331 }
345 332
346 fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> { 333 async fn poll(&mut self) -> Event {
347 poll_fn(move |cx| { 334 poll_fn(move |cx| {
348 BUS_WAKER.register(cx.waker()); 335 BUS_WAKER.register(cx.waker());
349 let regs = T::regs(); 336 let regs = T::regs();
@@ -401,6 +388,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
401 388
402 Poll::Pending 389 Poll::Pending
403 }) 390 })
391 .await
404 } 392 }
405 393
406 #[inline] 394 #[inline]
@@ -493,42 +481,40 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
493 } 481 }
494 482
495 #[inline] 483 #[inline]
496 fn remote_wakeup(&mut self) -> Self::RemoteWakeupFuture<'_> { 484 async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
497 async move { 485 let regs = T::regs();
498 let regs = T::regs();
499
500 if regs.lowpower.read().lowpower().is_low_power() {
501 errata::pre_wakeup();
502 486
503 regs.lowpower.write(|w| w.lowpower().force_normal()); 487 if regs.lowpower.read().lowpower().is_low_power() {
488 errata::pre_wakeup();
504 489
505 poll_fn(|cx| { 490 regs.lowpower.write(|w| w.lowpower().force_normal());
506 BUS_WAKER.register(cx.waker());
507 let regs = T::regs();
508 let r = regs.eventcause.read();
509 491
510 if regs.events_usbreset.read().bits() != 0 { 492 poll_fn(|cx| {
511 Poll::Ready(()) 493 BUS_WAKER.register(cx.waker());
512 } else if r.resume().bit() { 494 let regs = T::regs();
513 Poll::Ready(()) 495 let r = regs.eventcause.read();
514 } else if r.usbwuallowed().bit() {
515 regs.eventcause.write(|w| w.usbwuallowed().allowed());
516 496
517 regs.dpdmvalue.write(|w| w.state().resume()); 497 if regs.events_usbreset.read().bits() != 0 {
518 regs.tasks_dpdmdrive.write(|w| w.tasks_dpdmdrive().set_bit()); 498 Poll::Ready(())
499 } else if r.resume().bit() {
500 Poll::Ready(())
501 } else if r.usbwuallowed().bit() {
502 regs.eventcause.write(|w| w.usbwuallowed().allowed());
519 503
520 Poll::Ready(()) 504 regs.dpdmvalue.write(|w| w.state().resume());
521 } else { 505 regs.tasks_dpdmdrive.write(|w| w.tasks_dpdmdrive().set_bit());
522 Poll::Pending
523 }
524 })
525 .await;
526 506
527 errata::post_wakeup(); 507 Poll::Ready(())
528 } 508 } else {
509 Poll::Pending
510 }
511 })
512 .await;
529 513
530 Ok(()) 514 errata::post_wakeup();
531 } 515 }
516
517 Ok(())
532 } 518 }
533} 519}
534 520
@@ -594,9 +580,7 @@ impl<'d, T: Instance, Dir: EndpointDir> driver::Endpoint for Endpoint<'d, T, Dir
594 &self.info 580 &self.info
595 } 581 }
596 582
597 type WaitEnabledFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; 583 async fn wait_enabled(&mut self) {
598
599 fn wait_enabled(&mut self) -> Self::WaitEnabledFuture<'_> {
600 let i = self.info.addr.index(); 584 let i = self.info.addr.index();
601 assert!(i != 0); 585 assert!(i != 0);
602 586
@@ -608,6 +592,7 @@ impl<'d, T: Instance, Dir: EndpointDir> driver::Endpoint for Endpoint<'d, T, Dir
608 Poll::Pending 592 Poll::Pending
609 } 593 }
610 }) 594 })
595 .await
611 } 596 }
612} 597}
613 598
@@ -712,34 +697,26 @@ unsafe fn write_dma<T: Instance>(i: usize, buf: &[u8]) {
712} 697}
713 698
714impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { 699impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
715 type ReadFuture<'a> = impl Future<Output = Result<usize, EndpointError>> + 'a where Self: 'a; 700 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
716 701 let i = self.info.addr.index();
717 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { 702 assert!(i != 0);
718 async move {
719 let i = self.info.addr.index();
720 assert!(i != 0);
721 703
722 self.wait_data_ready().await.map_err(|_| EndpointError::Disabled)?; 704 self.wait_data_ready().await.map_err(|_| EndpointError::Disabled)?;
723 705
724 unsafe { read_dma::<T>(i, buf) } 706 unsafe { read_dma::<T>(i, buf) }
725 }
726 } 707 }
727} 708}
728 709
729impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { 710impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
730 type WriteFuture<'a> = impl Future<Output = Result<(), EndpointError>> + 'a where Self: 'a; 711 async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError> {
731 712 let i = self.info.addr.index();
732 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { 713 assert!(i != 0);
733 async move {
734 let i = self.info.addr.index();
735 assert!(i != 0);
736 714
737 self.wait_data_ready().await.map_err(|_| EndpointError::Disabled)?; 715 self.wait_data_ready().await.map_err(|_| EndpointError::Disabled)?;
738 716
739 unsafe { write_dma::<T>(i, buf) } 717 unsafe { write_dma::<T>(i, buf) }
740 718
741 Ok(()) 719 Ok(())
742 }
743 } 720 }
744} 721}
745 722
@@ -749,136 +726,120 @@ pub struct ControlPipe<'d, T: Instance> {
749} 726}
750 727
751impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { 728impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
752 type SetupFuture<'a> = impl Future<Output = [u8;8]> + 'a where Self: 'a;
753 type DataOutFuture<'a> = impl Future<Output = Result<usize, EndpointError>> + 'a where Self: 'a;
754 type DataInFuture<'a> = impl Future<Output = Result<(), EndpointError>> + 'a where Self: 'a;
755 type AcceptFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
756 type RejectFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
757
758 fn max_packet_size(&self) -> usize { 729 fn max_packet_size(&self) -> usize {
759 usize::from(self.max_packet_size) 730 usize::from(self.max_packet_size)
760 } 731 }
761 732
762 fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a> { 733 async fn setup(&mut self) -> [u8; 8] {
763 async move { 734 let regs = T::regs();
764 let regs = T::regs();
765 735
766 // Reset shorts 736 // Reset shorts
767 regs.shorts.write(|w| w); 737 regs.shorts.write(|w| w);
768 738
769 // Wait for SETUP packet 739 // Wait for SETUP packet
770 regs.intenset.write(|w| w.ep0setup().set()); 740 regs.intenset.write(|w| w.ep0setup().set());
771 poll_fn(|cx| { 741 poll_fn(|cx| {
772 EP0_WAKER.register(cx.waker()); 742 EP0_WAKER.register(cx.waker());
773 let regs = T::regs(); 743 let regs = T::regs();
774 if regs.events_ep0setup.read().bits() != 0 { 744 if regs.events_ep0setup.read().bits() != 0 {
775 Poll::Ready(()) 745 Poll::Ready(())
776 } else { 746 } else {
777 Poll::Pending 747 Poll::Pending
778 } 748 }
779 }) 749 })
780 .await; 750 .await;
781 751
782 regs.events_ep0setup.reset(); 752 regs.events_ep0setup.reset();
783 753
784 let mut buf = [0; 8]; 754 let mut buf = [0; 8];
785 buf[0] = regs.bmrequesttype.read().bits() as u8; 755 buf[0] = regs.bmrequesttype.read().bits() as u8;
786 buf[1] = regs.brequest.read().brequest().bits(); 756 buf[1] = regs.brequest.read().brequest().bits();
787 buf[2] = regs.wvaluel.read().wvaluel().bits(); 757 buf[2] = regs.wvaluel.read().wvaluel().bits();
788 buf[3] = regs.wvalueh.read().wvalueh().bits(); 758 buf[3] = regs.wvalueh.read().wvalueh().bits();
789 buf[4] = regs.windexl.read().windexl().bits(); 759 buf[4] = regs.windexl.read().windexl().bits();
790 buf[5] = regs.windexh.read().windexh().bits(); 760 buf[5] = regs.windexh.read().windexh().bits();
791 buf[6] = regs.wlengthl.read().wlengthl().bits(); 761 buf[6] = regs.wlengthl.read().wlengthl().bits();
792 buf[7] = regs.wlengthh.read().wlengthh().bits(); 762 buf[7] = regs.wlengthh.read().wlengthh().bits();
793 763
794 buf 764 buf
795 }
796 } 765 }
797 766
798 fn data_out<'a>(&'a mut self, buf: &'a mut [u8], _first: bool, _last: bool) -> Self::DataOutFuture<'a> { 767 async fn data_out(&mut self, buf: &mut [u8], _first: bool, _last: bool) -> Result<usize, EndpointError> {
799 async move { 768 let regs = T::regs();
800 let regs = T::regs();
801 769
802 regs.events_ep0datadone.reset(); 770 regs.events_ep0datadone.reset();
803 771
804 // This starts a RX on EP0. events_ep0datadone notifies when done. 772 // This starts a RX on EP0. events_ep0datadone notifies when done.
805 regs.tasks_ep0rcvout.write(|w| w.tasks_ep0rcvout().set_bit()); 773 regs.tasks_ep0rcvout.write(|w| w.tasks_ep0rcvout().set_bit());
806 774
807 // Wait until ready 775 // Wait until ready
808 regs.intenset.write(|w| { 776 regs.intenset.write(|w| {
809 w.usbreset().set(); 777 w.usbreset().set();
810 w.ep0setup().set(); 778 w.ep0setup().set();
811 w.ep0datadone().set() 779 w.ep0datadone().set()
812 }); 780 });
813 poll_fn(|cx| { 781 poll_fn(|cx| {
814 EP0_WAKER.register(cx.waker()); 782 EP0_WAKER.register(cx.waker());
815 let regs = T::regs(); 783 let regs = T::regs();
816 if regs.events_ep0datadone.read().bits() != 0 { 784 if regs.events_ep0datadone.read().bits() != 0 {
817 Poll::Ready(Ok(())) 785 Poll::Ready(Ok(()))
818 } else if regs.events_usbreset.read().bits() != 0 { 786 } else if regs.events_usbreset.read().bits() != 0 {
819 trace!("aborted control data_out: usb reset"); 787 trace!("aborted control data_out: usb reset");
820 Poll::Ready(Err(EndpointError::Disabled)) 788 Poll::Ready(Err(EndpointError::Disabled))
821 } else if regs.events_ep0setup.read().bits() != 0 { 789 } else if regs.events_ep0setup.read().bits() != 0 {
822 trace!("aborted control data_out: received another SETUP"); 790 trace!("aborted control data_out: received another SETUP");
823 Poll::Ready(Err(EndpointError::Disabled)) 791 Poll::Ready(Err(EndpointError::Disabled))
824 } else { 792 } else {
825 Poll::Pending 793 Poll::Pending
826 } 794 }
827 }) 795 })
828 .await?; 796 .await?;
829 797
830 unsafe { read_dma::<T>(0, buf) } 798 unsafe { read_dma::<T>(0, buf) }
831 }
832 } 799 }
833 800
834 fn data_in<'a>(&'a mut self, buf: &'a [u8], _first: bool, last: bool) -> Self::DataInFuture<'a> { 801 async fn data_in(&mut self, buf: &[u8], _first: bool, last: bool) -> Result<(), EndpointError> {
835 async move { 802 let regs = T::regs();
836 let regs = T::regs(); 803 regs.events_ep0datadone.reset();
837 regs.events_ep0datadone.reset();
838 804
839 regs.shorts.write(|w| w.ep0datadone_ep0status().bit(last)); 805 regs.shorts.write(|w| w.ep0datadone_ep0status().bit(last));
840 806
841 // This starts a TX on EP0. events_ep0datadone notifies when done. 807 // This starts a TX on EP0. events_ep0datadone notifies when done.
842 unsafe { write_dma::<T>(0, buf) } 808 unsafe { write_dma::<T>(0, buf) }
843 809
844 regs.intenset.write(|w| { 810 regs.intenset.write(|w| {
845 w.usbreset().set(); 811 w.usbreset().set();
846 w.ep0setup().set(); 812 w.ep0setup().set();
847 w.ep0datadone().set() 813 w.ep0datadone().set()
848 }); 814 });
849 815
850 poll_fn(|cx| { 816 poll_fn(|cx| {
851 cx.waker().wake_by_ref(); 817 cx.waker().wake_by_ref();
852 EP0_WAKER.register(cx.waker()); 818 EP0_WAKER.register(cx.waker());
853 let regs = T::regs(); 819 let regs = T::regs();
854 if regs.events_ep0datadone.read().bits() != 0 { 820 if regs.events_ep0datadone.read().bits() != 0 {
855 Poll::Ready(Ok(())) 821 Poll::Ready(Ok(()))
856 } else if regs.events_usbreset.read().bits() != 0 { 822 } else if regs.events_usbreset.read().bits() != 0 {
857 trace!("aborted control data_in: usb reset"); 823 trace!("aborted control data_in: usb reset");
858 Poll::Ready(Err(EndpointError::Disabled)) 824 Poll::Ready(Err(EndpointError::Disabled))
859 } else if regs.events_ep0setup.read().bits() != 0 { 825 } else if regs.events_ep0setup.read().bits() != 0 {
860 trace!("aborted control data_in: received another SETUP"); 826 trace!("aborted control data_in: received another SETUP");
861 Poll::Ready(Err(EndpointError::Disabled)) 827 Poll::Ready(Err(EndpointError::Disabled))
862 } else { 828 } else {
863 Poll::Pending 829 Poll::Pending
864 } 830 }
865 }) 831 })
866 .await 832 .await
867 }
868 } 833 }
869 834
870 fn accept<'a>(&'a mut self) -> Self::AcceptFuture<'a> { 835 async fn accept(&mut self) {
871 async move { 836 let regs = T::regs();
872 let regs = T::regs(); 837 regs.tasks_ep0status.write(|w| w.tasks_ep0status().bit(true));
873 regs.tasks_ep0status.write(|w| w.tasks_ep0status().bit(true));
874 }
875 } 838 }
876 839
877 fn reject<'a>(&'a mut self) -> Self::RejectFuture<'a> { 840 async fn reject(&mut self) {
878 async move { 841 let regs = T::regs();
879 let regs = T::regs(); 842 regs.tasks_ep0stall.write(|w| w.tasks_ep0stall().bit(true));
880 regs.tasks_ep0stall.write(|w| w.tasks_ep0stall().bit(true));
881 }
882 } 843 }
883} 844}
884 845
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 04b0c13ce..284d458c6 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -13,7 +13,7 @@ flavors = [
13] 13]
14 14
15[features] 15[features]
16defmt = ["dep:defmt", "embassy-usb-driver?/defmt"] 16defmt = ["dep:defmt", "embassy-usb-driver?/defmt", "embassy-hal-common/defmt"]
17 17
18# Reexport the PAC for the currently enabled chip at `embassy_rp::pac`. 18# Reexport the PAC for the currently enabled chip at `embassy_rp::pac`.
19# This is unstable because semver-minor (non-breaking) releases of embassy-rp may major-bump (breaking) the PAC version. 19# This is unstable because semver-minor (non-breaking) releases of embassy-rp may major-bump (breaking) the PAC version.
@@ -53,13 +53,14 @@ cortex-m = "0.7.6"
53critical-section = "1.1" 53critical-section = "1.1"
54futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 54futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
55chrono = { version = "0.4", default-features = false, optional = true } 55chrono = { version = "0.4", default-features = false, optional = true }
56embedded-io = { version = "0.3.1", features = ["async"], optional = true } 56embedded-io = { version = "0.4.0", features = ["async"], optional = true }
57embedded-storage = { version = "0.3" } 57embedded-storage = { version = "0.3" }
58rand_core = "0.6.4"
58 59
59rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] } 60rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] }
60#rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] } 61#rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] }
61 62
62embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 63embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
63embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} 64embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true}
64embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true} 65embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true}
65embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} 66embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true}
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs
new file mode 100644
index 000000000..025c6f917
--- /dev/null
+++ b/embassy-rp/src/adc.rs
@@ -0,0 +1,173 @@
1use core::future::poll_fn;
2use core::marker::PhantomData;
3use core::sync::atomic::{compiler_fence, Ordering};
4use core::task::Poll;
5
6use embassy_hal_common::into_ref;
7use embassy_sync::waitqueue::AtomicWaker;
8use embedded_hal_02::adc::{Channel, OneShot};
9
10use crate::interrupt::{self, InterruptExt};
11use crate::peripherals::ADC;
12use crate::{pac, peripherals, Peripheral};
13static WAKER: AtomicWaker = AtomicWaker::new();
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17#[non_exhaustive]
18pub enum Error {
19 // No errors for now
20}
21
22#[non_exhaustive]
23pub struct Config {}
24
25impl Default for Config {
26 fn default() -> Self {
27 Self {}
28 }
29}
30pub struct Adc<'d> {
31 phantom: PhantomData<&'d ADC>,
32}
33
34impl<'d> Adc<'d> {
35 #[inline]
36 fn regs() -> pac::adc::Adc {
37 pac::ADC
38 }
39
40 #[inline]
41 fn reset() -> pac::resets::regs::Peripherals {
42 let mut ret = pac::resets::regs::Peripherals::default();
43 ret.set_adc(true);
44 ret
45 }
46
47 pub fn new(
48 _inner: impl Peripheral<P = ADC> + 'd,
49 irq: impl Peripheral<P = interrupt::ADC_IRQ_FIFO> + 'd,
50 _config: Config,
51 ) -> Self {
52 into_ref!(irq);
53 unsafe {
54 let reset = Self::reset();
55 crate::reset::reset(reset);
56 crate::reset::unreset_wait(reset);
57 let r = Self::regs();
58 // Enable ADC
59 r.cs().write(|w| w.set_en(true));
60 // Wait for ADC ready
61 while !r.cs().read().ready() {}
62 }
63
64 // Setup IRQ
65 irq.disable();
66 irq.set_handler(|_| unsafe {
67 let r = Self::regs();
68 r.inte().write(|w| w.set_fifo(false));
69 WAKER.wake();
70 });
71 irq.unpend();
72 irq.enable();
73
74 Self { phantom: PhantomData }
75 }
76
77 async fn wait_for_ready() {
78 let r = Self::regs();
79 unsafe {
80 r.inte().write(|w| w.set_fifo(true));
81 compiler_fence(Ordering::SeqCst);
82 poll_fn(|cx| {
83 WAKER.register(cx.waker());
84 if r.cs().read().ready() {
85 return Poll::Ready(());
86 }
87 Poll::Pending
88 })
89 .await;
90 }
91 }
92
93 pub async fn read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 {
94 let r = Self::regs();
95 unsafe {
96 r.cs().modify(|w| {
97 w.set_ainsel(PIN::channel());
98 w.set_start_once(true)
99 });
100 Self::wait_for_ready().await;
101 r.result().read().result().into()
102 }
103 }
104
105 pub async fn read_temperature(&mut self) -> u16 {
106 let r = Self::regs();
107 unsafe {
108 r.cs().modify(|w| w.set_ts_en(true));
109 if !r.cs().read().ready() {
110 Self::wait_for_ready().await;
111 }
112 r.cs().modify(|w| {
113 w.set_ainsel(4);
114 w.set_start_once(true)
115 });
116 Self::wait_for_ready().await;
117 r.result().read().result().into()
118 }
119 }
120
121 pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 {
122 let r = Self::regs();
123 unsafe {
124 r.cs().modify(|w| {
125 w.set_ainsel(PIN::channel());
126 w.set_start_once(true)
127 });
128 while !r.cs().read().ready() {}
129 r.result().read().result().into()
130 }
131 }
132
133 pub fn blocking_read_temperature(&mut self) -> u16 {
134 let r = Self::regs();
135 unsafe {
136 r.cs().modify(|w| w.set_ts_en(true));
137 while !r.cs().read().ready() {}
138 r.cs().modify(|w| {
139 w.set_ainsel(4);
140 w.set_start_once(true)
141 });
142 while !r.cs().read().ready() {}
143 r.result().read().result().into()
144 }
145 }
146}
147
148macro_rules! impl_pin {
149 ($pin:ident, $channel:expr) => {
150 impl Channel<Adc<'static>> for peripherals::$pin {
151 type ID = u8;
152 fn channel() -> u8 {
153 $channel
154 }
155 }
156 };
157}
158
159impl_pin!(PIN_26, 0);
160impl_pin!(PIN_27, 1);
161impl_pin!(PIN_28, 2);
162impl_pin!(PIN_29, 3);
163
164impl<WORD, PIN> OneShot<Adc<'static>, WORD, PIN> for Adc<'static>
165where
166 WORD: From<u16>,
167 PIN: Channel<Adc<'static>, ID = u8>,
168{
169 type Error = ();
170 fn read(&mut self, pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
171 Ok(self.blocking_read(pin).into())
172 }
173}
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 1c446f389..85c9bbb7a 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -5,7 +5,7 @@ use crate::{pac, reset};
5const XOSC_MHZ: u32 = 12; 5const XOSC_MHZ: u32 = 12;
6 6
7/// safety: must be called exactly once at bootup 7/// safety: must be called exactly once at bootup
8pub unsafe fn init() { 8pub(crate) unsafe fn init() {
9 // Reset everything except: 9 // Reset everything except:
10 // - QSPI (we're using it to run this code!) 10 // - QSPI (we're using it to run this code!)
11 // - PLLs (it may be suicide if that's what's clocking us) 11 // - PLLs (it may be suicide if that's what's clocking us)
@@ -196,3 +196,40 @@ unsafe fn configure_pll(p: pac::pll::Pll, refdiv: u32, vco_freq: u32, post_div1:
196 // Turn on post divider 196 // Turn on post divider
197 p.pwr().modify(|w| w.set_postdivpd(false)); 197 p.pwr().modify(|w| w.set_postdivpd(false));
198} 198}
199
200/// Random number generator based on the ROSC RANDOMBIT register.
201///
202/// This will not produce random values if the ROSC is stopped or run at some
203/// harmonic of the bus frequency. With default clock settings these are not
204/// issues.
205pub struct RoscRng;
206
207impl RoscRng {
208 fn next_u8() -> u8 {
209 let random_reg = pac::ROSC.randombit();
210 let mut acc = 0;
211 for _ in 0..u8::BITS {
212 acc <<= 1;
213 acc |= unsafe { random_reg.read().randombit() as u8 };
214 }
215 acc
216 }
217}
218
219impl rand_core::RngCore for RoscRng {
220 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
221 Ok(self.fill_bytes(dest))
222 }
223
224 fn next_u32(&mut self) -> u32 {
225 rand_core::impls::next_u32_via_fill(self)
226 }
227
228 fn next_u64(&mut self) -> u64 {
229 rand_core::impls::next_u64_via_fill(self)
230 }
231
232 fn fill_bytes(&mut self, dest: &mut [u8]) {
233 dest.fill_with(Self::next_u8)
234 }
235}
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs
index d09cc62fb..a972d5f69 100644
--- a/embassy-rp/src/flash.rs
+++ b/embassy-rp/src/flash.rs
@@ -59,6 +59,11 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
59 } 59 }
60 60
61 pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 61 pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
62 trace!(
63 "Reading from 0x{:x} to 0x{:x}",
64 FLASH_BASE + offset as usize,
65 FLASH_BASE + offset as usize + bytes.len()
66 );
62 check_read(self, offset, bytes.len())?; 67 check_read(self, offset, bytes.len())?;
63 68
64 let flash_data = unsafe { core::slice::from_raw_parts((FLASH_BASE as u32 + offset) as *const u8, bytes.len()) }; 69 let flash_data = unsafe { core::slice::from_raw_parts((FLASH_BASE as u32 + offset) as *const u8, bytes.len()) };
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index f79f592b4..930de2068 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -411,6 +411,16 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
411 pub fn toggle(&mut self) { 411 pub fn toggle(&mut self) {
412 self.pin.toggle_set_as_output() 412 self.pin.toggle_set_as_output()
413 } 413 }
414
415 #[inline]
416 pub fn is_high(&self) -> bool {
417 self.pin.is_high()
418 }
419
420 #[inline]
421 pub fn is_low(&self) -> bool {
422 self.pin.is_low()
423 }
414} 424}
415 425
416/// GPIO flexible pin. 426/// GPIO flexible pin.
@@ -791,6 +801,18 @@ mod eh02 {
791 } 801 }
792 } 802 }
793 803
804 impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for OutputOpenDrain<'d, T> {
805 type Error = Infallible;
806
807 fn is_high(&self) -> Result<bool, Self::Error> {
808 Ok(self.is_high())
809 }
810
811 fn is_low(&self) -> Result<bool, Self::Error> {
812 Ok(self.is_low())
813 }
814 }
815
794 impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d, T> { 816 impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d, T> {
795 type Error = Infallible; 817 type Error = Infallible;
796 818
@@ -870,9 +892,6 @@ mod eh02 {
870mod eh1 { 892mod eh1 {
871 use core::convert::Infallible; 893 use core::convert::Infallible;
872 894
873 #[cfg(feature = "nightly")]
874 use futures::FutureExt;
875
876 use super::*; 895 use super::*;
877 896
878 impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> { 897 impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> {
@@ -949,6 +968,16 @@ mod eh1 {
949 } 968 }
950 } 969 }
951 970
971 impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> {
972 fn is_high(&self) -> Result<bool, Self::Error> {
973 Ok(self.is_high())
974 }
975
976 fn is_low(&self) -> Result<bool, Self::Error> {
977 Ok(self.is_low())
978 }
979 }
980
952 impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> { 981 impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> {
953 type Error = Infallible; 982 type Error = Infallible;
954 } 983 }
@@ -991,57 +1020,57 @@ mod eh1 {
991 1020
992 #[cfg(feature = "nightly")] 1021 #[cfg(feature = "nightly")]
993 impl<'d, T: Pin> embedded_hal_async::digital::Wait for Flex<'d, T> { 1022 impl<'d, T: Pin> embedded_hal_async::digital::Wait for Flex<'d, T> {
994 type WaitForHighFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 1023 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
995 fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> { 1024 self.wait_for_high().await;
996 self.wait_for_high().map(Ok) 1025 Ok(())
997 } 1026 }
998 1027
999 type WaitForLowFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 1028 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
1000 fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> { 1029 self.wait_for_low().await;
1001 self.wait_for_low().map(Ok) 1030 Ok(())
1002 } 1031 }
1003 1032
1004 type WaitForRisingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 1033 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
1005 fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> { 1034 self.wait_for_rising_edge().await;
1006 self.wait_for_rising_edge().map(Ok) 1035 Ok(())
1007 } 1036 }
1008 1037
1009 type WaitForFallingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 1038 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
1010 fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> { 1039 self.wait_for_falling_edge().await;
1011 self.wait_for_falling_edge().map(Ok) 1040 Ok(())
1012 } 1041 }
1013 1042
1014 type WaitForAnyEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 1043 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
1015 fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> { 1044 self.wait_for_any_edge().await;
1016 self.wait_for_any_edge().map(Ok) 1045 Ok(())
1017 } 1046 }
1018 } 1047 }
1019 1048
1020 #[cfg(feature = "nightly")] 1049 #[cfg(feature = "nightly")]
1021 impl<'d, T: Pin> embedded_hal_async::digital::Wait for Input<'d, T> { 1050 impl<'d, T: Pin> embedded_hal_async::digital::Wait for Input<'d, T> {
1022 type WaitForHighFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 1051 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
1023 fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> { 1052 self.wait_for_high().await;
1024 self.wait_for_high().map(Ok) 1053 Ok(())
1025 } 1054 }
1026 1055
1027 type WaitForLowFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 1056 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
1028 fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> { 1057 self.wait_for_low().await;
1029 self.wait_for_low().map(Ok) 1058 Ok(())
1030 } 1059 }
1031 1060
1032 type WaitForRisingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 1061 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
1033 fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> { 1062 self.wait_for_rising_edge().await;
1034 self.wait_for_rising_edge().map(Ok) 1063 Ok(())
1035 } 1064 }
1036 1065
1037 type WaitForFallingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 1066 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
1038 fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> { 1067 self.wait_for_falling_edge().await;
1039 self.wait_for_falling_edge().map(Ok) 1068 Ok(())
1040 } 1069 }
1041 1070
1042 type WaitForAnyEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 1071 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
1043 fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> { 1072 self.wait_for_any_edge().await;
1044 self.wait_for_any_edge().map(Ok) 1073 Ok(())
1045 } 1074 }
1046 } 1075 }
1047} 1076}
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index d6742f6a6..e48e16d81 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -717,8 +717,6 @@ mod eh1 {
717} 717}
718#[cfg(all(feature = "unstable-traits", feature = "nightly"))] 718#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
719mod nightly { 719mod nightly {
720 use core::future::Future;
721
722 use embedded_hal_1::i2c::Operation; 720 use embedded_hal_1::i2c::Operation;
723 use embedded_hal_async::i2c::AddressMode; 721 use embedded_hal_async::i2c::AddressMode;
724 722
@@ -729,74 +727,55 @@ mod nightly {
729 A: AddressMode + Into<u16> + 'static, 727 A: AddressMode + Into<u16> + 'static,
730 T: Instance + 'd, 728 T: Instance + 'd,
731 { 729 {
732 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a 730 async fn read<'a>(&'a mut self, address: A, read: &'a mut [u8]) -> Result<(), Self::Error> {
733 where Self: 'a;
734 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
735 where Self: 'a;
736 type WriteReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
737 where Self: 'a;
738 type TransactionFuture<'a, 'b> = impl Future<Output = Result<(), Error>> + 'a
739 where Self: 'a, 'b: 'a;
740
741 fn read<'a>(&'a mut self, address: A, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
742 let addr: u16 = address.into(); 731 let addr: u16 = address.into();
743 732
744 async move { 733 Self::setup(addr)?;
745 Self::setup(addr)?; 734 self.read_async_internal(read, false, true).await
746 self.read_async_internal(buffer, false, true).await
747 }
748 } 735 }
749 736
750 fn write<'a>(&'a mut self, address: A, write: &'a [u8]) -> Self::WriteFuture<'a> { 737 async fn write<'a>(&'a mut self, address: A, write: &'a [u8]) -> Result<(), Self::Error> {
751 let addr: u16 = address.into(); 738 let addr: u16 = address.into();
752 739
753 async move { 740 Self::setup(addr)?;
754 Self::setup(addr)?; 741 self.write_async_internal(write.iter().copied(), true).await
755 self.write_async_internal(write.iter().copied(), true).await
756 }
757 } 742 }
758 743 async fn write_read<'a>(
759 fn write_read<'a>(
760 &'a mut self, 744 &'a mut self,
761 address: A, 745 address: A,
762 bytes: &'a [u8], 746 write: &'a [u8],
763 buffer: &'a mut [u8], 747 read: &'a mut [u8],
764 ) -> Self::WriteReadFuture<'a> { 748 ) -> Result<(), Self::Error> {
765 let addr: u16 = address.into(); 749 let addr: u16 = address.into();
766 750
767 async move { 751 Self::setup(addr)?;
768 Self::setup(addr)?; 752 self.write_async_internal(write.iter().cloned(), false).await?;
769 self.write_async_internal(bytes.iter().cloned(), false).await?; 753 self.read_async_internal(read, false, true).await
770 self.read_async_internal(buffer, false, true).await
771 }
772 } 754 }
773 755 async fn transaction<'a, 'b>(
774 fn transaction<'a, 'b>(
775 &'a mut self, 756 &'a mut self,
776 address: A, 757 address: A,
777 operations: &'a mut [Operation<'b>], 758 operations: &'a mut [Operation<'b>],
778 ) -> Self::TransactionFuture<'a, 'b> { 759 ) -> Result<(), Self::Error> {
779 let addr: u16 = address.into(); 760 let addr: u16 = address.into();
780 761
781 async move { 762 let mut iterator = operations.iter_mut();
782 let mut iterator = operations.iter_mut();
783 763
784 while let Some(op) = iterator.next() { 764 while let Some(op) = iterator.next() {
785 let last = iterator.len() == 0; 765 let last = iterator.len() == 0;
786 766
787 match op { 767 match op {
788 Operation::Read(buffer) => { 768 Operation::Read(buffer) => {
789 Self::setup(addr)?; 769 Self::setup(addr)?;
790 self.read_async_internal(buffer, false, last).await?; 770 self.read_async_internal(buffer, false, last).await?;
791 } 771 }
792 Operation::Write(buffer) => { 772 Operation::Write(buffer) => {
793 Self::setup(addr)?; 773 Self::setup(addr)?;
794 self.write_async_internal(buffer.into_iter().cloned(), last).await?; 774 self.write_async_internal(buffer.into_iter().cloned(), last).await?;
795 }
796 } 775 }
797 } 776 }
798 Ok(())
799 } 777 }
778 Ok(())
800 } 779 }
801 } 780 }
802} 781}
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index f608f1768..d21b5f7b0 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -1,11 +1,13 @@
1#![no_std] 1#![no_std]
2#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))] 2#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))]
3#![cfg_attr(feature = "nightly", allow(incomplete_features))]
3 4
4// This mod MUST go first, so that the others see its macros. 5// This mod MUST go first, so that the others see its macros.
5pub(crate) mod fmt; 6pub(crate) mod fmt;
6 7
7mod intrinsics; 8mod intrinsics;
8 9
10pub mod adc;
9pub mod dma; 11pub mod dma;
10pub mod gpio; 12pub mod gpio;
11pub mod i2c; 13pub mod i2c;
@@ -19,7 +21,7 @@ pub mod uart;
19#[cfg(feature = "nightly")] 21#[cfg(feature = "nightly")]
20pub mod usb; 22pub mod usb;
21 23
22mod clocks; 24pub mod clocks;
23pub mod flash; 25pub mod flash;
24mod reset; 26mod reset;
25 27
@@ -98,6 +100,8 @@ embassy_hal_common::peripherals! {
98 RTC, 100 RTC,
99 101
100 FLASH, 102 FLASH,
103
104 ADC,
101} 105}
102 106
103#[link_section = ".boot2"] 107#[link_section = ".boot2"]
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs
index e4b6f0b1d..c173909c7 100644
--- a/embassy-rp/src/rtc/mod.rs
+++ b/embassy-rp/src/rtc/mod.rs
@@ -164,7 +164,7 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
164 } 164 }
165} 165}
166 166
167/// Errors that can occur on methods on [RtcClock] 167/// Errors that can occur on methods on [RealTimeClock]
168#[derive(Clone, Debug, PartialEq, Eq)] 168#[derive(Clone, Debug, PartialEq, Eq)]
169pub enum RtcError { 169pub enum RtcError {
170 /// An invalid DateTime was given or stored on the hardware. 170 /// An invalid DateTime was given or stored on the hardware.
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs
index 754e2dd30..2b7a818d9 100644
--- a/embassy-rp/src/spi.rs
+++ b/embassy-rp/src/spi.rs
@@ -554,45 +554,33 @@ mod eh1 {
554 554
555#[cfg(all(feature = "unstable-traits", feature = "nightly"))] 555#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
556mod eha { 556mod eha {
557 use core::future::Future;
558
559 use super::*; 557 use super::*;
560 558
561 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusFlush for Spi<'d, T, Async> { 559 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusFlush for Spi<'d, T, Async> {
562 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 560 async fn flush(&mut self) -> Result<(), Self::Error> {
563 561 Ok(())
564 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
565 async { Ok(()) }
566 } 562 }
567 } 563 }
568 564
569 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusWrite<u8> for Spi<'d, T, Async> { 565 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusWrite<u8> for Spi<'d, T, Async> {
570 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 566 async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
571 567 self.write(words).await
572 fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> {
573 self.write(data)
574 } 568 }
575 } 569 }
576 570
577 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusRead<u8> for Spi<'d, T, Async> { 571 impl<'d, T: Instance> embedded_hal_async::spi::SpiBusRead<u8> for Spi<'d, T, Async> {
578 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 572 async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
579 573 self.read(words).await
580 fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> {
581 self.read(data)
582 } 574 }
583 } 575 }
584 576
585 impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spi<'d, T, Async> { 577 impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spi<'d, T, Async> {
586 type TransferFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 578 async fn transfer<'a>(&'a mut self, read: &'a mut [u8], write: &'a [u8]) -> Result<(), Self::Error> {
587 579 self.transfer(read, write).await
588 fn transfer<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::TransferFuture<'a> {
589 self.transfer(rx, tx)
590 } 580 }
591 581
592 type TransferInPlaceFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 582 async fn transfer_in_place<'a>(&'a mut self, words: &'a mut [u8]) -> Result<(), Self::Error> {
593 583 self.transfer_in_place(words).await
594 fn transfer_in_place<'a>(&'a mut self, words: &'a mut [u8]) -> Self::TransferInPlaceFuture<'a> {
595 self.transfer_in_place(words)
596 } 584 }
597 } 585 }
598} 586}
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index 4f0a55532..32029f81e 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -1,337 +1,421 @@
1use core::future::{poll_fn, Future}; 1use core::future::{poll_fn, Future};
2use core::task::{Poll, Waker}; 2use core::slice;
3use core::task::Poll;
3 4
4use atomic_polyfill::{compiler_fence, Ordering}; 5use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
5use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; 6use embassy_hal_common::atomic_ring_buffer::RingBuffer;
6use embassy_hal_common::ring_buffer::RingBuffer; 7use embassy_sync::waitqueue::AtomicWaker;
7use embassy_sync::waitqueue::WakerRegistration;
8 8
9use super::*; 9use super::*;
10 10
11pub struct State<'d, T: Instance>(StateStorage<FullStateInner<'d, T>>); 11pub struct State {
12impl<'d, T: Instance> State<'d, T> { 12 tx_waker: AtomicWaker,
13 pub const fn new() -> Self { 13 tx_buf: RingBuffer,
14 Self(StateStorage::new()) 14 rx_waker: AtomicWaker,
15 } 15 rx_buf: RingBuffer,
16}
17
18pub struct RxState<'d, T: Instance>(StateStorage<RxStateInner<'d, T>>);
19impl<'d, T: Instance> RxState<'d, T> {
20 pub const fn new() -> Self {
21 Self(StateStorage::new())
22 }
23} 16}
24 17
25pub struct TxState<'d, T: Instance>(StateStorage<TxStateInner<'d, T>>); 18impl State {
26impl<'d, T: Instance> TxState<'d, T> {
27 pub const fn new() -> Self { 19 pub const fn new() -> Self {
28 Self(StateStorage::new()) 20 Self {
21 rx_buf: RingBuffer::new(),
22 tx_buf: RingBuffer::new(),
23 rx_waker: AtomicWaker::new(),
24 tx_waker: AtomicWaker::new(),
25 }
29 } 26 }
30} 27}
31 28
32struct RxStateInner<'d, T: Instance> {
33 phantom: PhantomData<&'d mut T>,
34
35 waker: WakerRegistration,
36 buf: RingBuffer<'d>,
37}
38
39struct TxStateInner<'d, T: Instance> {
40 phantom: PhantomData<&'d mut T>,
41
42 waker: WakerRegistration,
43 buf: RingBuffer<'d>,
44}
45
46struct FullStateInner<'d, T: Instance> {
47 rx: RxStateInner<'d, T>,
48 tx: TxStateInner<'d, T>,
49}
50
51unsafe impl<'d, T: Instance> Send for RxStateInner<'d, T> {}
52unsafe impl<'d, T: Instance> Sync for RxStateInner<'d, T> {}
53
54unsafe impl<'d, T: Instance> Send for TxStateInner<'d, T> {}
55unsafe impl<'d, T: Instance> Sync for TxStateInner<'d, T> {}
56
57unsafe impl<'d, T: Instance> Send for FullStateInner<'d, T> {}
58unsafe impl<'d, T: Instance> Sync for FullStateInner<'d, T> {}
59
60pub struct BufferedUart<'d, T: Instance> { 29pub struct BufferedUart<'d, T: Instance> {
61 inner: PeripheralMutex<'d, FullStateInner<'d, T>>, 30 phantom: PhantomData<&'d mut T>,
62} 31}
63 32
64pub struct BufferedUartRx<'d, T: Instance> { 33pub struct BufferedUartRx<'d, T: Instance> {
65 inner: PeripheralMutex<'d, RxStateInner<'d, T>>, 34 phantom: PhantomData<&'d mut T>,
66} 35}
67 36
68pub struct BufferedUartTx<'d, T: Instance> { 37pub struct BufferedUartTx<'d, T: Instance> {
69 inner: PeripheralMutex<'d, TxStateInner<'d, T>>, 38 phantom: PhantomData<&'d mut T>,
70} 39}
71 40
72impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {}
73impl<'d, T: Instance> Unpin for BufferedUartRx<'d, T> {}
74impl<'d, T: Instance> Unpin for BufferedUartTx<'d, T> {}
75
76impl<'d, T: Instance> BufferedUart<'d, T> { 41impl<'d, T: Instance> BufferedUart<'d, T> {
77 pub fn new<M: Mode>( 42 pub fn new(
78 state: &'d mut State<'d, T>, 43 _uart: impl Peripheral<P = T> + 'd,
79 _uart: Uart<'d, T, M>, 44 irq: impl Peripheral<P = T::Interrupt> + 'd,
45 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
46 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
47 tx_buffer: &'d mut [u8],
48 rx_buffer: &'d mut [u8],
49 config: Config,
50 ) -> Self {
51 into_ref!(tx, rx);
52 Self::new_inner(
53 irq,
54 tx.map_into(),
55 rx.map_into(),
56 None,
57 None,
58 tx_buffer,
59 rx_buffer,
60 config,
61 )
62 }
63
64 pub fn new_with_rtscts(
65 _uart: impl Peripheral<P = T> + 'd,
66 irq: impl Peripheral<P = T::Interrupt> + 'd,
67 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
68 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
69 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
70 cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
71 tx_buffer: &'d mut [u8],
72 rx_buffer: &'d mut [u8],
73 config: Config,
74 ) -> Self {
75 into_ref!(tx, rx, cts, rts);
76 Self::new_inner(
77 irq,
78 tx.map_into(),
79 rx.map_into(),
80 Some(rts.map_into()),
81 Some(cts.map_into()),
82 tx_buffer,
83 rx_buffer,
84 config,
85 )
86 }
87
88 fn new_inner(
80 irq: impl Peripheral<P = T::Interrupt> + 'd, 89 irq: impl Peripheral<P = T::Interrupt> + 'd,
90 mut tx: PeripheralRef<'d, AnyPin>,
91 mut rx: PeripheralRef<'d, AnyPin>,
92 mut rts: Option<PeripheralRef<'d, AnyPin>>,
93 mut cts: Option<PeripheralRef<'d, AnyPin>>,
81 tx_buffer: &'d mut [u8], 94 tx_buffer: &'d mut [u8],
82 rx_buffer: &'d mut [u8], 95 rx_buffer: &'d mut [u8],
83 ) -> BufferedUart<'d, T> { 96 config: Config,
97 ) -> Self {
84 into_ref!(irq); 98 into_ref!(irq);
99 super::Uart::<'d, T, Async>::init(
100 Some(tx.reborrow()),
101 Some(rx.reborrow()),
102 rts.as_mut().map(|x| x.reborrow()),
103 cts.as_mut().map(|x| x.reborrow()),
104 config,
105 );
106
107 let state = T::state();
108 let regs = T::regs();
109
110 let len = tx_buffer.len();
111 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
112 let len = rx_buffer.len();
113 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
85 114
86 let r = T::regs();
87 unsafe { 115 unsafe {
88 r.uartimsc().modify(|w| { 116 regs.uartimsc().modify(|w| {
89 w.set_rxim(true); 117 w.set_rxim(true);
90 w.set_rtim(true); 118 w.set_rtim(true);
91 w.set_txim(true); 119 w.set_txim(true);
92 }); 120 });
93 } 121 }
94 122
95 Self { 123 irq.set_handler(on_interrupt::<T>);
96 inner: PeripheralMutex::new(irq, &mut state.0, move || FullStateInner { 124 irq.unpend();
97 tx: TxStateInner { 125 irq.enable();
98 phantom: PhantomData, 126
99 waker: WakerRegistration::new(), 127 Self { phantom: PhantomData }
100 buf: RingBuffer::new(tx_buffer),
101 },
102 rx: RxStateInner {
103 phantom: PhantomData,
104 waker: WakerRegistration::new(),
105 buf: RingBuffer::new(rx_buffer),
106 },
107 }),
108 }
109 } 128 }
110} 129}
111 130
112impl<'d, T: Instance> BufferedUartRx<'d, T> { 131impl<'d, T: Instance> BufferedUartRx<'d, T> {
113 pub fn new<M: Mode>( 132 pub fn new(
114 state: &'d mut RxState<'d, T>, 133 _uart: impl Peripheral<P = T> + 'd,
115 _uart: UartRx<'d, T, M>,
116 irq: impl Peripheral<P = T::Interrupt> + 'd, 134 irq: impl Peripheral<P = T::Interrupt> + 'd,
135 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
117 rx_buffer: &'d mut [u8], 136 rx_buffer: &'d mut [u8],
118 ) -> BufferedUartRx<'d, T> { 137 config: Config,
138 ) -> Self {
139 into_ref!(rx);
140 Self::new_inner(irq, rx.map_into(), None, rx_buffer, config)
141 }
142
143 pub fn new_with_rts(
144 _uart: impl Peripheral<P = T> + 'd,
145 irq: impl Peripheral<P = T::Interrupt> + 'd,
146 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
147 rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
148 rx_buffer: &'d mut [u8],
149 config: Config,
150 ) -> Self {
151 into_ref!(rx, rts);
152 Self::new_inner(irq, rx.map_into(), Some(rts.map_into()), rx_buffer, config)
153 }
154
155 fn new_inner(
156 irq: impl Peripheral<P = T::Interrupt> + 'd,
157 mut rx: PeripheralRef<'d, AnyPin>,
158 mut rts: Option<PeripheralRef<'d, AnyPin>>,
159 rx_buffer: &'d mut [u8],
160 config: Config,
161 ) -> Self {
119 into_ref!(irq); 162 into_ref!(irq);
163 super::Uart::<'d, T, Async>::init(
164 None,
165 Some(rx.reborrow()),
166 rts.as_mut().map(|x| x.reborrow()),
167 None,
168 config,
169 );
170
171 let state = T::state();
172 let regs = T::regs();
173
174 let len = rx_buffer.len();
175 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
120 176
121 let r = T::regs();
122 unsafe { 177 unsafe {
123 r.uartimsc().modify(|w| { 178 regs.uartimsc().modify(|w| {
124 w.set_rxim(true); 179 w.set_rxim(true);
125 w.set_rtim(true); 180 w.set_rtim(true);
126 }); 181 });
127 } 182 }
128 183
129 Self { 184 irq.set_handler(on_interrupt::<T>);
130 inner: PeripheralMutex::new(irq, &mut state.0, move || RxStateInner { 185 irq.unpend();
131 phantom: PhantomData, 186 irq.enable();
132 187
133 buf: RingBuffer::new(rx_buffer), 188 Self { phantom: PhantomData }
134 waker: WakerRegistration::new(), 189 }
135 }), 190
136 } 191 fn read<'a>(buf: &'a mut [u8]) -> impl Future<Output = Result<usize, Error>> + 'a {
192 poll_fn(move |cx| {
193 let state = T::state();
194 let mut rx_reader = unsafe { state.rx_buf.reader() };
195 let n = rx_reader.pop(|data| {
196 let n = data.len().min(buf.len());
197 buf[..n].copy_from_slice(&data[..n]);
198 n
199 });
200 if n == 0 {
201 state.rx_waker.register(cx.waker());
202 return Poll::Pending;
203 }
204
205 Poll::Ready(Ok(n))
206 })
207 }
208
209 fn fill_buf<'a>() -> impl Future<Output = Result<&'a [u8], Error>> {
210 poll_fn(move |cx| {
211 let state = T::state();
212 let mut rx_reader = unsafe { state.rx_buf.reader() };
213 let (p, n) = rx_reader.pop_buf();
214 if n == 0 {
215 state.rx_waker.register(cx.waker());
216 return Poll::Pending;
217 }
218
219 let buf = unsafe { slice::from_raw_parts(p, n) };
220 Poll::Ready(Ok(buf))
221 })
222 }
223
224 fn consume(amt: usize) {
225 let state = T::state();
226 let mut rx_reader = unsafe { state.rx_buf.reader() };
227 rx_reader.pop_done(amt)
137 } 228 }
138} 229}
139 230
140impl<'d, T: Instance> BufferedUartTx<'d, T> { 231impl<'d, T: Instance> BufferedUartTx<'d, T> {
141 pub fn new<M: Mode>( 232 pub fn new(
142 state: &'d mut TxState<'d, T>, 233 _uart: impl Peripheral<P = T> + 'd,
143 _uart: UartTx<'d, T, M>, 234 irq: impl Peripheral<P = T::Interrupt> + 'd,
235 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
236 tx_buffer: &'d mut [u8],
237 config: Config,
238 ) -> Self {
239 into_ref!(tx);
240 Self::new_inner(irq, tx.map_into(), None, tx_buffer, config)
241 }
242
243 pub fn new_with_cts(
244 _uart: impl Peripheral<P = T> + 'd,
144 irq: impl Peripheral<P = T::Interrupt> + 'd, 245 irq: impl Peripheral<P = T::Interrupt> + 'd,
246 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
247 cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
145 tx_buffer: &'d mut [u8], 248 tx_buffer: &'d mut [u8],
146 ) -> BufferedUartTx<'d, T> { 249 config: Config,
250 ) -> Self {
251 into_ref!(tx, cts);
252 Self::new_inner(irq, tx.map_into(), Some(cts.map_into()), tx_buffer, config)
253 }
254
255 fn new_inner(
256 irq: impl Peripheral<P = T::Interrupt> + 'd,
257 mut tx: PeripheralRef<'d, AnyPin>,
258 mut cts: Option<PeripheralRef<'d, AnyPin>>,
259 tx_buffer: &'d mut [u8],
260 config: Config,
261 ) -> Self {
147 into_ref!(irq); 262 into_ref!(irq);
263 super::Uart::<'d, T, Async>::init(
264 Some(tx.reborrow()),
265 None,
266 None,
267 cts.as_mut().map(|x| x.reborrow()),
268 config,
269 );
270
271 let state = T::state();
272 let regs = T::regs();
273
274 let len = tx_buffer.len();
275 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
148 276
149 let r = T::regs();
150 unsafe { 277 unsafe {
151 r.uartimsc().modify(|w| { 278 regs.uartimsc().modify(|w| {
152 w.set_txim(true); 279 w.set_txim(true);
153 }); 280 });
154 } 281 }
155 282
156 Self { 283 irq.set_handler(on_interrupt::<T>);
157 inner: PeripheralMutex::new(irq, &mut state.0, move || TxStateInner { 284 irq.unpend();
158 phantom: PhantomData, 285 irq.enable();
159 286
160 buf: RingBuffer::new(tx_buffer), 287 Self { phantom: PhantomData }
161 waker: WakerRegistration::new(),
162 }),
163 }
164 } 288 }
165}
166 289
167impl<'d, T: Instance> PeripheralState for FullStateInner<'d, T> 290 fn write<'a>(buf: &'a [u8]) -> impl Future<Output = Result<usize, Error>> + 'a {
168where 291 poll_fn(move |cx| {
169 Self: 'd, 292 let state = T::state();
170{ 293 let mut tx_writer = unsafe { state.tx_buf.writer() };
171 type Interrupt = T::Interrupt; 294 let n = tx_writer.push(|data| {
172 fn on_interrupt(&mut self) { 295 let n = data.len().min(buf.len());
173 self.rx.on_interrupt(); 296 data[..n].copy_from_slice(&buf[..n]);
174 self.tx.on_interrupt(); 297 n
298 });
299 if n == 0 {
300 state.tx_waker.register(cx.waker());
301 return Poll::Pending;
302 } else {
303 unsafe { T::Interrupt::steal() }.pend();
304 }
305
306 Poll::Ready(Ok(n))
307 })
175 } 308 }
176}
177 309
178impl<'d, T: Instance> RxStateInner<'d, T> 310 fn flush() -> impl Future<Output = Result<(), Error>> {
179where 311 poll_fn(move |cx| {
180 Self: 'd, 312 let state = T::state();
181{ 313 if !state.tx_buf.is_empty() {
182 fn read(&mut self, buf: &mut [u8], waker: &Waker) -> (Poll<Result<usize, Error>>, bool) { 314 state.tx_waker.register(cx.waker());
183 // We have data ready in buffer? Return it. 315 return Poll::Pending;
184 let mut do_pend = false;
185 let data = self.buf.pop_buf();
186 if !data.is_empty() {
187 let len = data.len().min(buf.len());
188 buf[..len].copy_from_slice(&data[..len]);
189
190 if self.buf.is_full() {
191 do_pend = true;
192 } 316 }
193 self.buf.pop(len);
194
195 return (Poll::Ready(Ok(len)), do_pend);
196 }
197 317
198 self.waker.register(waker); 318 Poll::Ready(Ok(()))
199 (Poll::Pending, do_pend) 319 })
200 } 320 }
321}
201 322
202 fn fill_buf<'a>(&mut self, waker: &Waker) -> Poll<Result<&'a [u8], Error>> { 323impl<'d, T: Instance> Drop for BufferedUart<'d, T> {
203 // We have data ready in buffer? Return it. 324 fn drop(&mut self) {
204 let buf = self.buf.pop_buf(); 325 unsafe {
205 if !buf.is_empty() { 326 T::Interrupt::steal().disable();
206 let buf: &[u8] = buf; 327 let state = T::state();
207 // Safety: buffer lives as long as uart 328 state.tx_buf.deinit();
208 let buf: &[u8] = unsafe { core::mem::transmute(buf) }; 329 state.rx_buf.deinit();
209 return Poll::Ready(Ok(buf));
210 } 330 }
211
212 self.waker.register(waker);
213 Poll::Pending
214 } 331 }
332}
215 333
216 fn consume(&mut self, amt: usize) -> bool { 334impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {
217 let full = self.buf.is_full(); 335 fn drop(&mut self) {
218 self.buf.pop(amt); 336 unsafe {
219 full 337 T::Interrupt::steal().disable();
338 let state = T::state();
339 state.tx_buf.deinit();
340 state.rx_buf.deinit();
341 }
220 } 342 }
221} 343}
222 344
223impl<'d, T: Instance> PeripheralState for RxStateInner<'d, T> 345impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
224where 346 fn drop(&mut self) {
225 Self: 'd,
226{
227 type Interrupt = T::Interrupt;
228 fn on_interrupt(&mut self) {
229 let r = T::regs();
230 unsafe { 347 unsafe {
231 let ris = r.uartris().read(); 348 T::Interrupt::steal().disable();
232 // Clear interrupt flags 349 let state = T::state();
233 r.uarticr().modify(|w| { 350 state.tx_buf.deinit();
234 w.set_rxic(true); 351 state.rx_buf.deinit();
235 w.set_rtic(true);
236 });
237
238 if ris.peris() {
239 warn!("Parity error");
240 r.uarticr().modify(|w| {
241 w.set_peic(true);
242 });
243 }
244 if ris.feris() {
245 warn!("Framing error");
246 r.uarticr().modify(|w| {
247 w.set_feic(true);
248 });
249 }
250 if ris.beris() {
251 warn!("Break error");
252 r.uarticr().modify(|w| {
253 w.set_beic(true);
254 });
255 }
256 if ris.oeris() {
257 warn!("Overrun error");
258 r.uarticr().modify(|w| {
259 w.set_oeic(true);
260 });
261 }
262
263 if !r.uartfr().read().rxfe() {
264 let buf = self.buf.push_buf();
265 if !buf.is_empty() {
266 buf[0] = r.uartdr().read().data();
267 self.buf.push(1);
268 } else {
269 warn!("RX buffer full, discard received byte");
270 }
271
272 if self.buf.is_full() {
273 self.waker.wake();
274 }
275 }
276
277 if ris.rtris() {
278 self.waker.wake();
279 };
280 } 352 }
281 } 353 }
282} 354}
283 355
284impl<'d, T: Instance> TxStateInner<'d, T> 356pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) {
285where 357 trace!("on_interrupt");
286 Self: 'd,
287{
288 fn write(&mut self, buf: &[u8], waker: &Waker) -> (Poll<Result<usize, Error>>, bool) {
289 let empty = self.buf.is_empty();
290 let tx_buf = self.buf.push_buf();
291 if tx_buf.is_empty() {
292 self.waker.register(waker);
293 return (Poll::Pending, empty);
294 }
295 358
296 let n = core::cmp::min(tx_buf.len(), buf.len()); 359 let r = T::regs();
297 tx_buf[..n].copy_from_slice(&buf[..n]); 360 let s = T::state();
298 self.buf.push(n);
299 361
300 (Poll::Ready(Ok(n)), empty) 362 unsafe {
301 } 363 // RX
302 364
303 fn flush(&mut self, waker: &Waker) -> Poll<Result<(), Error>> { 365 let ris = r.uartris().read();
304 if !self.buf.is_empty() { 366 // Clear interrupt flags
305 self.waker.register(waker); 367 r.uarticr().write(|w| {
306 return Poll::Pending; 368 w.set_rxic(true);
307 } 369 w.set_rtic(true);
370 });
308 371
309 Poll::Ready(Ok(())) 372 if ris.peris() {
310 } 373 warn!("Parity error");
311} 374 r.uarticr().write(|w| {
375 w.set_peic(true);
376 });
377 }
378 if ris.feris() {
379 warn!("Framing error");
380 r.uarticr().write(|w| {
381 w.set_feic(true);
382 });
383 }
384 if ris.beris() {
385 warn!("Break error");
386 r.uarticr().write(|w| {
387 w.set_beic(true);
388 });
389 }
390 if ris.oeris() {
391 warn!("Overrun error");
392 r.uarticr().write(|w| {
393 w.set_oeic(true);
394 });
395 }
312 396
313impl<'d, T: Instance> PeripheralState for TxStateInner<'d, T> 397 let mut rx_writer = s.rx_buf.writer();
314where 398 if !r.uartfr().read().rxfe() {
315 Self: 'd, 399 let val = r.uartdr().read().data();
316{ 400 if !rx_writer.push_one(val) {
317 type Interrupt = T::Interrupt; 401 warn!("RX buffer full, discard received byte");
318 fn on_interrupt(&mut self) {
319 let r = T::regs();
320 unsafe {
321 let buf = self.buf.pop_buf();
322 if !buf.is_empty() {
323 r.uartimsc().modify(|w| {
324 w.set_txim(true);
325 });
326 r.uartdr().write(|w| w.set_data(buf[0].into()));
327 self.buf.pop(1);
328 self.waker.wake();
329 } else {
330 // Disable interrupt until we have something to transmit again
331 r.uartimsc().modify(|w| {
332 w.set_txim(false);
333 });
334 } 402 }
403 s.rx_waker.wake();
404 }
405
406 // TX
407 let mut tx_reader = s.tx_buf.reader();
408 if let Some(val) = tx_reader.pop_one() {
409 r.uartimsc().modify(|w| {
410 w.set_txim(true);
411 });
412 r.uartdr().write(|w| w.set_data(val));
413 s.tx_waker.wake();
414 } else {
415 // Disable interrupt until we have something to transmit again
416 r.uartimsc().modify(|w| {
417 w.set_txim(false);
418 });
335 } 419 }
336 } 420 }
337} 421}
@@ -355,135 +439,53 @@ impl<'d, T: Instance> embedded_io::Io for BufferedUartTx<'d, T> {
355} 439}
356 440
357impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { 441impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> {
358 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 442 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
359 where 443 BufferedUartRx::<'d, T>::read(buf).await
360 Self: 'a;
361
362 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
363 poll_fn(move |cx| {
364 let (res, do_pend) = self.inner.with(|state| {
365 compiler_fence(Ordering::SeqCst);
366 state.rx.read(buf, cx.waker())
367 });
368
369 if do_pend {
370 self.inner.pend();
371 }
372
373 res
374 })
375 } 444 }
376} 445}
377 446
378impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUartRx<'d, T> { 447impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUartRx<'d, T> {
379 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 448 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
380 where 449 Self::read(buf).await
381 Self: 'a;
382
383 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
384 poll_fn(move |cx| {
385 let (res, do_pend) = self.inner.with(|state| {
386 compiler_fence(Ordering::SeqCst);
387 state.read(buf, cx.waker())
388 });
389
390 if do_pend {
391 self.inner.pend();
392 }
393
394 res
395 })
396 } 450 }
397} 451}
398 452
399impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> { 453impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> {
400 type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a 454 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
401 where 455 BufferedUartRx::<'d, T>::fill_buf().await
402 Self: 'a;
403
404 fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> {
405 poll_fn(move |cx| {
406 self.inner.with(|state| {
407 compiler_fence(Ordering::SeqCst);
408 state.rx.fill_buf(cx.waker())
409 })
410 })
411 } 456 }
412 457
413 fn consume(&mut self, amt: usize) { 458 fn consume(&mut self, amt: usize) {
414 let signal = self.inner.with(|state| state.rx.consume(amt)); 459 BufferedUartRx::<'d, T>::consume(amt)
415 if signal {
416 self.inner.pend();
417 }
418 } 460 }
419} 461}
420 462
421impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUartRx<'d, T> { 463impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUartRx<'d, T> {
422 type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a 464 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
423 where 465 Self::fill_buf().await
424 Self: 'a;
425
426 fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> {
427 poll_fn(move |cx| {
428 self.inner.with(|state| {
429 compiler_fence(Ordering::SeqCst);
430 state.fill_buf(cx.waker())
431 })
432 })
433 } 466 }
434 467
435 fn consume(&mut self, amt: usize) { 468 fn consume(&mut self, amt: usize) {
436 let signal = self.inner.with(|state| state.consume(amt)); 469 Self::consume(amt)
437 if signal {
438 self.inner.pend();
439 }
440 } 470 }
441} 471}
442 472
443impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { 473impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> {
444 type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 474 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
445 where 475 BufferedUartTx::<'d, T>::write(buf).await
446 Self: 'a;
447
448 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
449 poll_fn(move |cx| {
450 let (poll, empty) = self.inner.with(|state| state.tx.write(buf, cx.waker()));
451 if empty {
452 self.inner.pend();
453 }
454 poll
455 })
456 } 476 }
457 477
458 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a 478 async fn flush(&mut self) -> Result<(), Self::Error> {
459 where 479 BufferedUartTx::<'d, T>::flush().await
460 Self: 'a;
461
462 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
463 poll_fn(move |cx| self.inner.with(|state| state.tx.flush(cx.waker())))
464 } 480 }
465} 481}
466 482
467impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUartTx<'d, T> { 483impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUartTx<'d, T> {
468 type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 484 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
469 where 485 Self::write(buf).await
470 Self: 'a;
471
472 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
473 poll_fn(move |cx| {
474 let (poll, empty) = self.inner.with(|state| state.write(buf, cx.waker()));
475 if empty {
476 self.inner.pend();
477 }
478 poll
479 })
480 } 486 }
481 487
482 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a 488 async fn flush(&mut self) -> Result<(), Self::Error> {
483 where 489 Self::flush().await
484 Self: 'a;
485
486 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
487 poll_fn(move |cx| self.inner.with(|state| state.flush(cx.waker())))
488 } 490 }
489} 491}
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index 56c25e189..7e7bcaf30 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -7,6 +7,11 @@ use crate::gpio::sealed::Pin;
7use crate::gpio::AnyPin; 7use crate::gpio::AnyPin;
8use crate::{pac, peripherals, Peripheral}; 8use crate::{pac, peripherals, Peripheral};
9 9
10#[cfg(feature = "nightly")]
11mod buffered;
12#[cfg(feature = "nightly")]
13pub use buffered::{BufferedUart, BufferedUartRx, BufferedUartTx};
14
10#[derive(Clone, Copy, PartialEq, Eq, Debug)] 15#[derive(Clone, Copy, PartialEq, Eq, Debug)]
11pub enum DataBits { 16pub enum DataBits {
12 DataBits5, 17 DataBits5,
@@ -196,7 +201,7 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
196 config: Config, 201 config: Config,
197 ) -> Self { 202 ) -> Self {
198 into_ref!(tx, rx); 203 into_ref!(tx, rx);
199 Self::new_inner(uart, rx.map_into(), tx.map_into(), None, None, None, None, config) 204 Self::new_inner(uart, tx.map_into(), rx.map_into(), None, None, None, None, config)
200 } 205 }
201 206
202 /// Create a new UART with hardware flow control (RTS/CTS) 207 /// Create a new UART with hardware flow control (RTS/CTS)
@@ -211,8 +216,8 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
211 into_ref!(tx, rx, cts, rts); 216 into_ref!(tx, rx, cts, rts);
212 Self::new_inner( 217 Self::new_inner(
213 uart, 218 uart,
214 rx.map_into(),
215 tx.map_into(), 219 tx.map_into(),
220 rx.map_into(),
216 Some(rts.map_into()), 221 Some(rts.map_into()),
217 Some(cts.map_into()), 222 Some(cts.map_into()),
218 None, 223 None,
@@ -235,8 +240,8 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
235 into_ref!(tx, rx, tx_dma, rx_dma); 240 into_ref!(tx, rx, tx_dma, rx_dma);
236 Self::new_inner( 241 Self::new_inner(
237 uart, 242 uart,
238 rx.map_into(),
239 tx.map_into(), 243 tx.map_into(),
244 rx.map_into(),
240 None, 245 None,
241 None, 246 None,
242 Some(tx_dma.map_into()), 247 Some(tx_dma.map_into()),
@@ -259,8 +264,8 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
259 into_ref!(tx, rx, cts, rts, tx_dma, rx_dma); 264 into_ref!(tx, rx, cts, rts, tx_dma, rx_dma);
260 Self::new_inner( 265 Self::new_inner(
261 uart, 266 uart,
262 rx.map_into(),
263 tx.map_into(), 267 tx.map_into(),
268 rx.map_into(),
264 Some(rts.map_into()), 269 Some(rts.map_into()),
265 Some(cts.map_into()), 270 Some(cts.map_into()),
266 Some(tx_dma.map_into()), 271 Some(tx_dma.map_into()),
@@ -273,41 +278,52 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
273impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { 278impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
274 fn new_inner( 279 fn new_inner(
275 _uart: impl Peripheral<P = T> + 'd, 280 _uart: impl Peripheral<P = T> + 'd,
276 tx: PeripheralRef<'d, AnyPin>, 281 mut tx: PeripheralRef<'d, AnyPin>,
277 rx: PeripheralRef<'d, AnyPin>, 282 mut rx: PeripheralRef<'d, AnyPin>,
278 rts: Option<PeripheralRef<'d, AnyPin>>, 283 mut rts: Option<PeripheralRef<'d, AnyPin>>,
279 cts: Option<PeripheralRef<'d, AnyPin>>, 284 mut cts: Option<PeripheralRef<'d, AnyPin>>,
280 tx_dma: Option<PeripheralRef<'d, AnyChannel>>, 285 tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
281 rx_dma: Option<PeripheralRef<'d, AnyChannel>>, 286 rx_dma: Option<PeripheralRef<'d, AnyChannel>>,
282 config: Config, 287 config: Config,
283 ) -> Self { 288 ) -> Self {
284 into_ref!(_uart); 289 Self::init(
285 290 Some(tx.reborrow()),
286 unsafe { 291 Some(rx.reborrow()),
287 let r = T::regs(); 292 rts.as_mut().map(|x| x.reborrow()),
288 293 cts.as_mut().map(|x| x.reborrow()),
289 tx.io().ctrl().write(|w| w.set_funcsel(2)); 294 config,
290 rx.io().ctrl().write(|w| w.set_funcsel(2)); 295 );
291
292 tx.pad_ctrl().write(|w| {
293 w.set_ie(true);
294 });
295 296
296 rx.pad_ctrl().write(|w| { 297 Self {
297 w.set_ie(true); 298 tx: UartTx::new(tx_dma),
298 }); 299 rx: UartRx::new(rx_dma),
300 }
301 }
299 302
303 fn init(
304 tx: Option<PeripheralRef<'_, AnyPin>>,
305 rx: Option<PeripheralRef<'_, AnyPin>>,
306 rts: Option<PeripheralRef<'_, AnyPin>>,
307 cts: Option<PeripheralRef<'_, AnyPin>>,
308 config: Config,
309 ) {
310 let r = T::regs();
311 unsafe {
312 if let Some(pin) = &tx {
313 pin.io().ctrl().write(|w| w.set_funcsel(2));
314 pin.pad_ctrl().write(|w| w.set_ie(true));
315 }
316 if let Some(pin) = &rx {
317 pin.io().ctrl().write(|w| w.set_funcsel(2));
318 pin.pad_ctrl().write(|w| w.set_ie(true));
319 }
300 if let Some(pin) = &cts { 320 if let Some(pin) = &cts {
301 pin.io().ctrl().write(|w| w.set_funcsel(2)); 321 pin.io().ctrl().write(|w| w.set_funcsel(2));
302 pin.pad_ctrl().write(|w| { 322 pin.pad_ctrl().write(|w| w.set_ie(true));
303 w.set_ie(true);
304 });
305 } 323 }
306 if let Some(pin) = &rts { 324 if let Some(pin) = &rts {
307 pin.io().ctrl().write(|w| w.set_funcsel(2)); 325 pin.io().ctrl().write(|w| w.set_funcsel(2));
308 pin.pad_ctrl().write(|w| { 326 pin.pad_ctrl().write(|w| w.set_ie(true));
309 w.set_ie(true);
310 });
311 } 327 }
312 328
313 let clk_base = crate::clocks::clk_peri_freq(); 329 let clk_base = crate::clocks::clk_peri_freq();
@@ -359,11 +375,6 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
359 w.set_rtsen(rts.is_some()); 375 w.set_rtsen(rts.is_some());
360 }); 376 });
361 } 377 }
362
363 Self {
364 tx: UartTx::new(tx_dma),
365 rx: UartRx::new(rx_dma),
366 }
367 } 378 }
368} 379}
369 380
@@ -611,11 +622,6 @@ mod eha {
611 } 622 }
612} 623}
613 624
614#[cfg(feature = "nightly")]
615mod buffered;
616#[cfg(feature = "nightly")]
617pub use buffered::*;
618
619mod sealed { 625mod sealed {
620 use super::*; 626 use super::*;
621 627
@@ -628,6 +634,9 @@ mod sealed {
628 type Interrupt: crate::interrupt::Interrupt; 634 type Interrupt: crate::interrupt::Interrupt;
629 635
630 fn regs() -> pac::uart::Uart; 636 fn regs() -> pac::uart::Uart;
637
638 #[cfg(feature = "nightly")]
639 fn state() -> &'static buffered::State;
631 } 640 }
632 pub trait TxPin<T: Instance> {} 641 pub trait TxPin<T: Instance> {}
633 pub trait RxPin<T: Instance> {} 642 pub trait RxPin<T: Instance> {}
@@ -663,6 +672,12 @@ macro_rules! impl_instance {
663 fn regs() -> pac::uart::Uart { 672 fn regs() -> pac::uart::Uart {
664 pac::$inst 673 pac::$inst
665 } 674 }
675
676 #[cfg(feature = "nightly")]
677 fn state() -> &'static buffered::State {
678 static STATE: buffered::State = buffered::State::new();
679 &STATE
680 }
666 } 681 }
667 impl Instance for peripherals::$inst {} 682 impl Instance for peripherals::$inst {}
668 }; 683 };
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index 6dc90b98e..dfc2e9da6 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -1,4 +1,4 @@
1use core::future::{poll_fn, Future}; 1use core::future::poll_fn;
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::slice; 3use core::slice;
4use core::sync::atomic::Ordering; 4use core::sync::atomic::Ordering;
@@ -352,9 +352,7 @@ pub struct Bus<'d, T: Instance> {
352} 352}
353 353
354impl<'d, T: Instance> driver::Bus for Bus<'d, T> { 354impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
355 type PollFuture<'a> = impl Future<Output = Event> + 'a where Self: 'a; 355 async fn poll(&mut self) -> Event {
356
357 fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> {
358 poll_fn(move |cx| unsafe { 356 poll_fn(move |cx| unsafe {
359 BUS_WAKER.register(cx.waker()); 357 BUS_WAKER.register(cx.waker());
360 358
@@ -406,6 +404,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
406 }); 404 });
407 Poll::Pending 405 Poll::Pending
408 }) 406 })
407 .await
409 } 408 }
410 409
411 #[inline] 410 #[inline]
@@ -456,22 +455,12 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
456 } 455 }
457 } 456 }
458 457
459 type EnableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; 458 async fn enable(&mut self) {}
460
461 fn enable(&mut self) -> Self::EnableFuture<'_> {
462 async move {}
463 }
464
465 type DisableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
466
467 fn disable(&mut self) -> Self::DisableFuture<'_> {
468 async move {}
469 }
470 459
471 type RemoteWakeupFuture<'a> = impl Future<Output = Result<(), Unsupported>> + 'a where Self: 'a; 460 async fn disable(&mut self) {}
472 461
473 fn remote_wakeup(&mut self) -> Self::RemoteWakeupFuture<'_> { 462 async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
474 async move { Err(Unsupported) } 463 Err(Unsupported)
475 } 464 }
476} 465}
477 466
@@ -515,24 +504,20 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
515 &self.info 504 &self.info
516 } 505 }
517 506
518 type WaitEnabledFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; 507 async fn wait_enabled(&mut self) {
519 508 trace!("wait_enabled IN WAITING");
520 fn wait_enabled(&mut self) -> Self::WaitEnabledFuture<'_> { 509 let index = self.info.addr.index();
521 async move { 510 poll_fn(|cx| {
522 trace!("wait_enabled IN WAITING"); 511 EP_IN_WAKERS[index].register(cx.waker());
523 let index = self.info.addr.index(); 512 let val = unsafe { T::dpram().ep_in_control(self.info.addr.index() - 1).read() };
524 poll_fn(|cx| { 513 if val.enable() {
525 EP_IN_WAKERS[index].register(cx.waker()); 514 Poll::Ready(())
526 let val = unsafe { T::dpram().ep_in_control(self.info.addr.index() - 1).read() }; 515 } else {
527 if val.enable() { 516 Poll::Pending
528 Poll::Ready(()) 517 }
529 } else { 518 })
530 Poll::Pending 519 .await;
531 } 520 trace!("wait_enabled IN OK");
532 })
533 .await;
534 trace!("wait_enabled IN OK");
535 }
536 } 521 }
537} 522}
538 523
@@ -541,117 +526,105 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> {
541 &self.info 526 &self.info
542 } 527 }
543 528
544 type WaitEnabledFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; 529 async fn wait_enabled(&mut self) {
545 530 trace!("wait_enabled OUT WAITING");
546 fn wait_enabled(&mut self) -> Self::WaitEnabledFuture<'_> { 531 let index = self.info.addr.index();
547 async move { 532 poll_fn(|cx| {
548 trace!("wait_enabled OUT WAITING"); 533 EP_OUT_WAKERS[index].register(cx.waker());
549 let index = self.info.addr.index(); 534 let val = unsafe { T::dpram().ep_out_control(self.info.addr.index() - 1).read() };
550 poll_fn(|cx| { 535 if val.enable() {
551 EP_OUT_WAKERS[index].register(cx.waker()); 536 Poll::Ready(())
552 let val = unsafe { T::dpram().ep_out_control(self.info.addr.index() - 1).read() }; 537 } else {
553 if val.enable() { 538 Poll::Pending
554 Poll::Ready(()) 539 }
555 } else { 540 })
556 Poll::Pending 541 .await;
557 } 542 trace!("wait_enabled OUT OK");
558 })
559 .await;
560 trace!("wait_enabled OUT OK");
561 }
562 } 543 }
563} 544}
564 545
565impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { 546impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
566 type ReadFuture<'a> = impl Future<Output = Result<usize, EndpointError>> + 'a where Self: 'a; 547 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
567 548 trace!("READ WAITING, buf.len() = {}", buf.len());
568 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { 549 let index = self.info.addr.index();
569 async move { 550 let val = poll_fn(|cx| unsafe {
570 trace!("READ WAITING, buf.len() = {}", buf.len()); 551 EP_OUT_WAKERS[index].register(cx.waker());
571 let index = self.info.addr.index(); 552 let val = T::dpram().ep_out_buffer_control(index).read();
572 let val = poll_fn(|cx| unsafe { 553 if val.available(0) {
573 EP_OUT_WAKERS[index].register(cx.waker()); 554 Poll::Pending
574 let val = T::dpram().ep_out_buffer_control(index).read(); 555 } else {
575 if val.available(0) { 556 Poll::Ready(val)
576 Poll::Pending
577 } else {
578 Poll::Ready(val)
579 }
580 })
581 .await;
582
583 let rx_len = val.length(0) as usize;
584 if rx_len > buf.len() {
585 return Err(EndpointError::BufferOverflow);
586 } 557 }
587 self.buf.read(&mut buf[..rx_len]); 558 })
559 .await;
588 560
589 trace!("READ OK, rx_len = {}", rx_len); 561 let rx_len = val.length(0) as usize;
562 if rx_len > buf.len() {
563 return Err(EndpointError::BufferOverflow);
564 }
565 self.buf.read(&mut buf[..rx_len]);
590 566
591 unsafe { 567 trace!("READ OK, rx_len = {}", rx_len);
592 let pid = !val.pid(0);
593 T::dpram().ep_out_buffer_control(index).write(|w| {
594 w.set_pid(0, pid);
595 w.set_length(0, self.info.max_packet_size);
596 });
597 cortex_m::asm::delay(12);
598 T::dpram().ep_out_buffer_control(index).write(|w| {
599 w.set_pid(0, pid);
600 w.set_length(0, self.info.max_packet_size);
601 w.set_available(0, true);
602 });
603 }
604 568
605 Ok(rx_len) 569 unsafe {
570 let pid = !val.pid(0);
571 T::dpram().ep_out_buffer_control(index).write(|w| {
572 w.set_pid(0, pid);
573 w.set_length(0, self.info.max_packet_size);
574 });
575 cortex_m::asm::delay(12);
576 T::dpram().ep_out_buffer_control(index).write(|w| {
577 w.set_pid(0, pid);
578 w.set_length(0, self.info.max_packet_size);
579 w.set_available(0, true);
580 });
606 } 581 }
582
583 Ok(rx_len)
607 } 584 }
608} 585}
609 586
610impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { 587impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
611 type WriteFuture<'a> = impl Future<Output = Result<(), EndpointError>> + 'a where Self: 'a; 588 async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError> {
612 589 if buf.len() > self.info.max_packet_size as usize {
613 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { 590 return Err(EndpointError::BufferOverflow);
614 async move { 591 }
615 if buf.len() > self.info.max_packet_size as usize {
616 return Err(EndpointError::BufferOverflow);
617 }
618
619 trace!("WRITE WAITING");
620
621 let index = self.info.addr.index();
622 let val = poll_fn(|cx| unsafe {
623 EP_IN_WAKERS[index].register(cx.waker());
624 let val = T::dpram().ep_in_buffer_control(index).read();
625 if val.available(0) {
626 Poll::Pending
627 } else {
628 Poll::Ready(val)
629 }
630 })
631 .await;
632 592
633 self.buf.write(buf); 593 trace!("WRITE WAITING");
634 594
635 unsafe { 595 let index = self.info.addr.index();
636 let pid = !val.pid(0); 596 let val = poll_fn(|cx| unsafe {
637 T::dpram().ep_in_buffer_control(index).write(|w| { 597 EP_IN_WAKERS[index].register(cx.waker());
638 w.set_pid(0, pid); 598 let val = T::dpram().ep_in_buffer_control(index).read();
639 w.set_length(0, buf.len() as _); 599 if val.available(0) {
640 w.set_full(0, true); 600 Poll::Pending
641 }); 601 } else {
642 cortex_m::asm::delay(12); 602 Poll::Ready(val)
643 T::dpram().ep_in_buffer_control(index).write(|w| {
644 w.set_pid(0, pid);
645 w.set_length(0, buf.len() as _);
646 w.set_full(0, true);
647 w.set_available(0, true);
648 });
649 } 603 }
604 })
605 .await;
650 606
651 trace!("WRITE OK"); 607 self.buf.write(buf);
652 608
653 Ok(()) 609 unsafe {
610 let pid = !val.pid(0);
611 T::dpram().ep_in_buffer_control(index).write(|w| {
612 w.set_pid(0, pid);
613 w.set_length(0, buf.len() as _);
614 w.set_full(0, true);
615 });
616 cortex_m::asm::delay(12);
617 T::dpram().ep_in_buffer_control(index).write(|w| {
618 w.set_pid(0, pid);
619 w.set_length(0, buf.len() as _);
620 w.set_full(0, true);
621 w.set_available(0, true);
622 });
654 } 623 }
624
625 trace!("WRITE OK");
626
627 Ok(())
655 } 628 }
656} 629}
657 630
@@ -661,199 +634,183 @@ pub struct ControlPipe<'d, T: Instance> {
661} 634}
662 635
663impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { 636impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
664 type SetupFuture<'a> = impl Future<Output = [u8;8]> + 'a where Self: 'a;
665 type DataOutFuture<'a> = impl Future<Output = Result<usize, EndpointError>> + 'a where Self: 'a;
666 type DataInFuture<'a> = impl Future<Output = Result<(), EndpointError>> + 'a where Self: 'a;
667 type AcceptFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
668 type RejectFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
669
670 fn max_packet_size(&self) -> usize { 637 fn max_packet_size(&self) -> usize {
671 64 638 64
672 } 639 }
673 640
674 fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a> { 641 async fn setup(&mut self) -> [u8; 8] {
675 async move { 642 loop {
676 loop { 643 trace!("SETUP read waiting");
677 trace!("SETUP read waiting"); 644 let regs = T::regs();
678 let regs = T::regs(); 645 unsafe { regs.inte().write_set(|w| w.set_setup_req(true)) };
679 unsafe { regs.inte().write_set(|w| w.set_setup_req(true)) };
680
681 poll_fn(|cx| unsafe {
682 EP_OUT_WAKERS[0].register(cx.waker());
683 let regs = T::regs();
684 if regs.sie_status().read().setup_rec() {
685 Poll::Ready(())
686 } else {
687 Poll::Pending
688 }
689 })
690 .await;
691
692 let mut buf = [0; 8];
693 EndpointBuffer::<T>::new(0, 8).read(&mut buf);
694
695 let regs = T::regs();
696 unsafe {
697 regs.sie_status().write(|w| w.set_setup_rec(true));
698
699 // set PID to 0, so (after toggling) first DATA is PID 1
700 T::dpram().ep_in_buffer_control(0).write(|w| w.set_pid(0, false));
701 T::dpram().ep_out_buffer_control(0).write(|w| w.set_pid(0, false));
702 }
703
704 trace!("SETUP read ok");
705 return buf;
706 }
707 }
708 }
709
710 fn data_out<'a>(&'a mut self, buf: &'a mut [u8], _first: bool, _last: bool) -> Self::DataOutFuture<'a> {
711 async move {
712 unsafe {
713 let bufcontrol = T::dpram().ep_out_buffer_control(0);
714 let pid = !bufcontrol.read().pid(0);
715 bufcontrol.write(|w| {
716 w.set_length(0, self.max_packet_size);
717 w.set_pid(0, pid);
718 });
719 cortex_m::asm::delay(12);
720 bufcontrol.write(|w| {
721 w.set_length(0, self.max_packet_size);
722 w.set_pid(0, pid);
723 w.set_available(0, true);
724 });
725 }
726 646
727 trace!("control: data_out len={} first={} last={}", buf.len(), _first, _last); 647 poll_fn(|cx| unsafe {
728 let val = poll_fn(|cx| unsafe {
729 EP_OUT_WAKERS[0].register(cx.waker()); 648 EP_OUT_WAKERS[0].register(cx.waker());
730 let val = T::dpram().ep_out_buffer_control(0).read(); 649 let regs = T::regs();
731 if val.available(0) { 650 if regs.sie_status().read().setup_rec() {
732 Poll::Pending 651 Poll::Ready(())
733 } else { 652 } else {
734 Poll::Ready(val) 653 Poll::Pending
735 } 654 }
736 }) 655 })
737 .await; 656 .await;
738 657
739 let rx_len = val.length(0) as _; 658 let mut buf = [0; 8];
740 trace!("control data_out DONE, rx_len = {}", rx_len); 659 EndpointBuffer::<T>::new(0, 8).read(&mut buf);
741 660
742 if rx_len > buf.len() { 661 let regs = T::regs();
743 return Err(EndpointError::BufferOverflow); 662 unsafe {
663 regs.sie_status().write(|w| w.set_setup_rec(true));
664
665 // set PID to 0, so (after toggling) first DATA is PID 1
666 T::dpram().ep_in_buffer_control(0).write(|w| w.set_pid(0, false));
667 T::dpram().ep_out_buffer_control(0).write(|w| w.set_pid(0, false));
744 } 668 }
745 EndpointBuffer::<T>::new(0x100, 64).read(&mut buf[..rx_len]);
746 669
747 Ok(rx_len) 670 trace!("SETUP read ok");
671 return buf;
748 } 672 }
749 } 673 }
750 674
751 fn data_in<'a>(&'a mut self, buf: &'a [u8], _first: bool, _last: bool) -> Self::DataInFuture<'a> { 675 async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError> {
752 async move { 676 unsafe {
753 trace!("control: data_in len={} first={} last={}", buf.len(), _first, _last); 677 let bufcontrol = T::dpram().ep_out_buffer_control(0);
754 678 let pid = !bufcontrol.read().pid(0);
755 if buf.len() > 64 { 679 bufcontrol.write(|w| {
756 return Err(EndpointError::BufferOverflow); 680 w.set_length(0, self.max_packet_size);
757 } 681 w.set_pid(0, pid);
758 EndpointBuffer::<T>::new(0x100, 64).write(buf); 682 });
683 cortex_m::asm::delay(12);
684 bufcontrol.write(|w| {
685 w.set_length(0, self.max_packet_size);
686 w.set_pid(0, pid);
687 w.set_available(0, true);
688 });
689 }
759 690
760 unsafe { 691 trace!("control: data_out len={} first={} last={}", buf.len(), first, last);
761 let bufcontrol = T::dpram().ep_in_buffer_control(0); 692 let val = poll_fn(|cx| unsafe {
762 let pid = !bufcontrol.read().pid(0); 693 EP_OUT_WAKERS[0].register(cx.waker());
763 bufcontrol.write(|w| { 694 let val = T::dpram().ep_out_buffer_control(0).read();
764 w.set_length(0, buf.len() as _); 695 if val.available(0) {
765 w.set_pid(0, pid); 696 Poll::Pending
766 w.set_full(0, true); 697 } else {
767 }); 698 Poll::Ready(val)
768 cortex_m::asm::delay(12);
769 bufcontrol.write(|w| {
770 w.set_length(0, buf.len() as _);
771 w.set_pid(0, pid);
772 w.set_full(0, true);
773 w.set_available(0, true);
774 });
775 } 699 }
700 })
701 .await;
776 702
777 poll_fn(|cx| unsafe { 703 let rx_len = val.length(0) as _;
778 EP_IN_WAKERS[0].register(cx.waker()); 704 trace!("control data_out DONE, rx_len = {}", rx_len);
779 let bufcontrol = T::dpram().ep_in_buffer_control(0);
780 if bufcontrol.read().available(0) {
781 Poll::Pending
782 } else {
783 Poll::Ready(())
784 }
785 })
786 .await;
787 trace!("control: data_in DONE");
788
789 if _last {
790 // prepare status phase right away.
791 unsafe {
792 let bufcontrol = T::dpram().ep_out_buffer_control(0);
793 bufcontrol.write(|w| {
794 w.set_length(0, 0);
795 w.set_pid(0, true);
796 });
797 cortex_m::asm::delay(12);
798 bufcontrol.write(|w| {
799 w.set_length(0, 0);
800 w.set_pid(0, true);
801 w.set_available(0, true);
802 });
803 }
804 }
805 705
806 Ok(()) 706 if rx_len > buf.len() {
707 return Err(EndpointError::BufferOverflow);
807 } 708 }
709 EndpointBuffer::<T>::new(0x100, 64).read(&mut buf[..rx_len]);
710
711 Ok(rx_len)
808 } 712 }
809 713
810 fn accept<'a>(&'a mut self) -> Self::AcceptFuture<'a> { 714 async fn data_in(&mut self, data: &[u8], first: bool, last: bool) -> Result<(), EndpointError> {
811 async move { 715 trace!("control: data_in len={} first={} last={}", data.len(), first, last);
812 trace!("control: accept"); 716
717 if data.len() > 64 {
718 return Err(EndpointError::BufferOverflow);
719 }
720 EndpointBuffer::<T>::new(0x100, 64).write(data);
721
722 unsafe {
723 let bufcontrol = T::dpram().ep_in_buffer_control(0);
724 let pid = !bufcontrol.read().pid(0);
725 bufcontrol.write(|w| {
726 w.set_length(0, data.len() as _);
727 w.set_pid(0, pid);
728 w.set_full(0, true);
729 });
730 cortex_m::asm::delay(12);
731 bufcontrol.write(|w| {
732 w.set_length(0, data.len() as _);
733 w.set_pid(0, pid);
734 w.set_full(0, true);
735 w.set_available(0, true);
736 });
737 }
813 738
739 poll_fn(|cx| unsafe {
740 EP_IN_WAKERS[0].register(cx.waker());
814 let bufcontrol = T::dpram().ep_in_buffer_control(0); 741 let bufcontrol = T::dpram().ep_in_buffer_control(0);
742 if bufcontrol.read().available(0) {
743 Poll::Pending
744 } else {
745 Poll::Ready(())
746 }
747 })
748 .await;
749 trace!("control: data_in DONE");
750
751 if last {
752 // prepare status phase right away.
815 unsafe { 753 unsafe {
754 let bufcontrol = T::dpram().ep_out_buffer_control(0);
816 bufcontrol.write(|w| { 755 bufcontrol.write(|w| {
817 w.set_length(0, 0); 756 w.set_length(0, 0);
818 w.set_pid(0, true); 757 w.set_pid(0, true);
819 w.set_full(0, true);
820 }); 758 });
821 cortex_m::asm::delay(12); 759 cortex_m::asm::delay(12);
822 bufcontrol.write(|w| { 760 bufcontrol.write(|w| {
823 w.set_length(0, 0); 761 w.set_length(0, 0);
824 w.set_pid(0, true); 762 w.set_pid(0, true);
825 w.set_full(0, true);
826 w.set_available(0, true); 763 w.set_available(0, true);
827 }); 764 });
828 } 765 }
829
830 // wait for completion before returning, needed so
831 // set_address() doesn't happen early.
832 poll_fn(|cx| {
833 EP_IN_WAKERS[0].register(cx.waker());
834 if unsafe { bufcontrol.read().available(0) } {
835 Poll::Pending
836 } else {
837 Poll::Ready(())
838 }
839 })
840 .await;
841 } 766 }
767
768 Ok(())
842 } 769 }
843 770
844 fn reject<'a>(&'a mut self) -> Self::RejectFuture<'a> { 771 async fn accept(&mut self) {
845 async move { 772 trace!("control: accept");
846 trace!("control: reject");
847 773
848 let regs = T::regs(); 774 let bufcontrol = T::dpram().ep_in_buffer_control(0);
849 unsafe { 775 unsafe {
850 regs.ep_stall_arm().write_set(|w| { 776 bufcontrol.write(|w| {
851 w.set_ep0_in(true); 777 w.set_length(0, 0);
852 w.set_ep0_out(true); 778 w.set_pid(0, true);
853 }); 779 w.set_full(0, true);
854 T::dpram().ep_out_buffer_control(0).write(|w| w.set_stall(true)); 780 });
855 T::dpram().ep_in_buffer_control(0).write(|w| w.set_stall(true)); 781 cortex_m::asm::delay(12);
782 bufcontrol.write(|w| {
783 w.set_length(0, 0);
784 w.set_pid(0, true);
785 w.set_full(0, true);
786 w.set_available(0, true);
787 });
788 }
789
790 // wait for completion before returning, needed so
791 // set_address() doesn't happen early.
792 poll_fn(|cx| {
793 EP_IN_WAKERS[0].register(cx.waker());
794 if unsafe { bufcontrol.read().available(0) } {
795 Poll::Pending
796 } else {
797 Poll::Ready(())
856 } 798 }
799 })
800 .await;
801 }
802
803 async fn reject(&mut self) {
804 trace!("control: reject");
805
806 let regs = T::regs();
807 unsafe {
808 regs.ep_stall_arm().write_set(|w| {
809 w.set_ep0_in(true);
810 w.set_ep0_out(true);
811 });
812 T::dpram().ep_out_buffer_control(0).write(|w| w.set_stall(true));
813 T::dpram().ep_in_buffer_control(0).write(|w| w.set_stall(true));
857 } 814 }
858 } 815 }
859} 816}
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 6b00518a6..b7f718c5f 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -44,7 +44,7 @@ embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optiona
44 44
45embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 45embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
46embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} 46embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true}
47embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true} 47embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true}
48embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} 48embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true}
49 49
50embedded-storage = "0.3.0" 50embedded-storage = "0.3.0"
@@ -67,7 +67,7 @@ nb = "1.0.0"
67stm32-fmc = "0.2.4" 67stm32-fmc = "0.2.4"
68seq-macro = "0.3.0" 68seq-macro = "0.3.0"
69cfg-if = "1.0.0" 69cfg-if = "1.0.0"
70embedded-io = { version = "0.3.1", features = ["async"], optional = true } 70embedded-io = { version = "0.4.0", features = ["async"], optional = true }
71 71
72[build-dependencies] 72[build-dependencies]
73proc-macro2 = "1.0.36" 73proc-macro2 = "1.0.36"
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 8f81cb7a3..90aa7d3b9 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -71,7 +71,7 @@ impl<'d, T: Instance> Adc<'d, T> {
71 71
72 #[cfg(adc_g0)] 72 #[cfg(adc_g0)]
73 T::regs().cfgr1().modify(|reg| { 73 T::regs().cfgr1().modify(|reg| {
74 reg.set_chselrmod(true); 74 reg.set_chselrmod(false);
75 }); 75 });
76 } 76 }
77 77
@@ -200,7 +200,7 @@ impl<'d, T: Instance> Adc<'d, T> {
200 #[cfg(not(stm32g0))] 200 #[cfg(not(stm32g0))]
201 T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); 201 T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
202 #[cfg(stm32g0)] 202 #[cfg(stm32g0)]
203 T::regs().chselr().write(|reg| reg.set_chsel(pin.channel() as u32)); 203 T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel()));
204 204
205 // Some models are affected by an erratum: 205 // Some models are affected by an erratum:
206 // If we perform conversions slower than 1 kHz, the first read ADC value can be 206 // If we perform conversions slower than 1 kHz, the first read ADC value can be
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index 674255ddc..e6ce05b7b 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -3,6 +3,7 @@
3use core::sync::atomic::{fence, Ordering}; 3use core::sync::atomic::{fence, Ordering};
4use core::task::Waker; 4use core::task::Waker;
5 5
6use embassy_cortex_m::interrupt::Priority;
6use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
7 8
8use super::{TransferOptions, Word, WordSize}; 9use super::{TransferOptions, Word, WordSize};
@@ -38,10 +39,12 @@ impl State {
38static STATE: State = State::new(); 39static STATE: State = State::new();
39 40
40/// safety: must be called only once 41/// safety: must be called only once
41pub(crate) unsafe fn init() { 42pub(crate) unsafe fn init(irq_priority: Priority) {
42 foreach_interrupt! { 43 foreach_interrupt! {
43 ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => { 44 ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => {
44 crate::interrupt::$irq::steal().enable(); 45 let irq = crate::interrupt::$irq::steal();
46 irq.set_priority(irq_priority);
47 irq.enable();
45 }; 48 };
46 } 49 }
47 crate::_generated::init_bdma(); 50 crate::_generated::init_bdma();
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index a45b8780b..97a3df088 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -1,6 +1,7 @@
1use core::sync::atomic::{fence, Ordering}; 1use core::sync::atomic::{fence, Ordering};
2use core::task::Waker; 2use core::task::Waker;
3 3
4use embassy_cortex_m::interrupt::Priority;
4use embassy_sync::waitqueue::AtomicWaker; 5use embassy_sync::waitqueue::AtomicWaker;
5 6
6use super::{Burst, FlowControl, Request, TransferOptions, Word, WordSize}; 7use super::{Burst, FlowControl, Request, TransferOptions, Word, WordSize};
@@ -67,10 +68,12 @@ impl State {
67static STATE: State = State::new(); 68static STATE: State = State::new();
68 69
69/// safety: must be called only once 70/// safety: must be called only once
70pub(crate) unsafe fn init() { 71pub(crate) unsafe fn init(irq_priority: Priority) {
71 foreach_interrupt! { 72 foreach_interrupt! {
72 ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { 73 ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
73 interrupt::$irq::steal().enable(); 74 let irq = interrupt::$irq::steal();
75 irq.set_priority(irq_priority);
76 irq.enable();
74 }; 77 };
75 } 78 }
76 crate::_generated::init_dma(); 79 crate::_generated::init_dma();
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index cc030a93e..74bce6aa9 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -12,6 +12,8 @@ use core::mem;
12use core::pin::Pin; 12use core::pin::Pin;
13use core::task::{Context, Poll, Waker}; 13use core::task::{Context, Poll, Waker};
14 14
15#[cfg(any(dma, bdma))]
16use embassy_cortex_m::interrupt::Priority;
15use embassy_hal_common::{impl_peripheral, into_ref}; 17use embassy_hal_common::{impl_peripheral, into_ref};
16 18
17#[cfg(dmamux)] 19#[cfg(dmamux)]
@@ -294,11 +296,11 @@ pub struct NoDma;
294impl_peripheral!(NoDma); 296impl_peripheral!(NoDma);
295 297
296// safety: must be called only once at startup 298// safety: must be called only once at startup
297pub(crate) unsafe fn init() { 299pub(crate) unsafe fn init(#[cfg(bdma)] bdma_priority: Priority, #[cfg(dma)] dma_priority: Priority) {
298 #[cfg(bdma)] 300 #[cfg(bdma)]
299 bdma::init(); 301 bdma::init(bdma_priority);
300 #[cfg(dma)] 302 #[cfg(dma)]
301 dma::init(); 303 dma::init(dma_priority);
302 #[cfg(dmamux)] 304 #[cfg(dmamux)]
303 dmamux::init(); 305 dmamux::init();
304 #[cfg(gpdma)] 306 #[cfg(gpdma)]
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index a81ee1183..5b76d1e7f 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -116,6 +116,24 @@ impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, T,
116 116
117 mac.macqtx_fcr().modify(|w| w.set_pt(0x100)); 117 mac.macqtx_fcr().modify(|w| w.set_pt(0x100));
118 118
119 // disable all MMC RX interrupts
120 mac.mmc_rx_interrupt_mask().write(|w| {
121 w.set_rxcrcerpim(true);
122 w.set_rxalgnerpim(true);
123 w.set_rxucgpim(true);
124 w.set_rxlpiuscim(true);
125 w.set_rxlpitrcim(true)
126 });
127
128 // disable all MMC TX interrupts
129 mac.mmc_tx_interrupt_mask().write(|w| {
130 w.set_txscolgpim(true);
131 w.set_txmcolgpim(true);
132 w.set_txgpktim(true);
133 w.set_txlpiuscim(true);
134 w.set_txlpitrcim(true);
135 });
136
119 mtl.mtlrx_qomr().modify(|w| w.set_rsf(true)); 137 mtl.mtlrx_qomr().modify(|w| w.set_rsf(true));
120 mtl.mtltx_qomr().modify(|w| w.set_tsf(true)); 138 mtl.mtltx_qomr().modify(|w| w.set_tsf(true));
121 139
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index dca991859..f90785815 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -167,39 +167,33 @@ mod eh1 {
167} 167}
168#[cfg(all(feature = "unstable-traits", feature = "nightly"))] 168#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
169mod eha { 169mod eha {
170 use futures::FutureExt;
171 170
172 use super::*; 171 use super::*;
173 172
174 impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for ExtiInput<'d, T> { 173 impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for ExtiInput<'d, T> {
175 type WaitForHighFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 174 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
176 175 self.wait_for_high().await;
177 fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> { 176 Ok(())
178 self.wait_for_high().map(Ok)
179 } 177 }
180 178
181 type WaitForLowFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 179 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
182 180 self.wait_for_low().await;
183 fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> { 181 Ok(())
184 self.wait_for_low().map(Ok)
185 } 182 }
186 183
187 type WaitForRisingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 184 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
188 185 self.wait_for_rising_edge().await;
189 fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> { 186 Ok(())
190 self.wait_for_rising_edge().map(Ok)
191 } 187 }
192 188
193 type WaitForFallingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 189 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
194 190 self.wait_for_falling_edge().await;
195 fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> { 191 Ok(())
196 self.wait_for_falling_edge().map(Ok)
197 } 192 }
198 193
199 type WaitForAnyEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 194 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
200 195 self.wait_for_any_edge().await;
201 fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> { 196 Ok(())
202 self.wait_for_any_edge().map(Ok)
203 } 197 }
204 } 198 }
205} 199}
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index 3f2129de8..3178b3be9 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -79,24 +79,19 @@ pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> {
79 let from = from - super::FLASH_BASE as u32; 79 let from = from - super::FLASH_BASE as u32;
80 let to = to - super::FLASH_BASE as u32; 80 let to = to - super::FLASH_BASE as u32;
81 81
82 let bank_size = (super::FLASH_SIZE / 2) as u32; 82 let (start, end) = if to <= super::FLASH_SIZE as u32 {
83
84 let (bank, start, end) = if to <= bank_size {
85 let start_sector = from / super::ERASE_SIZE as u32; 83 let start_sector = from / super::ERASE_SIZE as u32;
86 let end_sector = to / super::ERASE_SIZE as u32; 84 let end_sector = to / super::ERASE_SIZE as u32;
87 (0, start_sector, end_sector) 85 (start_sector, end_sector)
88 } else if from >= SECOND_BANK_OFFSET as u32 && to <= (SECOND_BANK_OFFSET as u32 + bank_size) {
89 let start_sector = (from - SECOND_BANK_OFFSET as u32) / super::ERASE_SIZE as u32;
90 let end_sector = (to - SECOND_BANK_OFFSET as u32) / super::ERASE_SIZE as u32;
91 (1, start_sector, end_sector)
92 } else { 86 } else {
93 error!("Attempting to write outside of defined sectors"); 87 error!("Attempting to write outside of defined sectors {:x} {:x}", from, to);
94 return Err(Error::Unaligned); 88 return Err(Error::Unaligned);
95 }; 89 };
96 90
97 trace!("Erasing bank {}, sectors from {} to {}", bank, start, end); 91 trace!("Erasing sectors from {} to {}", start, end);
98 for sector in start..end { 92 for sector in start..end {
99 let ret = erase_sector(pac::FLASH.bank(bank), sector as u8); 93 let bank = if sector >= 8 { 1 } else { 0 };
94 let ret = erase_sector(pac::FLASH.bank(bank), (sector % 8) as u8);
100 if ret.is_err() { 95 if ret.is_err() {
101 return ret; 96 return ret;
102 } 97 }
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index aa4e6bb08..47dc7d2a4 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -1048,43 +1048,35 @@ mod eh1 {
1048 1048
1049#[cfg(all(feature = "unstable-traits", feature = "nightly"))] 1049#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
1050mod eha { 1050mod eha {
1051 use core::future::Future;
1052
1053 use super::super::{RxDma, TxDma}; 1051 use super::super::{RxDma, TxDma};
1054 use super::*; 1052 use super::*;
1055 1053
1056 impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c::I2c for I2c<'d, T, TXDMA, RXDMA> { 1054 impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c::I2c for I2c<'d, T, TXDMA, RXDMA> {
1057 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 1055 async fn read<'a>(&'a mut self, address: u8, read: &'a mut [u8]) -> Result<(), Self::Error> {
1058 1056 self.read(address, read).await
1059 fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
1060 self.read(address, buffer)
1061 } 1057 }
1062 1058
1063 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 1059 async fn write<'a>(&'a mut self, address: u8, write: &'a [u8]) -> Result<(), Self::Error> {
1064 fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { 1060 self.write(address, write).await
1065 self.write(address, bytes)
1066 } 1061 }
1067 1062
1068 type WriteReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 1063 async fn write_read<'a>(
1069 fn write_read<'a>(
1070 &'a mut self, 1064 &'a mut self,
1071 address: u8, 1065 address: u8,
1072 bytes: &'a [u8], 1066 write: &'a [u8],
1073 buffer: &'a mut [u8], 1067 read: &'a mut [u8],
1074 ) -> Self::WriteReadFuture<'a> { 1068 ) -> Result<(), Self::Error> {
1075 self.write_read(address, bytes, buffer) 1069 self.write_read(address, write, read).await
1076 } 1070 }
1077 1071
1078 type TransactionFuture<'a, 'b> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a, 'b: 'a; 1072 async fn transaction<'a, 'b>(
1079
1080 fn transaction<'a, 'b>(
1081 &'a mut self, 1073 &'a mut self,
1082 address: u8, 1074 address: u8,
1083 operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], 1075 operations: &'a mut [embedded_hal_1::i2c::Operation<'b>],
1084 ) -> Self::TransactionFuture<'a, 'b> { 1076 ) -> Result<(), Self::Error> {
1085 let _ = address; 1077 let _ = address;
1086 let _ = operations; 1078 let _ = operations;
1087 async move { todo!() } 1079 todo!()
1088 } 1080 }
1089 } 1081 }
1090} 1082}
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index bcf2feee8..16c46ca22 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -1,5 +1,9 @@
1#![no_std] 1#![no_std]
2#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))] 2#![cfg_attr(
3 feature = "nightly",
4 feature(type_alias_impl_trait, async_fn_in_trait, impl_trait_projections)
5)]
6#![cfg_attr(feature = "nightly", allow(incomplete_features))]
3 7
4// This must go FIRST so that all the other modules see its macros. 8// This must go FIRST so that all the other modules see its macros.
5pub mod fmt; 9pub mod fmt;
@@ -75,6 +79,8 @@ pub(crate) mod _generated {
75// Reexports 79// Reexports
76pub use _generated::{peripherals, Peripherals}; 80pub use _generated::{peripherals, Peripherals};
77pub use embassy_cortex_m::executor; 81pub use embassy_cortex_m::executor;
82#[cfg(any(dma, bdma))]
83use embassy_cortex_m::interrupt::Priority;
78pub use embassy_cortex_m::interrupt::_export::interrupt; 84pub use embassy_cortex_m::interrupt::_export::interrupt;
79pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 85pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
80#[cfg(feature = "unstable-pac")] 86#[cfg(feature = "unstable-pac")]
@@ -87,6 +93,10 @@ pub struct Config {
87 pub rcc: rcc::Config, 93 pub rcc: rcc::Config,
88 #[cfg(dbgmcu)] 94 #[cfg(dbgmcu)]
89 pub enable_debug_during_sleep: bool, 95 pub enable_debug_during_sleep: bool,
96 #[cfg(bdma)]
97 pub bdma_interrupt_priority: Priority,
98 #[cfg(dma)]
99 pub dma_interrupt_priority: Priority,
90} 100}
91 101
92impl Default for Config { 102impl Default for Config {
@@ -95,6 +105,10 @@ impl Default for Config {
95 rcc: Default::default(), 105 rcc: Default::default(),
96 #[cfg(dbgmcu)] 106 #[cfg(dbgmcu)]
97 enable_debug_during_sleep: true, 107 enable_debug_during_sleep: true,
108 #[cfg(bdma)]
109 bdma_interrupt_priority: Priority::P0,
110 #[cfg(dma)]
111 dma_interrupt_priority: Priority::P0,
98 } 112 }
99 } 113 }
100} 114}
@@ -133,7 +147,12 @@ pub fn init(config: Config) -> Peripherals {
133 } 147 }
134 148
135 gpio::init(); 149 gpio::init();
136 dma::init(); 150 dma::init(
151 #[cfg(bdma)]
152 config.bdma_interrupt_priority,
153 #[cfg(dma)]
154 config.dma_interrupt_priority,
155 );
137 #[cfg(feature = "exti")] 156 #[cfg(feature = "exti")]
138 exti::init(); 157 exti::init();
139 158
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index c91f3c8bf..a52c65b92 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -18,6 +18,9 @@ use crate::rcc::RccPeripheral;
18use crate::time::Hertz; 18use crate::time::Hertz;
19use crate::{peripherals, Peripheral}; 19use crate::{peripherals, Peripheral};
20 20
21/// Frequency used for SD Card initialization. Must be no higher than 400 kHz.
22const SD_INIT_FREQ: Hertz = Hertz(400_000);
23
21/// The signalling scheme used on the SDMMC bus 24/// The signalling scheme used on the SDMMC bus
22#[non_exhaustive] 25#[non_exhaustive]
23#[derive(Debug, Copy, Clone, PartialEq, Eq)] 26#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -295,7 +298,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
295 T::reset(); 298 T::reset();
296 299
297 let inner = T::inner(); 300 let inner = T::inner();
298 let clock = unsafe { inner.new_inner(T::frequency()) }; 301 unsafe { inner.new_inner() };
299 302
300 irq.set_handler(Self::on_interrupt); 303 irq.set_handler(Self::on_interrupt);
301 irq.unpend(); 304 irq.unpend();
@@ -314,7 +317,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
314 d3, 317 d3,
315 318
316 config, 319 config,
317 clock, 320 clock: SD_INIT_FREQ,
318 signalling: Default::default(), 321 signalling: Default::default(),
319 card: None, 322 card: None,
320 } 323 }
@@ -415,7 +418,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
415 T::reset(); 418 T::reset();
416 419
417 let inner = T::inner(); 420 let inner = T::inner();
418 let clock = unsafe { inner.new_inner(T::frequency()) }; 421 unsafe { inner.new_inner() };
419 422
420 irq.set_handler(Self::on_interrupt); 423 irq.set_handler(Self::on_interrupt);
421 irq.unpend(); 424 irq.unpend();
@@ -434,7 +437,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
434 d3, 437 d3,
435 438
436 config, 439 config,
437 clock, 440 clock: SD_INIT_FREQ,
438 signalling: Default::default(), 441 signalling: Default::default(),
439 card: None, 442 card: None,
440 } 443 }
@@ -561,16 +564,10 @@ impl SdmmcInner {
561 /// # Safety 564 /// # Safety
562 /// 565 ///
563 /// Access to `regs` registers should be exclusive 566 /// Access to `regs` registers should be exclusive
564 unsafe fn new_inner(&self, kernel_clk: Hertz) -> Hertz { 567 unsafe fn new_inner(&self) {
565 let regs = self.0; 568 let regs = self.0;
566 569
567 // While the SD/SDIO card or eMMC is in identification mode,
568 // the SDMMC_CK frequency must be less than 400 kHz.
569 let (clkdiv, clock) = unwrap!(clk_div(kernel_clk, 400_000));
570
571 regs.clkcr().write(|w| { 570 regs.clkcr().write(|w| {
572 w.set_widbus(0);
573 w.set_clkdiv(clkdiv);
574 w.set_pwrsav(false); 571 w.set_pwrsav(false);
575 w.set_negedge(false); 572 w.set_negedge(false);
576 w.set_hwfc_en(true); 573 w.set_hwfc_en(true);
@@ -582,8 +579,6 @@ impl SdmmcInner {
582 // Power off, writen 00: Clock to the card is stopped; 579 // Power off, writen 00: Clock to the card is stopped;
583 // D[7:0], CMD, and CK are driven high. 580 // D[7:0], CMD, and CK are driven high.
584 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); 581 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
585
586 clock
587 } 582 }
588 583
589 /// Initializes card (if present) and sets the bus at the 584 /// Initializes card (if present) and sets the bus at the
@@ -605,6 +600,19 @@ impl SdmmcInner {
605 600
606 // NOTE(unsafe) We have exclusive access to the peripheral 601 // NOTE(unsafe) We have exclusive access to the peripheral
607 unsafe { 602 unsafe {
603 // While the SD/SDIO card or eMMC is in identification mode,
604 // the SDMMC_CK frequency must be no more than 400 kHz.
605 let (clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
606 *clock = init_clock;
607
608 // CPSMACT and DPSMACT must be 0 to set WIDBUS
609 self.wait_idle();
610
611 regs.clkcr().modify(|w| {
612 w.set_widbus(0);
613 w.set_clkdiv(clkdiv);
614 });
615
608 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); 616 regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
609 self.cmd(Cmd::idle(), false)?; 617 self.cmd(Cmd::idle(), false)?;
610 618
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 396427782..ab4352a5c 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -8,7 +8,7 @@ use embassy_hal_common::{into_ref, PeripheralRef};
8pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 8pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
9 9
10use self::sealed::WordSize; 10use self::sealed::WordSize;
11use crate::dma::{slice_ptr_parts, NoDma, Transfer}; 11use crate::dma::{slice_ptr_parts, Transfer};
12use crate::gpio::sealed::{AFType, Pin as _}; 12use crate::gpio::sealed::{AFType, Pin as _};
13use crate::gpio::AnyPin; 13use crate::gpio::AnyPin;
14use crate::pac::spi::{regs, vals, Spi as Regs}; 14use crate::pac::spi::{regs, vals, Spi as Regs};
@@ -812,7 +812,7 @@ mod eh02 {
812 // some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289 812 // some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
813 macro_rules! impl_blocking { 813 macro_rules! impl_blocking {
814 ($w:ident) => { 814 ($w:ident) => {
815 impl<'d, T: Instance> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, T, NoDma, NoDma> { 815 impl<'d, T: Instance, Tx, Rx> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, T, Tx, Rx> {
816 type Error = Error; 816 type Error = Error;
817 817
818 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> { 818 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
@@ -820,7 +820,7 @@ mod eh02 {
820 } 820 }
821 } 821 }
822 822
823 impl<'d, T: Instance> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, T, NoDma, NoDma> { 823 impl<'d, T: Instance, Tx, Rx> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, T, Tx, Rx> {
824 type Error = Error; 824 type Error = Error;
825 825
826 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> { 826 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
@@ -849,19 +849,19 @@ mod eh1 {
849 } 849 }
850 } 850 }
851 851
852 impl<'d, T: Instance, W: Word> embedded_hal_1::spi::SpiBusRead<W> for Spi<'d, T, NoDma, NoDma> { 852 impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBusRead<W> for Spi<'d, T, Tx, Rx> {
853 fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> { 853 fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
854 self.blocking_read(words) 854 self.blocking_read(words)
855 } 855 }
856 } 856 }
857 857
858 impl<'d, T: Instance, W: Word> embedded_hal_1::spi::SpiBusWrite<W> for Spi<'d, T, NoDma, NoDma> { 858 impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBusWrite<W> for Spi<'d, T, Tx, Rx> {
859 fn write(&mut self, words: &[W]) -> Result<(), Self::Error> { 859 fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
860 self.blocking_write(words) 860 self.blocking_write(words)
861 } 861 }
862 } 862 }
863 863
864 impl<'d, T: Instance, W: Word> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, NoDma, NoDma> { 864 impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> {
865 fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> { 865 fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> {
866 self.blocking_transfer(read, write) 866 self.blocking_transfer(read, write)
867 } 867 }
@@ -885,46 +885,34 @@ mod eh1 {
885 885
886#[cfg(all(feature = "unstable-traits", feature = "nightly"))] 886#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
887mod eha { 887mod eha {
888 use core::future::Future;
889
890 use super::*; 888 use super::*;
891 impl<'d, T: Instance, Tx, Rx> embedded_hal_async::spi::SpiBusFlush for Spi<'d, T, Tx, Rx> { 889 impl<'d, T: Instance, Tx, Rx> embedded_hal_async::spi::SpiBusFlush for Spi<'d, T, Tx, Rx> {
892 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 890 async fn flush(&mut self) -> Result<(), Self::Error> {
893 891 Ok(())
894 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
895 async { Ok(()) }
896 } 892 }
897 } 893 }
898 894
899 impl<'d, T: Instance, Tx: TxDma<T>, Rx, W: Word> embedded_hal_async::spi::SpiBusWrite<W> for Spi<'d, T, Tx, Rx> { 895 impl<'d, T: Instance, Tx: TxDma<T>, Rx, W: Word> embedded_hal_async::spi::SpiBusWrite<W> for Spi<'d, T, Tx, Rx> {
900 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 896 async fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
901 897 self.write(words).await
902 fn write<'a>(&'a mut self, data: &'a [W]) -> Self::WriteFuture<'a> {
903 self.write(data)
904 } 898 }
905 } 899 }
906 900
907 impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBusRead<W> 901 impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBusRead<W>
908 for Spi<'d, T, Tx, Rx> 902 for Spi<'d, T, Tx, Rx>
909 { 903 {
910 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 904 async fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
911 905 self.read(words).await
912 fn read<'a>(&'a mut self, data: &'a mut [W]) -> Self::ReadFuture<'a> {
913 self.read(data)
914 } 906 }
915 } 907 }
916 908
917 impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> { 909 impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> {
918 type TransferFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 910 async fn transfer<'a>(&'a mut self, read: &'a mut [W], write: &'a [W]) -> Result<(), Self::Error> {
919 911 self.transfer(read, write).await
920 fn transfer<'a>(&'a mut self, rx: &'a mut [W], tx: &'a [W]) -> Self::TransferFuture<'a> {
921 self.transfer(rx, tx)
922 } 912 }
923 913
924 type TransferInPlaceFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 914 async fn transfer_in_place<'a>(&'a mut self, words: &'a mut [W]) -> Result<(), Self::Error> {
925 915 self.transfer_in_place(words).await
926 fn transfer_in_place<'a>(&'a mut self, words: &'a mut [W]) -> Self::TransferInPlaceFuture<'a> {
927 self.transfer_in_place(words)
928 } 916 }
929 } 917 }
930} 918}
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 0a6d6e149..d024bedcf 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -1,5 +1,5 @@
1use core::cell::RefCell; 1use core::cell::RefCell;
2use core::future::{poll_fn, Future}; 2use core::future::poll_fn;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use atomic_polyfill::{compiler_fence, Ordering}; 5use atomic_polyfill::{compiler_fence, Ordering};
@@ -112,6 +112,9 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
112 112
113 unsafe { 113 unsafe {
114 r.cr1().modify(|w| { 114 r.cr1().modify(|w| {
115 #[cfg(lpuart_v2)]
116 w.set_fifoen(true);
117
115 w.set_rxneie(true); 118 w.set_rxneie(true);
116 w.set_idleie(true); 119 w.set_idleie(true);
117 }); 120 });
@@ -339,32 +342,20 @@ impl<'u, 'd, T: BasicInstance> embedded_io::Io for BufferedUartTx<'u, 'd, T> {
339} 342}
340 343
341impl<'d, T: BasicInstance> embedded_io::asynch::Read for BufferedUart<'d, T> { 344impl<'d, T: BasicInstance> embedded_io::asynch::Read for BufferedUart<'d, T> {
342 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 345 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
343 where 346 self.inner_read(buf).await
344 Self: 'a;
345
346 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
347 self.inner_read(buf)
348 } 347 }
349} 348}
350 349
351impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Read for BufferedUartRx<'u, 'd, T> { 350impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Read for BufferedUartRx<'u, 'd, T> {
352 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 351 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
353 where 352 self.inner.inner_read(buf).await
354 Self: 'a;
355
356 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
357 self.inner.inner_read(buf)
358 } 353 }
359} 354}
360 355
361impl<'d, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUart<'d, T> { 356impl<'d, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUart<'d, T> {
362 type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a 357 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
363 where 358 self.inner_fill_buf().await
364 Self: 'a;
365
366 fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> {
367 self.inner_fill_buf()
368 } 359 }
369 360
370 fn consume(&mut self, amt: usize) { 361 fn consume(&mut self, amt: usize) {
@@ -373,12 +364,8 @@ impl<'d, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUart<'d, T>
373} 364}
374 365
375impl<'u, 'd, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUartRx<'u, 'd, T> { 366impl<'u, 'd, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUartRx<'u, 'd, T> {
376 type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> + 'a 367 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
377 where 368 self.inner.inner_fill_buf().await
378 Self: 'a;
379
380 fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> {
381 self.inner.inner_fill_buf()
382 } 369 }
383 370
384 fn consume(&mut self, amt: usize) { 371 fn consume(&mut self, amt: usize) {
@@ -387,37 +374,21 @@ impl<'u, 'd, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUartRx<'
387} 374}
388 375
389impl<'d, T: BasicInstance> embedded_io::asynch::Write for BufferedUart<'d, T> { 376impl<'d, T: BasicInstance> embedded_io::asynch::Write for BufferedUart<'d, T> {
390 type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 377 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
391 where 378 self.inner_write(buf).await
392 Self: 'a;
393
394 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
395 self.inner_write(buf)
396 } 379 }
397 380
398 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a 381 async fn flush(&mut self) -> Result<(), Self::Error> {
399 where 382 self.inner_flush().await
400 Self: 'a;
401
402 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
403 self.inner_flush()
404 } 383 }
405} 384}
406 385
407impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Write for BufferedUartTx<'u, 'd, T> { 386impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Write for BufferedUartTx<'u, 'd, T> {
408 type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 387 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
409 where 388 self.inner.inner_write(buf).await
410 Self: 'a;
411
412 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
413 self.inner.inner_write(buf)
414 } 389 }
415 390
416 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a 391 async fn flush(&mut self) -> Result<(), Self::Error> {
417 where 392 self.inner.inner_flush().await
418 Self: 'a;
419
420 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
421 self.inner.inner_flush()
422 } 393 }
423} 394}
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 2654f156a..460abfe28 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -1,6 +1,6 @@
1#![macro_use] 1#![macro_use]
2 2
3use core::future::{poll_fn, Future}; 3use core::future::poll_fn;
4use core::marker::PhantomData; 4use core::marker::PhantomData;
5use core::sync::atomic::Ordering; 5use core::sync::atomic::Ordering;
6use core::task::Poll; 6use core::task::Poll;
@@ -429,9 +429,7 @@ pub struct Bus<'d, T: Instance> {
429} 429}
430 430
431impl<'d, T: Instance> driver::Bus for Bus<'d, T> { 431impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
432 type PollFuture<'a> = impl Future<Output = Event> + 'a where Self: 'a; 432 async fn poll(&mut self) -> Event {
433
434 fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> {
435 poll_fn(move |cx| unsafe { 433 poll_fn(move |cx| unsafe {
436 BUS_WAKER.register(cx.waker()); 434 BUS_WAKER.register(cx.waker());
437 435
@@ -488,6 +486,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
488 return Poll::Ready(Event::PowerDetected); 486 return Poll::Ready(Event::PowerDetected);
489 } 487 }
490 }) 488 })
489 .await
491 } 490 }
492 491
493 #[inline] 492 #[inline]
@@ -598,22 +597,11 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
598 trace!("EPR after: {:04x}", unsafe { reg.read() }.0); 597 trace!("EPR after: {:04x}", unsafe { reg.read() }.0);
599 } 598 }
600 599
601 type EnableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; 600 async fn enable(&mut self) {}
602 601 async fn disable(&mut self) {}
603 fn enable(&mut self) -> Self::EnableFuture<'_> {
604 async move {}
605 }
606
607 type DisableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
608
609 fn disable(&mut self) -> Self::DisableFuture<'_> {
610 async move {}
611 }
612
613 type RemoteWakeupFuture<'a> = impl Future<Output = Result<(), Unsupported>> + 'a where Self: 'a;
614 602
615 fn remote_wakeup(&mut self) -> Self::RemoteWakeupFuture<'_> { 603 async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
616 async move { Err(Unsupported) } 604 Err(Unsupported)
617 } 605 }
618} 606}
619 607
@@ -676,24 +664,20 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
676 &self.info 664 &self.info
677 } 665 }
678 666
679 type WaitEnabledFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; 667 async fn wait_enabled(&mut self) {
680 668 trace!("wait_enabled OUT WAITING");
681 fn wait_enabled(&mut self) -> Self::WaitEnabledFuture<'_> { 669 let index = self.info.addr.index();
682 async move { 670 poll_fn(|cx| {
683 trace!("wait_enabled OUT WAITING"); 671 EP_OUT_WAKERS[index].register(cx.waker());
684 let index = self.info.addr.index(); 672 let regs = T::regs();
685 poll_fn(|cx| { 673 if unsafe { regs.epr(index).read() }.stat_tx() == Stat::DISABLED {
686 EP_OUT_WAKERS[index].register(cx.waker()); 674 Poll::Pending
687 let regs = T::regs(); 675 } else {
688 if unsafe { regs.epr(index).read() }.stat_tx() == Stat::DISABLED { 676 Poll::Ready(())
689 Poll::Pending 677 }
690 } else { 678 })
691 Poll::Ready(()) 679 .await;
692 } 680 trace!("wait_enabled OUT OK");
693 })
694 .await;
695 trace!("wait_enabled OUT OK");
696 }
697 } 681 }
698} 682}
699 683
@@ -702,116 +686,104 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> {
702 &self.info 686 &self.info
703 } 687 }
704 688
705 type WaitEnabledFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; 689 async fn wait_enabled(&mut self) {
706 690 trace!("wait_enabled OUT WAITING");
707 fn wait_enabled(&mut self) -> Self::WaitEnabledFuture<'_> { 691 let index = self.info.addr.index();
708 async move { 692 poll_fn(|cx| {
709 trace!("wait_enabled OUT WAITING"); 693 EP_OUT_WAKERS[index].register(cx.waker());
710 let index = self.info.addr.index(); 694 let regs = T::regs();
711 poll_fn(|cx| { 695 if unsafe { regs.epr(index).read() }.stat_rx() == Stat::DISABLED {
712 EP_OUT_WAKERS[index].register(cx.waker()); 696 Poll::Pending
713 let regs = T::regs(); 697 } else {
714 if unsafe { regs.epr(index).read() }.stat_rx() == Stat::DISABLED { 698 Poll::Ready(())
715 Poll::Pending 699 }
716 } else { 700 })
717 Poll::Ready(()) 701 .await;
718 } 702 trace!("wait_enabled OUT OK");
719 })
720 .await;
721 trace!("wait_enabled OUT OK");
722 }
723 } 703 }
724} 704}
725 705
726impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { 706impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
727 type ReadFuture<'a> = impl Future<Output = Result<usize, EndpointError>> + 'a where Self: 'a; 707 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
728 708 trace!("READ WAITING, buf.len() = {}", buf.len());
729 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { 709 let index = self.info.addr.index();
730 async move { 710 let stat = poll_fn(|cx| {
731 trace!("READ WAITING, buf.len() = {}", buf.len()); 711 EP_OUT_WAKERS[index].register(cx.waker());
732 let index = self.info.addr.index(); 712 let regs = T::regs();
733 let stat = poll_fn(|cx| { 713 let stat = unsafe { regs.epr(index).read() }.stat_rx();
734 EP_OUT_WAKERS[index].register(cx.waker()); 714 if matches!(stat, Stat::NAK | Stat::DISABLED) {
735 let regs = T::regs(); 715 Poll::Ready(stat)
736 let stat = unsafe { regs.epr(index).read() }.stat_rx(); 716 } else {
737 if matches!(stat, Stat::NAK | Stat::DISABLED) { 717 Poll::Pending
738 Poll::Ready(stat)
739 } else {
740 Poll::Pending
741 }
742 })
743 .await;
744
745 if stat == Stat::DISABLED {
746 return Err(EndpointError::Disabled);
747 } 718 }
719 })
720 .await;
748 721
749 let rx_len = self.read_data(buf)?; 722 if stat == Stat::DISABLED {
723 return Err(EndpointError::Disabled);
724 }
750 725
751 let regs = T::regs(); 726 let rx_len = self.read_data(buf)?;
752 unsafe {
753 regs.epr(index).write(|w| {
754 w.set_ep_type(convert_type(self.info.ep_type));
755 w.set_ea(self.info.addr.index() as _);
756 w.set_stat_rx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
757 w.set_stat_tx(Stat(0));
758 w.set_ctr_rx(true); // don't clear
759 w.set_ctr_tx(true); // don't clear
760 })
761 };
762 trace!("READ OK, rx_len = {}", rx_len);
763 727
764 Ok(rx_len) 728 let regs = T::regs();
765 } 729 unsafe {
730 regs.epr(index).write(|w| {
731 w.set_ep_type(convert_type(self.info.ep_type));
732 w.set_ea(self.info.addr.index() as _);
733 w.set_stat_rx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
734 w.set_stat_tx(Stat(0));
735 w.set_ctr_rx(true); // don't clear
736 w.set_ctr_tx(true); // don't clear
737 })
738 };
739 trace!("READ OK, rx_len = {}", rx_len);
740
741 Ok(rx_len)
766 } 742 }
767} 743}
768 744
769impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { 745impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
770 type WriteFuture<'a> = impl Future<Output = Result<(), EndpointError>> + 'a where Self: 'a; 746 async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError> {
771 747 if buf.len() > self.info.max_packet_size as usize {
772 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { 748 return Err(EndpointError::BufferOverflow);
773 async move { 749 }
774 if buf.len() > self.info.max_packet_size as usize {
775 return Err(EndpointError::BufferOverflow);
776 }
777
778 let index = self.info.addr.index();
779 750
780 trace!("WRITE WAITING"); 751 let index = self.info.addr.index();
781 let stat = poll_fn(|cx| {
782 EP_IN_WAKERS[index].register(cx.waker());
783 let regs = T::regs();
784 let stat = unsafe { regs.epr(index).read() }.stat_tx();
785 if matches!(stat, Stat::NAK | Stat::DISABLED) {
786 Poll::Ready(stat)
787 } else {
788 Poll::Pending
789 }
790 })
791 .await;
792 752
793 if stat == Stat::DISABLED { 753 trace!("WRITE WAITING");
794 return Err(EndpointError::Disabled); 754 let stat = poll_fn(|cx| {
755 EP_IN_WAKERS[index].register(cx.waker());
756 let regs = T::regs();
757 let stat = unsafe { regs.epr(index).read() }.stat_tx();
758 if matches!(stat, Stat::NAK | Stat::DISABLED) {
759 Poll::Ready(stat)
760 } else {
761 Poll::Pending
795 } 762 }
763 })
764 .await;
796 765
797 self.write_data(buf); 766 if stat == Stat::DISABLED {
767 return Err(EndpointError::Disabled);
768 }
798 769
799 let regs = T::regs(); 770 self.write_data(buf);
800 unsafe {
801 regs.epr(index).write(|w| {
802 w.set_ep_type(convert_type(self.info.ep_type));
803 w.set_ea(self.info.addr.index() as _);
804 w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
805 w.set_stat_rx(Stat(0));
806 w.set_ctr_rx(true); // don't clear
807 w.set_ctr_tx(true); // don't clear
808 })
809 };
810 771
811 trace!("WRITE OK"); 772 let regs = T::regs();
773 unsafe {
774 regs.epr(index).write(|w| {
775 w.set_ep_type(convert_type(self.info.ep_type));
776 w.set_ea(self.info.addr.index() as _);
777 w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
778 w.set_stat_rx(Stat(0));
779 w.set_ctr_rx(true); // don't clear
780 w.set_ctr_tx(true); // don't clear
781 })
782 };
812 783
813 Ok(()) 784 trace!("WRITE OK");
814 } 785
786 Ok(())
815 } 787 }
816} 788}
817 789
@@ -823,84 +795,16 @@ pub struct ControlPipe<'d, T: Instance> {
823} 795}
824 796
825impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { 797impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
826 type SetupFuture<'a> = impl Future<Output = [u8;8]> + 'a where Self: 'a;
827 type DataOutFuture<'a> = impl Future<Output = Result<usize, EndpointError>> + 'a where Self: 'a;
828 type DataInFuture<'a> = impl Future<Output = Result<(), EndpointError>> + 'a where Self: 'a;
829 type AcceptFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
830 type RejectFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
831
832 fn max_packet_size(&self) -> usize { 798 fn max_packet_size(&self) -> usize {
833 usize::from(self.max_packet_size) 799 usize::from(self.max_packet_size)
834 } 800 }
835 801
836 fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a> { 802 async fn setup(&mut self) -> [u8; 8] {
837 async move { 803 loop {
838 loop { 804 trace!("SETUP read waiting");
839 trace!("SETUP read waiting");
840 poll_fn(|cx| {
841 EP_OUT_WAKERS[0].register(cx.waker());
842 if EP0_SETUP.load(Ordering::Relaxed) {
843 Poll::Ready(())
844 } else {
845 Poll::Pending
846 }
847 })
848 .await;
849
850 let mut buf = [0; 8];
851 let rx_len = self.ep_out.read_data(&mut buf);
852 if rx_len != Ok(8) {
853 trace!("SETUP read failed: {:?}", rx_len);
854 continue;
855 }
856
857 EP0_SETUP.store(false, Ordering::Relaxed);
858
859 trace!("SETUP read ok");
860 return buf;
861 }
862 }
863 }
864
865 fn data_out<'a>(&'a mut self, buf: &'a mut [u8], first: bool, last: bool) -> Self::DataOutFuture<'a> {
866 async move {
867 let regs = T::regs();
868
869 // When a SETUP is received, Stat/Stat is set to NAK.
870 // On first transfer, we must set Stat=VALID, to get the OUT data stage.
871 // We want Stat=STALL so that the host gets a STALL if it switches to the status
872 // stage too soon, except in the last transfer we set Stat=NAK so that it waits
873 // for the status stage, which we will ACK or STALL later.
874 if first || last {
875 let mut stat_rx = 0;
876 let mut stat_tx = 0;
877 if first {
878 // change NAK -> VALID
879 stat_rx ^= Stat::NAK.0 ^ Stat::VALID.0;
880 stat_tx ^= Stat::NAK.0 ^ Stat::STALL.0;
881 }
882 if last {
883 // change STALL -> VALID
884 stat_tx ^= Stat::STALL.0 ^ Stat::NAK.0;
885 }
886 // Note: if this is the first AND last transfer, the above effectively
887 // changes stat_tx like NAK -> NAK, so noop.
888 unsafe {
889 regs.epr(0).write(|w| {
890 w.set_ep_type(EpType::CONTROL);
891 w.set_stat_rx(Stat(stat_rx));
892 w.set_stat_tx(Stat(stat_tx));
893 w.set_ctr_rx(true); // don't clear
894 w.set_ctr_tx(true); // don't clear
895 })
896 }
897 }
898
899 trace!("data_out WAITING, buf.len() = {}", buf.len());
900 poll_fn(|cx| { 805 poll_fn(|cx| {
901 EP_OUT_WAKERS[0].register(cx.waker()); 806 EP_OUT_WAKERS[0].register(cx.waker());
902 let regs = T::regs(); 807 if EP0_SETUP.load(Ordering::Relaxed) {
903 if unsafe { regs.epr(0).read() }.stat_rx() == Stat::NAK {
904 Poll::Ready(()) 808 Poll::Ready(())
905 } else { 809 } else {
906 Poll::Pending 810 Poll::Pending
@@ -908,157 +812,209 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
908 }) 812 })
909 .await; 813 .await;
910 814
911 if EP0_SETUP.load(Ordering::Relaxed) { 815 let mut buf = [0; 8];
912 trace!("received another SETUP, aborting data_out."); 816 let rx_len = self.ep_out.read_data(&mut buf);
913 return Err(EndpointError::Disabled); 817 if rx_len != Ok(8) {
818 trace!("SETUP read failed: {:?}", rx_len);
819 continue;
914 } 820 }
915 821
916 let rx_len = self.ep_out.read_data(buf)?; 822 EP0_SETUP.store(false, Ordering::Relaxed);
823
824 trace!("SETUP read ok");
825 return buf;
826 }
827 }
828
829 async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError> {
830 let regs = T::regs();
917 831
832 // When a SETUP is received, Stat/Stat is set to NAK.
833 // On first transfer, we must set Stat=VALID, to get the OUT data stage.
834 // We want Stat=STALL so that the host gets a STALL if it switches to the status
835 // stage too soon, except in the last transfer we set Stat=NAK so that it waits
836 // for the status stage, which we will ACK or STALL later.
837 if first || last {
838 let mut stat_rx = 0;
839 let mut stat_tx = 0;
840 if first {
841 // change NAK -> VALID
842 stat_rx ^= Stat::NAK.0 ^ Stat::VALID.0;
843 stat_tx ^= Stat::NAK.0 ^ Stat::STALL.0;
844 }
845 if last {
846 // change STALL -> VALID
847 stat_tx ^= Stat::STALL.0 ^ Stat::NAK.0;
848 }
849 // Note: if this is the first AND last transfer, the above effectively
850 // changes stat_tx like NAK -> NAK, so noop.
918 unsafe { 851 unsafe {
919 regs.epr(0).write(|w| { 852 regs.epr(0).write(|w| {
920 w.set_ep_type(EpType::CONTROL); 853 w.set_ep_type(EpType::CONTROL);
921 w.set_stat_rx(Stat(match last { 854 w.set_stat_rx(Stat(stat_rx));
922 // If last, set STAT_RX=STALL. 855 w.set_stat_tx(Stat(stat_tx));
923 true => Stat::NAK.0 ^ Stat::STALL.0,
924 // Otherwise, set STAT_RX=VALID, to allow the host to send the next packet.
925 false => Stat::NAK.0 ^ Stat::VALID.0,
926 }));
927 w.set_ctr_rx(true); // don't clear 856 w.set_ctr_rx(true); // don't clear
928 w.set_ctr_tx(true); // don't clear 857 w.set_ctr_tx(true); // don't clear
929 }) 858 })
930 }; 859 }
931
932 Ok(rx_len)
933 } 860 }
934 }
935
936 fn data_in<'a>(&'a mut self, buf: &'a [u8], first: bool, last: bool) -> Self::DataInFuture<'a> {
937 async move {
938 trace!("control: data_in");
939 861
940 if buf.len() > self.ep_in.info.max_packet_size as usize { 862 trace!("data_out WAITING, buf.len() = {}", buf.len());
941 return Err(EndpointError::BufferOverflow); 863 poll_fn(|cx| {
864 EP_OUT_WAKERS[0].register(cx.waker());
865 let regs = T::regs();
866 if unsafe { regs.epr(0).read() }.stat_rx() == Stat::NAK {
867 Poll::Ready(())
868 } else {
869 Poll::Pending
942 } 870 }
871 })
872 .await;
943 873
944 let regs = T::regs(); 874 if EP0_SETUP.load(Ordering::Relaxed) {
875 trace!("received another SETUP, aborting data_out.");
876 return Err(EndpointError::Disabled);
877 }
945 878
946 // When a SETUP is received, Stat is set to NAK. 879 let rx_len = self.ep_out.read_data(buf)?;
947 // We want it to be STALL in non-last transfers.
948 // We want it to be VALID in last transfer, so the HW does the status stage.
949 if first || last {
950 let mut stat_rx = 0;
951 if first {
952 // change NAK -> STALL
953 stat_rx ^= Stat::NAK.0 ^ Stat::STALL.0;
954 }
955 if last {
956 // change STALL -> VALID
957 stat_rx ^= Stat::STALL.0 ^ Stat::VALID.0;
958 }
959 // Note: if this is the first AND last transfer, the above effectively
960 // does a change of NAK -> VALID.
961 unsafe {
962 regs.epr(0).write(|w| {
963 w.set_ep_type(EpType::CONTROL);
964 w.set_stat_rx(Stat(stat_rx));
965 w.set_ep_kind(last); // set OUT_STATUS if last.
966 w.set_ctr_rx(true); // don't clear
967 w.set_ctr_tx(true); // don't clear
968 })
969 }
970 }
971 880
972 trace!("WRITE WAITING"); 881 unsafe {
973 poll_fn(|cx| { 882 regs.epr(0).write(|w| {
974 EP_IN_WAKERS[0].register(cx.waker()); 883 w.set_ep_type(EpType::CONTROL);
975 EP_OUT_WAKERS[0].register(cx.waker()); 884 w.set_stat_rx(Stat(match last {
976 let regs = T::regs(); 885 // If last, set STAT_RX=STALL.
977 if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK { 886 true => Stat::NAK.0 ^ Stat::STALL.0,
978 Poll::Ready(()) 887 // Otherwise, set STAT_RX=VALID, to allow the host to send the next packet.
979 } else { 888 false => Stat::NAK.0 ^ Stat::VALID.0,
980 Poll::Pending 889 }));
981 } 890 w.set_ctr_rx(true); // don't clear
891 w.set_ctr_tx(true); // don't clear
982 }) 892 })
983 .await; 893 };
984 894
985 if EP0_SETUP.load(Ordering::Relaxed) { 895 Ok(rx_len)
986 trace!("received another SETUP, aborting data_in."); 896 }
987 return Err(EndpointError::Disabled);
988 }
989 897
990 self.ep_in.write_data(buf); 898 async fn data_in(&mut self, data: &[u8], first: bool, last: bool) -> Result<(), EndpointError> {
899 trace!("control: data_in");
991 900
992 let regs = T::regs(); 901 if data.len() > self.ep_in.info.max_packet_size as usize {
902 return Err(EndpointError::BufferOverflow);
903 }
904
905 let regs = T::regs();
906
907 // When a SETUP is received, Stat is set to NAK.
908 // We want it to be STALL in non-last transfers.
909 // We want it to be VALID in last transfer, so the HW does the status stage.
910 if first || last {
911 let mut stat_rx = 0;
912 if first {
913 // change NAK -> STALL
914 stat_rx ^= Stat::NAK.0 ^ Stat::STALL.0;
915 }
916 if last {
917 // change STALL -> VALID
918 stat_rx ^= Stat::STALL.0 ^ Stat::VALID.0;
919 }
920 // Note: if this is the first AND last transfer, the above effectively
921 // does a change of NAK -> VALID.
993 unsafe { 922 unsafe {
994 regs.epr(0).write(|w| { 923 regs.epr(0).write(|w| {
995 w.set_ep_type(EpType::CONTROL); 924 w.set_ep_type(EpType::CONTROL);
996 w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); 925 w.set_stat_rx(Stat(stat_rx));
997 w.set_ep_kind(last); // set OUT_STATUS if last. 926 w.set_ep_kind(last); // set OUT_STATUS if last.
998 w.set_ctr_rx(true); // don't clear 927 w.set_ctr_rx(true); // don't clear
999 w.set_ctr_tx(true); // don't clear 928 w.set_ctr_tx(true); // don't clear
1000 }) 929 })
1001 }; 930 }
1002
1003 trace!("WRITE OK");
1004
1005 Ok(())
1006 } 931 }
1007 }
1008 932
1009 fn accept<'a>(&'a mut self) -> Self::AcceptFuture<'a> { 933 trace!("WRITE WAITING");
1010 async move { 934 poll_fn(|cx| {
935 EP_IN_WAKERS[0].register(cx.waker());
936 EP_OUT_WAKERS[0].register(cx.waker());
1011 let regs = T::regs(); 937 let regs = T::regs();
1012 trace!("control: accept"); 938 if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK {
939 Poll::Ready(())
940 } else {
941 Poll::Pending
942 }
943 })
944 .await;
1013 945
1014 self.ep_in.write_data(&[]); 946 if EP0_SETUP.load(Ordering::Relaxed) {
947 trace!("received another SETUP, aborting data_in.");
948 return Err(EndpointError::Disabled);
949 }
1015 950
1016 // Set OUT=stall, IN=accept 951 self.ep_in.write_data(data);
1017 unsafe {
1018 let epr = regs.epr(0).read();
1019 regs.epr(0).write(|w| {
1020 w.set_ep_type(EpType::CONTROL);
1021 w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0));
1022 w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::VALID.0));
1023 w.set_ctr_rx(true); // don't clear
1024 w.set_ctr_tx(true); // don't clear
1025 });
1026 }
1027 trace!("control: accept WAITING");
1028 952
1029 // Wait is needed, so that we don't set the address too soon, breaking the status stage. 953 let regs = T::regs();
1030 // (embassy-usb sets the address after accept() returns) 954 unsafe {
1031 poll_fn(|cx| { 955 regs.epr(0).write(|w| {
1032 EP_IN_WAKERS[0].register(cx.waker()); 956 w.set_ep_type(EpType::CONTROL);
1033 let regs = T::regs(); 957 w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
1034 if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK { 958 w.set_ep_kind(last); // set OUT_STATUS if last.
1035 Poll::Ready(()) 959 w.set_ctr_rx(true); // don't clear
1036 } else { 960 w.set_ctr_tx(true); // don't clear
1037 Poll::Pending
1038 }
1039 }) 961 })
1040 .await; 962 };
1041 963
1042 trace!("control: accept OK"); 964 trace!("WRITE OK");
1043 } 965
966 Ok(())
1044 } 967 }
1045 968
1046 fn reject<'a>(&'a mut self) -> Self::RejectFuture<'a> { 969 async fn accept(&mut self) {
1047 async move { 970 let regs = T::regs();
1048 let regs = T::regs(); 971 trace!("control: accept");
1049 trace!("control: reject");
1050 972
1051 // Set IN+OUT to stall 973 self.ep_in.write_data(&[]);
1052 unsafe { 974
1053 let epr = regs.epr(0).read(); 975 // Set OUT=stall, IN=accept
1054 regs.epr(0).write(|w| { 976 unsafe {
1055 w.set_ep_type(EpType::CONTROL); 977 let epr = regs.epr(0).read();
1056 w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); 978 regs.epr(0).write(|w| {
1057 w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::STALL.0)); 979 w.set_ep_type(EpType::CONTROL);
1058 w.set_ctr_rx(true); // don't clear 980 w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0));
1059 w.set_ctr_tx(true); // don't clear 981 w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::VALID.0));
1060 }); 982 w.set_ctr_rx(true); // don't clear
983 w.set_ctr_tx(true); // don't clear
984 });
985 }
986 trace!("control: accept WAITING");
987
988 // Wait is needed, so that we don't set the address too soon, breaking the status stage.
989 // (embassy-usb sets the address after accept() returns)
990 poll_fn(|cx| {
991 EP_IN_WAKERS[0].register(cx.waker());
992 let regs = T::regs();
993 if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK {
994 Poll::Ready(())
995 } else {
996 Poll::Pending
1061 } 997 }
998 })
999 .await;
1000
1001 trace!("control: accept OK");
1002 }
1003
1004 async fn reject(&mut self) {
1005 let regs = T::regs();
1006 trace!("control: reject");
1007
1008 // Set IN+OUT to stall
1009 unsafe {
1010 let epr = regs.epr(0).read();
1011 regs.epr(0).write(|w| {
1012 w.set_ep_type(EpType::CONTROL);
1013 w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0));
1014 w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::STALL.0));
1015 w.set_ctr_rx(true); // don't clear
1016 w.set_ctr_tx(true); // don't clear
1017 });
1062 } 1018 }
1063 } 1019 }
1064} 1020}
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs
index 85176eefc..92b9a5ca8 100644
--- a/embassy-stm32/src/wdg/mod.rs
+++ b/embassy-stm32/src/wdg/mod.rs
@@ -13,12 +13,12 @@ pub struct IndependentWatchdog<'d, T: Instance> {
13const MAX_RL: u16 = 0xFFF; 13const MAX_RL: u16 = 0xFFF;
14 14
15/// Calculates maximum watchdog timeout in us (RL = 0xFFF) for a given prescaler 15/// Calculates maximum watchdog timeout in us (RL = 0xFFF) for a given prescaler
16const fn max_timeout(prescaler: u8) -> u32 { 16const fn max_timeout(prescaler: u16) -> u32 {
17 1_000_000 * MAX_RL as u32 / (LSI_FREQ.0 / prescaler as u32) 17 1_000_000 * MAX_RL as u32 / (LSI_FREQ.0 / prescaler as u32)
18} 18}
19 19
20/// Calculates watchdog reload value for the given prescaler and desired timeout 20/// Calculates watchdog reload value for the given prescaler and desired timeout
21const fn reload_value(prescaler: u8, timeout_us: u32) -> u16 { 21const fn reload_value(prescaler: u16, timeout_us: u32) -> u16 {
22 (timeout_us / prescaler as u32 * LSI_FREQ.0 / 1_000_000) as u16 22 (timeout_us / prescaler as u32 * LSI_FREQ.0 / 1_000_000) as u16
23} 23}
24 24
@@ -33,12 +33,12 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
33 // Find lowest prescaler value, which makes watchdog period longer or equal to timeout. 33 // Find lowest prescaler value, which makes watchdog period longer or equal to timeout.
34 // This iterates from 4 (2^2) to 256 (2^8). 34 // This iterates from 4 (2^2) to 256 (2^8).
35 let psc_power = unwrap!((2..=8).find(|psc_power| { 35 let psc_power = unwrap!((2..=8).find(|psc_power| {
36 let psc = 2u8.pow(*psc_power); 36 let psc = 2u16.pow(*psc_power);
37 timeout_us <= max_timeout(psc) 37 timeout_us <= max_timeout(psc)
38 })); 38 }));
39 39
40 // Prescaler value 40 // Prescaler value
41 let psc = 2u8.pow(psc_power); 41 let psc = 2u16.pow(psc_power);
42 42
43 // Convert prescaler power to PR register value 43 // Convert prescaler power to PR register value
44 let pr = psc_power as u8 - 2; 44 let pr = psc_power as u8 - 2;
diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml
index b7fe1643c..1eeb94c9a 100644
--- a/embassy-sync/Cargo.toml
+++ b/embassy-sync/Cargo.toml
@@ -35,7 +35,7 @@ atomic-polyfill = "1.0.1"
35critical-section = "1.1" 35critical-section = "1.1"
36heapless = "0.7.5" 36heapless = "0.7.5"
37cfg-if = "1.0.0" 37cfg-if = "1.0.0"
38embedded-io = "0.3.1" 38embedded-io = "0.4.0"
39 39
40[dev-dependencies] 40[dev-dependencies]
41futures-executor = { version = "0.3.17", features = [ "thread-pool" ] } 41futures-executor = { version = "0.3.17", features = [ "thread-pool" ] }
diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs
index 80bb907a3..f9435ecff 100644
--- a/embassy-sync/src/lib.rs
+++ b/embassy-sync/src/lib.rs
@@ -1,5 +1,6 @@
1#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)] 1#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)]
2#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))] 2#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))]
3#![cfg_attr(feature = "nightly", allow(incomplete_features))]
3#![allow(clippy::new_without_default)] 4#![allow(clippy::new_without_default)]
4#![doc = include_str!("../README.md")] 5#![doc = include_str!("../README.md")]
5#![warn(missing_docs)] 6#![warn(missing_docs)]
diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs
index cd577f34f..905686acd 100644
--- a/embassy-sync/src/pipe.rs
+++ b/embassy-sync/src/pipe.rs
@@ -352,8 +352,6 @@ where
352mod io_impls { 352mod io_impls {
353 use core::convert::Infallible; 353 use core::convert::Infallible;
354 354
355 use futures_util::FutureExt;
356
357 use super::*; 355 use super::*;
358 356
359 impl<M: RawMutex, const N: usize> embedded_io::Io for Pipe<M, N> { 357 impl<M: RawMutex, const N: usize> embedded_io::Io for Pipe<M, N> {
@@ -361,30 +359,18 @@ mod io_impls {
361 } 359 }
362 360
363 impl<M: RawMutex, const N: usize> embedded_io::asynch::Read for Pipe<M, N> { 361 impl<M: RawMutex, const N: usize> embedded_io::asynch::Read for Pipe<M, N> {
364 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 362 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
365 where 363 Ok(Pipe::read(self, buf).await)
366 Self: 'a;
367
368 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
369 Pipe::read(self, buf).map(Ok)
370 } 364 }
371 } 365 }
372 366
373 impl<M: RawMutex, const N: usize> embedded_io::asynch::Write for Pipe<M, N> { 367 impl<M: RawMutex, const N: usize> embedded_io::asynch::Write for Pipe<M, N> {
374 type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 368 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
375 where 369 Ok(Pipe::write(self, buf).await)
376 Self: 'a;
377
378 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
379 Pipe::write(self, buf).map(Ok)
380 } 370 }
381 371
382 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a 372 async fn flush(&mut self) -> Result<(), Self::Error> {
383 where 373 Ok(())
384 Self: 'a;
385
386 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
387 futures_util::future::ready(Ok(()))
388 } 374 }
389 } 375 }
390 376
@@ -393,30 +379,18 @@ mod io_impls {
393 } 379 }
394 380
395 impl<M: RawMutex, const N: usize> embedded_io::asynch::Read for &Pipe<M, N> { 381 impl<M: RawMutex, const N: usize> embedded_io::asynch::Read for &Pipe<M, N> {
396 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 382 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
397 where 383 Ok(Pipe::read(self, buf).await)
398 Self: 'a;
399
400 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
401 Pipe::read(self, buf).map(Ok)
402 } 384 }
403 } 385 }
404 386
405 impl<M: RawMutex, const N: usize> embedded_io::asynch::Write for &Pipe<M, N> { 387 impl<M: RawMutex, const N: usize> embedded_io::asynch::Write for &Pipe<M, N> {
406 type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 388 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
407 where 389 Ok(Pipe::write(self, buf).await)
408 Self: 'a;
409
410 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
411 Pipe::write(self, buf).map(Ok)
412 } 390 }
413 391
414 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a 392 async fn flush(&mut self) -> Result<(), Self::Error> {
415 where 393 Ok(())
416 Self: 'a;
417
418 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
419 futures_util::future::ready(Ok(()))
420 } 394 }
421 } 395 }
422 396
@@ -425,12 +399,8 @@ mod io_impls {
425 } 399 }
426 400
427 impl<M: RawMutex, const N: usize> embedded_io::asynch::Read for Reader<'_, M, N> { 401 impl<M: RawMutex, const N: usize> embedded_io::asynch::Read for Reader<'_, M, N> {
428 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 402 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
429 where 403 Ok(Reader::read(self, buf).await)
430 Self: 'a;
431
432 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
433 Reader::read(self, buf).map(Ok)
434 } 404 }
435 } 405 }
436 406
@@ -439,20 +409,12 @@ mod io_impls {
439 } 409 }
440 410
441 impl<M: RawMutex, const N: usize> embedded_io::asynch::Write for Writer<'_, M, N> { 411 impl<M: RawMutex, const N: usize> embedded_io::asynch::Write for Writer<'_, M, N> {
442 type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> + 'a 412 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
443 where 413 Ok(Writer::write(self, buf).await)
444 Self: 'a;
445
446 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
447 Writer::write(self, buf).map(Ok)
448 } 414 }
449 415
450 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a 416 async fn flush(&mut self) -> Result<(), Self::Error> {
451 where 417 Ok(())
452 Self: 'a;
453
454 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
455 futures_util::future::ready(Ok(()))
456 } 418 }
457 } 419 }
458} 420}
diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs
index c3c10a8af..bea67d8be 100644
--- a/embassy-sync/src/signal.rs
+++ b/embassy-sync/src/signal.rs
@@ -56,6 +56,15 @@ where
56 } 56 }
57} 57}
58 58
59impl<M, T> Default for Signal<M, T>
60where
61 M: RawMutex,
62{
63 fn default() -> Self {
64 Self::new()
65 }
66}
67
59impl<M, T: Send> Signal<M, T> 68impl<M, T: Send> Signal<M, T>
60where 69where
61 M: RawMutex, 70 M: RawMutex,
diff --git a/embassy-sync/src/waitqueue/waker.rs b/embassy-sync/src/waitqueue/waker.rs
index 64e300eb8..9ce94a089 100644
--- a/embassy-sync/src/waitqueue/waker.rs
+++ b/embassy-sync/src/waitqueue/waker.rs
@@ -6,7 +6,7 @@ use crate::blocking_mutex::raw::CriticalSectionRawMutex;
6use crate::blocking_mutex::Mutex; 6use crate::blocking_mutex::Mutex;
7 7
8/// Utility struct to register and wake a waker. 8/// Utility struct to register and wake a waker.
9#[derive(Debug)] 9#[derive(Debug, Default)]
10pub struct WakerRegistration { 10pub struct WakerRegistration {
11 waker: Option<Waker>, 11 waker: Option<Waker>,
12} 12}
diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml
index 9487003cc..5701ab351 100644
--- a/embassy-time/Cargo.toml
+++ b/embassy-time/Cargo.toml
@@ -134,7 +134,7 @@ log = { version = "0.4.14", optional = true }
134 134
135embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } 135embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" }
136embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} 136embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true}
137embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true} 137embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true}
138 138
139futures-util = { version = "0.3.17", default-features = false } 139futures-util = { version = "0.3.17", default-features = false }
140embassy-sync = { version = "0.1", path = "../embassy-sync" } 140embassy-sync = { version = "0.1", path = "../embassy-sync" }
diff --git a/embassy-time/src/delay.rs b/embassy-time/src/delay.rs
index ff6b6869a..0ca176abd 100644
--- a/embassy-time/src/delay.rs
+++ b/embassy-time/src/delay.rs
@@ -33,26 +33,18 @@ mod eh1 {
33 33
34#[cfg(all(feature = "unstable-traits", feature = "nightly"))] 34#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
35mod eha { 35mod eha {
36 use core::future::Future;
37
38 use futures_util::FutureExt;
39
40 use super::*; 36 use super::*;
41 use crate::Timer; 37 use crate::Timer;
42 38
43 impl embedded_hal_async::delay::DelayUs for Delay { 39 impl embedded_hal_async::delay::DelayUs for Delay {
44 type Error = core::convert::Infallible; 40 type Error = core::convert::Infallible;
45 41
46 type DelayUsFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 42 async fn delay_us(&mut self, micros: u32) -> Result<(), Self::Error> {
47 43 Ok(Timer::after(Duration::from_micros(micros as _)).await)
48 fn delay_us(&mut self, micros: u32) -> Self::DelayUsFuture<'_> {
49 Timer::after(Duration::from_micros(micros as _)).map(Ok)
50 } 44 }
51 45
52 type DelayMsFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; 46 async fn delay_ms(&mut self, millis: u32) -> Result<(), Self::Error> {
53 47 Ok(Timer::after(Duration::from_millis(millis as _)).await)
54 fn delay_ms(&mut self, millis: u32) -> Self::DelayMsFuture<'_> {
55 Timer::after(Duration::from_millis(millis as _)).map(Ok)
56 } 48 }
57 } 49 }
58} 50}
diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs
index 586aa28de..8b0aebe19 100644
--- a/embassy-time/src/lib.rs
+++ b/embassy-time/src/lib.rs
@@ -1,5 +1,6 @@
1#![cfg_attr(not(any(feature = "std", feature = "wasm", test)), no_std)] 1#![cfg_attr(not(any(feature = "std", feature = "wasm", test)), no_std)]
2#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))] 2#![cfg_attr(feature = "nightly", feature(async_fn_in_trait))]
3#![cfg_attr(feature = "nightly", allow(incomplete_features))]
3#![doc = include_str!("../README.md")] 4#![doc = include_str!("../README.md")]
4#![allow(clippy::new_without_default)] 5#![allow(clippy::new_without_default)]
5#![warn(missing_docs)] 6#![warn(missing_docs)]
diff --git a/embassy-usb-driver/src/lib.rs b/embassy-usb-driver/src/lib.rs
index 931e9c318..9300ff812 100644
--- a/embassy-usb-driver/src/lib.rs
+++ b/embassy-usb-driver/src/lib.rs
@@ -1,6 +1,6 @@
1#![no_std] 1#![no_std]
2 2#![feature(async_fn_in_trait)]
3use core::future::Future; 3#![allow(incomplete_features)]
4 4
5/// Direction of USB traffic. Note that in the USB standard the direction is always indicated from 5/// Direction of USB traffic. Note that in the USB standard the direction is always indicated from
6/// the perspective of the host, which is backward for devices, but the standard directions are used 6/// the perspective of the host, which is backward for devices, but the standard directions are used
@@ -155,27 +155,14 @@ pub trait Driver<'a> {
155} 155}
156 156
157pub trait Bus { 157pub trait Bus {
158 type EnableFuture<'a>: Future<Output = ()> + 'a
159 where
160 Self: 'a;
161 type DisableFuture<'a>: Future<Output = ()> + 'a
162 where
163 Self: 'a;
164 type PollFuture<'a>: Future<Output = Event> + 'a
165 where
166 Self: 'a;
167 type RemoteWakeupFuture<'a>: Future<Output = Result<(), Unsupported>> + 'a
168 where
169 Self: 'a;
170
171 /// Enables the USB peripheral. Soon after enabling the device will be reset, so 158 /// Enables the USB peripheral. Soon after enabling the device will be reset, so
172 /// there is no need to perform a USB reset in this method. 159 /// there is no need to perform a USB reset in this method.
173 fn enable(&mut self) -> Self::EnableFuture<'_>; 160 async fn enable(&mut self);
174 161
175 /// Disables and powers down the USB peripheral. 162 /// Disables and powers down the USB peripheral.
176 fn disable(&mut self) -> Self::DisableFuture<'_>; 163 async fn disable(&mut self);
177 164
178 fn poll<'a>(&'a mut self) -> Self::PollFuture<'a>; 165 async fn poll(&mut self) -> Event;
179 166
180 /// Sets the device USB address to `addr`. 167 /// Sets the device USB address to `addr`.
181 fn set_address(&mut self, addr: u8); 168 fn set_address(&mut self, addr: u8);
@@ -197,7 +184,7 @@ pub trait Bus {
197 /// 184 ///
198 /// # Errors 185 /// # Errors
199 /// 186 ///
200 /// * [`Unsupported`](crate::driver::Unsupported) - This UsbBus implementation doesn't support 187 /// * [`Unsupported`](crate::Unsupported) - This UsbBus implementation doesn't support
201 /// simulating a disconnect or it has not been enabled at creation time. 188 /// simulating a disconnect or it has not been enabled at creation time.
202 fn force_reset(&mut self) -> Result<(), Unsupported> { 189 fn force_reset(&mut self) -> Result<(), Unsupported> {
203 Err(Unsupported) 190 Err(Unsupported)
@@ -207,87 +194,59 @@ pub trait Bus {
207 /// 194 ///
208 /// # Errors 195 /// # Errors
209 /// 196 ///
210 /// * [`Unsupported`](crate::driver::Unsupported) - This UsbBus implementation doesn't support 197 /// * [`Unsupported`](crate::Unsupported) - This UsbBus implementation doesn't support
211 /// remote wakeup or it has not been enabled at creation time. 198 /// remote wakeup or it has not been enabled at creation time.
212 fn remote_wakeup(&mut self) -> Self::RemoteWakeupFuture<'_>; 199 async fn remote_wakeup(&mut self) -> Result<(), Unsupported>;
213} 200}
214 201
215pub trait Endpoint { 202pub trait Endpoint {
216 type WaitEnabledFuture<'a>: Future<Output = ()> + 'a
217 where
218 Self: 'a;
219
220 /// Get the endpoint address 203 /// Get the endpoint address
221 fn info(&self) -> &EndpointInfo; 204 fn info(&self) -> &EndpointInfo;
222 205
223 /// Waits for the endpoint to be enabled. 206 /// Waits for the endpoint to be enabled.
224 fn wait_enabled(&mut self) -> Self::WaitEnabledFuture<'_>; 207 async fn wait_enabled(&mut self);
225} 208}
226 209
227pub trait EndpointOut: Endpoint { 210pub trait EndpointOut: Endpoint {
228 type ReadFuture<'a>: Future<Output = Result<usize, EndpointError>> + 'a
229 where
230 Self: 'a;
231
232 /// Reads a single packet of data from the endpoint, and returns the actual length of 211 /// Reads a single packet of data from the endpoint, and returns the actual length of
233 /// the packet. 212 /// the packet.
234 /// 213 ///
235 /// This should also clear any NAK flags and prepare the endpoint to receive the next packet. 214 /// This should also clear any NAK flags and prepare the endpoint to receive the next packet.
236 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a>; 215 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError>;
237} 216}
238 217
239pub trait ControlPipe { 218pub trait ControlPipe {
240 type SetupFuture<'a>: Future<Output = [u8; 8]> + 'a
241 where
242 Self: 'a;
243 type DataOutFuture<'a>: Future<Output = Result<usize, EndpointError>> + 'a
244 where
245 Self: 'a;
246 type DataInFuture<'a>: Future<Output = Result<(), EndpointError>> + 'a
247 where
248 Self: 'a;
249 type AcceptFuture<'a>: Future<Output = ()> + 'a
250 where
251 Self: 'a;
252 type RejectFuture<'a>: Future<Output = ()> + 'a
253 where
254 Self: 'a;
255
256 /// Maximum packet size for the control pipe 219 /// Maximum packet size for the control pipe
257 fn max_packet_size(&self) -> usize; 220 fn max_packet_size(&self) -> usize;
258 221
259 /// Reads a single setup packet from the endpoint. 222 /// Reads a single setup packet from the endpoint.
260 fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a>; 223 async fn setup(&mut self) -> [u8; 8];
261 224
262 /// Reads a DATA OUT packet into `buf` in response to a control write request. 225 /// Reads a DATA OUT packet into `buf` in response to a control write request.
263 /// 226 ///
264 /// Must be called after `setup()` for requests with `direction` of `Out` 227 /// Must be called after `setup()` for requests with `direction` of `Out`
265 /// and `length` greater than zero. 228 /// and `length` greater than zero.
266 fn data_out<'a>(&'a mut self, buf: &'a mut [u8], first: bool, last: bool) -> Self::DataOutFuture<'a>; 229 async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError>;
267 230
268 /// Sends a DATA IN packet with `data` in response to a control read request. 231 /// Sends a DATA IN packet with `data` in response to a control read request.
269 /// 232 ///
270 /// If `last_packet` is true, the STATUS packet will be ACKed following the transfer of `data`. 233 /// If `last_packet` is true, the STATUS packet will be ACKed following the transfer of `data`.
271 fn data_in<'a>(&'a mut self, data: &'a [u8], first: bool, last: bool) -> Self::DataInFuture<'a>; 234 async fn data_in(&mut self, data: &[u8], first: bool, last: bool) -> Result<(), EndpointError>;
272 235
273 /// Accepts a control request. 236 /// Accepts a control request.
274 /// 237 ///
275 /// Causes the STATUS packet for the current request to be ACKed. 238 /// Causes the STATUS packet for the current request to be ACKed.
276 fn accept<'a>(&'a mut self) -> Self::AcceptFuture<'a>; 239 async fn accept(&mut self);
277 240
278 /// Rejects a control request. 241 /// Rejects a control request.
279 /// 242 ///
280 /// Sets a STALL condition on the pipe to indicate an error. 243 /// Sets a STALL condition on the pipe to indicate an error.
281 fn reject<'a>(&'a mut self) -> Self::RejectFuture<'a>; 244 async fn reject(&mut self);
282} 245}
283 246
284pub trait EndpointIn: Endpoint { 247pub trait EndpointIn: Endpoint {
285 type WriteFuture<'a>: Future<Output = Result<(), EndpointError>> + 'a
286 where
287 Self: 'a;
288
289 /// Writes a single packet of data to the endpoint. 248 /// Writes a single packet of data to the endpoint.
290 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a>; 249 async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError>;
291} 250}
292 251
293#[derive(Copy, Clone, Eq, PartialEq, Debug)] 252#[derive(Copy, Clone, Eq, PartialEq, Debug)]
diff --git a/embassy-usb-logger/Cargo.toml b/embassy-usb-logger/Cargo.toml
new file mode 100644
index 000000000..2f4665922
--- /dev/null
+++ b/embassy-usb-logger/Cargo.toml
@@ -0,0 +1,13 @@
1[package]
2name = "embassy-usb-logger"
3version = "0.1.0"
4edition = "2021"
5
6[dependencies]
7embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
8embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
9embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
10futures = { version = "0.3", default-features = false }
11static_cell = "1"
12usbd-hid = "0.6.0"
13log = "0.4"
diff --git a/embassy-usb-logger/README.md b/embassy-usb-logger/README.md
new file mode 100644
index 000000000..81b0dcd0e
--- /dev/null
+++ b/embassy-usb-logger/README.md
@@ -0,0 +1,15 @@
1# embassy-usb-logger
2
3USB implementation of the `log` crate. This logger can be used by any device that implements `embassy-usb`. When running,
4it will output all logging done through the `log` facade to the USB serial peripheral.
5
6## Usage
7
8Add the following embassy task to your application. The `Driver` type is different depending on which HAL you use.
9
10 ```rust
11#[embassy_executor::task]
12async fn logger_task(driver: Driver<'static, USB>) {
13 embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver);
14}
15```
diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs
new file mode 100644
index 000000000..6386e2096
--- /dev/null
+++ b/embassy-usb-logger/src/lib.rs
@@ -0,0 +1,146 @@
1#![no_std]
2#![doc = include_str!("../README.md")]
3#![warn(missing_docs)]
4
5use core::fmt::Write as _;
6
7use embassy_futures::join::join;
8use embassy_sync::pipe::Pipe;
9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
10use embassy_usb::driver::Driver;
11use embassy_usb::{Builder, Config};
12use log::{Metadata, Record};
13
14type CS = embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
15
16/// The logger state containing buffers that must live as long as the USB peripheral.
17pub struct LoggerState<'d> {
18 state: State<'d>,
19 device_descriptor: [u8; 32],
20 config_descriptor: [u8; 128],
21 bos_descriptor: [u8; 16],
22 control_buf: [u8; 64],
23}
24
25impl<'d> LoggerState<'d> {
26 /// Create a new instance of the logger state.
27 pub fn new() -> Self {
28 Self {
29 state: State::new(),
30 device_descriptor: [0; 32],
31 config_descriptor: [0; 128],
32 bos_descriptor: [0; 16],
33 control_buf: [0; 64],
34 }
35 }
36}
37
38/// The logger handle, which contains a pipe with configurable size for buffering log messages.
39pub struct UsbLogger<const N: usize> {
40 buffer: Pipe<CS, N>,
41}
42
43impl<const N: usize> UsbLogger<N> {
44 /// Create a new logger instance.
45 pub const fn new() -> Self {
46 Self { buffer: Pipe::new() }
47 }
48
49 /// Run the USB logger using the state and USB driver. Never returns.
50 pub async fn run<'d, D>(&'d self, state: &'d mut LoggerState<'d>, driver: D) -> !
51 where
52 D: Driver<'d>,
53 Self: 'd,
54 {
55 const MAX_PACKET_SIZE: u8 = 64;
56 let mut config = Config::new(0xc0de, 0xcafe);
57 config.manufacturer = Some("Embassy");
58 config.product = Some("USB-serial logger");
59 config.serial_number = None;
60 config.max_power = 100;
61 config.max_packet_size_0 = MAX_PACKET_SIZE;
62
63 // Required for windows compatiblity.
64 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
65 config.device_class = 0xEF;
66 config.device_sub_class = 0x02;
67 config.device_protocol = 0x01;
68 config.composite_with_iads = true;
69
70 let mut builder = Builder::new(
71 driver,
72 config,
73 &mut state.device_descriptor,
74 &mut state.config_descriptor,
75 &mut state.bos_descriptor,
76 &mut state.control_buf,
77 None,
78 );
79
80 // Create classes on the builder.
81 let mut class = CdcAcmClass::new(&mut builder, &mut state.state, MAX_PACKET_SIZE as u16);
82
83 // Build the builder.
84 let mut device = builder.build();
85
86 loop {
87 let run_fut = device.run();
88 let log_fut = async {
89 let mut rx: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize];
90 class.wait_connection().await;
91 loop {
92 let len = self.buffer.read(&mut rx[..]).await;
93 let _ = class.write_packet(&rx[..len]).await;
94 }
95 };
96 join(run_fut, log_fut).await;
97 }
98 }
99}
100
101impl<const N: usize> log::Log for UsbLogger<N> {
102 fn enabled(&self, _metadata: &Metadata) -> bool {
103 true
104 }
105
106 fn log(&self, record: &Record) {
107 if self.enabled(record.metadata()) {
108 let _ = write!(Writer(&self.buffer), "{}\r\n", record.args());
109 }
110 }
111
112 fn flush(&self) {}
113}
114
115struct Writer<'d, const N: usize>(&'d Pipe<CS, N>);
116
117impl<'d, const N: usize> core::fmt::Write for Writer<'d, N> {
118 fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
119 let _ = self.0.try_write(s.as_bytes());
120 Ok(())
121 }
122}
123
124/// Initialize and run the USB serial logger, never returns.
125///
126/// Arguments specify the buffer size, log level and the USB driver, respectively.
127///
128/// # Usage
129///
130/// ```
131/// embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver);
132/// ```
133///
134/// # Safety
135///
136/// This macro should only be invoked only once since it is setting the global logging state of the application.
137#[macro_export]
138macro_rules! run {
139 ( $x:expr, $l:expr, $p:ident ) => {
140 static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::new();
141 unsafe {
142 let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level($l));
143 }
144 let _ = LOGGER.run(&mut ::embassy_usb_logger::LoggerState::new(), $p).await;
145 };
146}
diff --git a/embassy-usb/src/class/hid.rs b/embassy-usb/src/class/hid.rs
index 4d1fa995f..b967aba0e 100644
--- a/embassy-usb/src/class/hid.rs
+++ b/embassy-usb/src/class/hid.rs
@@ -299,7 +299,7 @@ impl<'d, D: Driver<'d>, const N: usize> HidReader<'d, D, N> {
299 /// **Note:** If `N` > the maximum packet size of the endpoint (i.e. output 299 /// **Note:** If `N` > the maximum packet size of the endpoint (i.e. output
300 /// reports may be split across multiple packets) and this method's future 300 /// reports may be split across multiple packets) and this method's future
301 /// is dropped after some packets have been read, the next call to `read()` 301 /// is dropped after some packets have been read, the next call to `read()`
302 /// will return a [`ReadError::SyncError()`]. The range in the sync error 302 /// will return a [`ReadError::Sync`]. The range in the sync error
303 /// indicates the portion `buf` that was filled by the current call to 303 /// indicates the portion `buf` that was filled by the current call to
304 /// `read()`. If the dropped future used the same `buf`, then `buf` will 304 /// `read()`. If the dropped future used the same `buf`, then `buf` will
305 /// contain the full report. 305 /// contain the full report.
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml
index a5d82b601..1e7a5a84b 100644
--- a/examples/boot/application/nrf/Cargo.toml
+++ b/examples/boot/application/nrf/Cargo.toml
@@ -13,7 +13,7 @@ embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot/nrf" }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/rp/.cargo/config.toml b/examples/boot/application/rp/.cargo/config.toml
new file mode 100644
index 000000000..edbd0a867
--- /dev/null
+++ b/examples/boot/application/rp/.cargo/config.toml
@@ -0,0 +1,12 @@
1[unstable]
2build-std = ["core"]
3build-std-features = ["panic_immediate_abort"]
4
5[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6runner = "probe-run --chip RP2040"
7
8[build]
9target = "thumbv6m-none-eabi"
10
11[env]
12DEFMT_LOG = "trace"
diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml
new file mode 100644
index 000000000..8d826790b
--- /dev/null
+++ b/examples/boot/application/rp/Cargo.toml
@@ -0,0 +1,33 @@
1[package]
2edition = "2021"
3name = "embassy-boot-rp-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly"] }
11embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", "unstable-traits", "nightly"] }
12embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp" }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14
15defmt = "0.3"
16defmt-rtt = "0.4"
17panic-probe = { version = "0.3", features = ["print-defmt"], optional = true }
18panic-reset = { version = "0.1.1", optional = true }
19embedded-hal = { version = "0.2.6" }
20
21cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
22cortex-m-rt = "0.7.0"
23
24[features]
25default = ["panic-reset"]
26debug = [
27 "embassy-rp/defmt",
28 "embassy-boot-rp/defmt",
29 "panic-probe"
30]
31
32[profile.release]
33debug = true
diff --git a/examples/boot/application/rp/README.md b/examples/boot/application/rp/README.md
new file mode 100644
index 000000000..41304c526
--- /dev/null
+++ b/examples/boot/application/rp/README.md
@@ -0,0 +1,28 @@
1# Examples using bootloader
2
3Example for Raspberry Pi Pico demonstrating the bootloader. The example consists of application binaries, 'a'
4which waits for 5 seconds before flashing the 'b' binary, which blinks the LED.
5
6NOTE: The 'b' binary does not mark the new binary as active, so if you reset the device, it will roll back to the 'a' binary before automatically updating it again.
7
8## Prerequisites
9
10* `cargo-binutils`
11* `cargo-flash`
12* `embassy-boot-rp`
13
14## Usage
15
16```
17# Flash bootloader
18cargo flash --manifest-path ../../bootloader/rp/Cargo.toml --release --chip RP2040
19
20# Build 'b'
21cargo build --release --bin b
22
23# Generate binary for 'b'
24cargo objcopy --release --bin b -- -O binary b.bin
25
26# Flash `a` (which includes b.bin)
27cargo flash --release --bin a --chip RP2040
28```
diff --git a/examples/boot/application/rp/build.rs b/examples/boot/application/rp/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/boot/application/rp/build.rs
@@ -0,0 +1,35 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
35}
diff --git a/examples/boot/application/rp/memory.x b/examples/boot/application/rp/memory.x
new file mode 100644
index 000000000..c19473114
--- /dev/null
+++ b/examples/boot/application/rp/memory.x
@@ -0,0 +1,15 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
5 BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4K
6 FLASH : ORIGIN = 0x10007000, LENGTH = 512K
7 DFU : ORIGIN = 0x10087000, LENGTH = 516K
8 RAM : ORIGIN = 0x20000000, LENGTH = 256K
9}
10
11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOT2);
12__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(BOOT2);
13
14__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOT2);
15__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOT2);
diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs
new file mode 100644
index 000000000..3736c9141
--- /dev/null
+++ b/examples/boot/application/rp/src/bin/a.rs
@@ -0,0 +1,52 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt_rtt as _;
6use embassy_boot_rp::*;
7use embassy_executor::Spawner;
8use embassy_rp::flash::Flash;
9use embassy_rp::gpio::{Level, Output};
10use embassy_time::{Duration, Timer};
11#[cfg(feature = "panic-probe")]
12use panic_probe as _;
13#[cfg(feature = "panic-reset")]
14use panic_reset as _;
15
16static APP_B: &[u8] = include_bytes!("../../b.bin");
17const FLASH_SIZE: usize = 2 * 1024 * 1024;
18
19#[embassy_executor::main]
20async fn main(_s: Spawner) {
21 let p = embassy_rp::init(Default::default());
22 let mut led = Output::new(p.PIN_25, Level::Low);
23
24 let mut flash: Flash<_, FLASH_SIZE> = Flash::new(p.FLASH);
25
26 let mut updater = FirmwareUpdater::default();
27
28 Timer::after(Duration::from_secs(5)).await;
29 led.set_high();
30 let mut offset = 0;
31 let mut buf: AlignedBuffer<4096> = AlignedBuffer([0; 4096]);
32 defmt::info!("preparing update");
33 let mut writer = updater
34 .prepare_update_blocking(&mut flash)
35 .map_err(|e| defmt::warn!("E: {:?}", defmt::Debug2Format(&e)))
36 .unwrap();
37 defmt::info!("writer created, starting write");
38 for chunk in APP_B.chunks(4096) {
39 buf.0[..chunk.len()].copy_from_slice(chunk);
40 defmt::info!("writing block at offset {}", offset);
41 writer
42 .write_block_blocking(offset, &buf.0[..], &mut flash, 256)
43 .unwrap();
44 offset += chunk.len();
45 }
46 defmt::info!("firmware written, marking update");
47 updater.mark_updated_blocking(&mut flash, &mut buf.0[..1]).unwrap();
48 Timer::after(Duration::from_secs(2)).await;
49 led.set_low();
50 defmt::info!("update marked, resetting");
51 cortex_m::peripheral::SCB::sys_reset();
52}
diff --git a/examples/boot/application/rp/src/bin/b.rs b/examples/boot/application/rp/src/bin/b.rs
new file mode 100644
index 000000000..47dec329c
--- /dev/null
+++ b/examples/boot/application/rp/src/bin/b.rs
@@ -0,0 +1,23 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use embassy_executor::Spawner;
6use embassy_rp::gpio;
7use embassy_time::{Duration, Timer};
8use gpio::{Level, Output};
9use {defmt_rtt as _, panic_reset as _};
10
11#[embassy_executor::main]
12async fn main(_s: Spawner) {
13 let p = embassy_rp::init(Default::default());
14 let mut led = Output::new(p.PIN_25, Level::Low);
15
16 loop {
17 led.set_high();
18 Timer::after(Duration::from_millis(100)).await;
19
20 led.set_low();
21 Timer::after(Duration::from_millis(100)).await;
22 }
23}
diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml
index 3a1843562..aa279fb76 100644
--- a/examples/boot/application/stm32f3/Cargo.toml
+++ b/examples/boot/application/stm32f3/Cargo.toml
@@ -13,7 +13,7 @@ embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml
index 8d9c4490e..1ec0643a6 100644
--- a/examples/boot/application/stm32f7/Cargo.toml
+++ b/examples/boot/application/stm32f7/Cargo.toml
@@ -13,7 +13,7 @@ embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml
index b4314aa72..a4eefe2a5 100644
--- a/examples/boot/application/stm32h7/Cargo.toml
+++ b/examples/boot/application/stm32h7/Cargo.toml
@@ -13,7 +13,7 @@ embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml
index a17d336a6..36eada29b 100644
--- a/examples/boot/application/stm32l0/Cargo.toml
+++ b/examples/boot/application/stm32l0/Cargo.toml
@@ -13,7 +13,7 @@ embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml
index 683f2c860..67efda748 100644
--- a/examples/boot/application/stm32l1/Cargo.toml
+++ b/examples/boot/application/stm32l1/Cargo.toml
@@ -13,7 +13,7 @@ embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml
index b879c0d76..4b2e02dd2 100644
--- a/examples/boot/application/stm32l4/Cargo.toml
+++ b/examples/boot/application/stm32l4/Cargo.toml
@@ -13,7 +13,7 @@ embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml
index e3bc0e49c..fecbfc51d 100644
--- a/examples/boot/application/stm32wl/Cargo.toml
+++ b/examples/boot/application/stm32wl/Cargo.toml
@@ -13,7 +13,7 @@ embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml
index b417a40d1..8a6f53643 100644
--- a/examples/boot/bootloader/nrf/Cargo.toml
+++ b/examples/boot/bootloader/nrf/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7 7
8[dependencies] 8[dependencies]
9defmt = { version = "0.3", optional = true } 9defmt = { version = "0.3", optional = true }
10defmt-rtt = { version = "0.3", optional = true } 10defmt-rtt = { version = "0.4", optional = true }
11 11
12embassy-nrf = { path = "../../../../embassy-nrf", default-features = false, features = ["nightly"] } 12embassy-nrf = { path = "../../../../embassy-nrf", default-features = false, features = ["nightly"] }
13embassy-boot-nrf = { path = "../../../../embassy-boot/nrf", default-features = false } 13embassy-boot-nrf = { path = "../../../../embassy-boot/nrf", default-features = false }
diff --git a/examples/boot/bootloader/rp/.cargo/config.toml b/examples/boot/bootloader/rp/.cargo/config.toml
new file mode 100644
index 000000000..18bd4dfe8
--- /dev/null
+++ b/examples/boot/bootloader/rp/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-run --chip RP2040"
3
4[build]
5target = "thumbv6m-none-eabi"
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml
new file mode 100644
index 000000000..580ced22e
--- /dev/null
+++ b/examples/boot/bootloader/rp/Cargo.toml
@@ -0,0 +1,29 @@
1[package]
2edition = "2021"
3name = "rp-bootloader-example"
4version = "0.1.0"
5description = "Example bootloader for RP2040 chips"
6license = "MIT OR Apache-2.0"
7
8[dependencies]
9defmt = { version = "0.3", optional = true }
10defmt-rtt = { version = "0.4", optional = true }
11
12embassy-rp = { path = "../../../../embassy-rp", default-features = false, features = ["nightly"] }
13embassy-boot-rp = { path = "../../../../embassy-boot/rp", default-features = false }
14cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
15cortex-m-rt = { version = "0.7" }
16embedded-storage = "0.3.0"
17embedded-storage-async = "0.3.0"
18cfg-if = "1.0.0"
19
20[features]
21defmt = [
22 "dep:defmt",
23 "embassy-boot-rp/defmt",
24 "embassy-rp/defmt",
25]
26debug = ["defmt-rtt", "defmt"]
27
28[profile.release]
29debug = true
diff --git a/examples/boot/bootloader/rp/README.md b/examples/boot/bootloader/rp/README.md
new file mode 100644
index 000000000..064e87273
--- /dev/null
+++ b/examples/boot/bootloader/rp/README.md
@@ -0,0 +1,17 @@
1# Bootloader for RP2040
2
3The bootloader uses `embassy-boot` to interact with the flash.
4
5# Usage
6
7Flashing the bootloader
8
9```
10cargo flash --release --chip RP2040
11```
12
13To debug, use `cargo run` and enable the debug feature flag
14
15``` rust
16cargo run --release --features debug
17```
diff --git a/examples/boot/bootloader/rp/build.rs b/examples/boot/bootloader/rp/build.rs
new file mode 100644
index 000000000..c201704ad
--- /dev/null
+++ b/examples/boot/bootloader/rp/build.rs
@@ -0,0 +1,28 @@
1use std::env;
2use std::fs::File;
3use std::io::Write;
4use std::path::PathBuf;
5
6fn main() {
7 // Put `memory.x` in our output directory and ensure it's
8 // on the linker search path.
9 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
10 File::create(out.join("memory.x"))
11 .unwrap()
12 .write_all(include_bytes!("memory.x"))
13 .unwrap();
14 println!("cargo:rustc-link-search={}", out.display());
15
16 // By default, Cargo will re-run a build script whenever
17 // any file in the project changes. By specifying `memory.x`
18 // here, we ensure the build script is only re-run when
19 // `memory.x` is changed.
20 println!("cargo:rerun-if-changed=memory.x");
21
22 println!("cargo:rustc-link-arg-bins=--nmagic");
23 println!("cargo:rustc-link-arg-bins=-Tlink.x");
24 println!("cargo:rustc-link-arg-bins=-Tlink-rp.x");
25 if env::var("CARGO_FEATURE_DEFMT").is_ok() {
26 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
27 }
28}
diff --git a/examples/boot/bootloader/rp/memory.x b/examples/boot/bootloader/rp/memory.x
new file mode 100644
index 000000000..d6ef38469
--- /dev/null
+++ b/examples/boot/bootloader/rp/memory.x
@@ -0,0 +1,19 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
5 FLASH : ORIGIN = 0x10000100, LENGTH = 24K
6 BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4K
7 ACTIVE : ORIGIN = 0x10007000, LENGTH = 512K
8 DFU : ORIGIN = 0x10087000, LENGTH = 516K
9 RAM : ORIGIN = 0x20000000, LENGTH = 256K
10}
11
12__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOT2);
13__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(BOOT2);
14
15__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(BOOT2);
16__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(BOOT2);
17
18__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOT2);
19__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOT2);
diff --git a/examples/boot/bootloader/rp/src/main.rs b/examples/boot/bootloader/rp/src/main.rs
new file mode 100644
index 000000000..5028ec688
--- /dev/null
+++ b/examples/boot/bootloader/rp/src/main.rs
@@ -0,0 +1,51 @@
1#![no_std]
2#![no_main]
3
4use cortex_m_rt::{entry, exception};
5#[cfg(feature = "defmt")]
6use defmt_rtt as _;
7use embassy_boot_rp::*;
8use embassy_rp::flash::{Flash, ERASE_SIZE};
9use embassy_rp::peripherals::FLASH;
10
11const FLASH_SIZE: usize = 2 * 1024 * 1024;
12
13#[entry]
14fn main() -> ! {
15 let p = embassy_rp::init(Default::default());
16
17 // Uncomment this if you are debugging the bootloader with debugger/RTT attached,
18 // as it prevents a hard fault when accessing flash 'too early' after boot.
19 /*
20 for i in 0..10000000 {
21 cortex_m::asm::nop();
22 }
23 */
24
25 let mut bl: BootLoader = BootLoader::default();
26 let flash: Flash<'_, FLASH, FLASH_SIZE> = Flash::new(p.FLASH);
27 let mut flash = BootFlash::<_, ERASE_SIZE>::new(flash);
28 let start = bl.prepare(&mut SingleFlashConfig::new(&mut flash));
29 core::mem::drop(flash);
30
31 unsafe { bl.load(start) }
32}
33
34#[no_mangle]
35#[cfg_attr(target_os = "none", link_section = ".HardFault.user")]
36unsafe extern "C" fn HardFault() {
37 cortex_m::peripheral::SCB::sys_reset();
38}
39
40#[exception]
41unsafe fn DefaultHandler(_: i16) -> ! {
42 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
43 let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16;
44
45 panic!("DefaultHandler #{:?}", irqn);
46}
47
48#[panic_handler]
49fn panic(_info: &core::panic::PanicInfo) -> ! {
50 cortex_m::asm::udf();
51}
diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml
index 4ddd1c99c..be659e02a 100644
--- a/examples/boot/bootloader/stm32/Cargo.toml
+++ b/examples/boot/bootloader/stm32/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7 7
8[dependencies] 8[dependencies]
9defmt = { version = "0.3", optional = true } 9defmt = { version = "0.3", optional = true }
10defmt-rtt = { version = "0.3", optional = true } 10defmt-rtt = { version = "0.4", optional = true }
11 11
12embassy-stm32 = { path = "../../../../embassy-stm32", default-features = false, features = ["nightly"] } 12embassy-stm32 = { path = "../../../../embassy-stm32", default-features = false, features = ["nightly"] }
13embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32", default-features = false } 13embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32", default-features = false }
diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml
index c633f82f5..8b95ac3a6 100644
--- a/examples/nrf/Cargo.toml
+++ b/examples/nrf/Cargo.toml
@@ -17,14 +17,14 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de
17embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } 17embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
18embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true } 18embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true }
19embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } 19embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true }
20embedded-io = "0.3.1" 20embedded-io = "0.4.0"
21embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true } 21embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true }
22 22
23lorawan-device = { version = "0.8.0", default-features = false, features = ["async"], optional = true } 23lorawan-device = { version = "0.8.0", default-features = false, features = ["async"], optional = true }
24lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"], optional = true } 24lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"], optional = true }
25 25
26defmt = "0.3" 26defmt = "0.3"
27defmt-rtt = "0.3" 27defmt-rtt = "0.4"
28 28
29static_cell = "1.0" 29static_cell = "1.0"
30cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 30cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
@@ -34,4 +34,4 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
34rand = { version = "0.8.4", default-features = false } 34rand = { version = "0.8.4", default-features = false }
35embedded-storage = "0.3.0" 35embedded-storage = "0.3.0"
36usbd-hid = "0.6.0" 36usbd-hid = "0.6.0"
37serde = { version = "1.0.136", default-features = false } 37serde = { version = "1.0.136", default-features = false } \ No newline at end of file
diff --git a/examples/nrf/src/bin/i2s_effect.rs b/examples/nrf/src/bin/i2s_effect.rs
new file mode 100644
index 000000000..3cca005b1
--- /dev/null
+++ b/examples/nrf/src/bin/i2s_effect.rs
@@ -0,0 +1,117 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::f32::consts::PI;
6
7use defmt::{error, info};
8use embassy_executor::Spawner;
9use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S};
10use embassy_nrf::interrupt;
11use {defmt_rtt as _, panic_probe as _};
12
13type Sample = i16;
14
15const NUM_BUFFERS: usize = 2;
16const NUM_SAMPLES: usize = 4;
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) {
20 let p = embassy_nrf::init(Default::default());
21
22 let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
23
24 let sample_rate = master_clock.sample_rate();
25 info!("Sample rate: {}", sample_rate);
26
27 let config = Config::default()
28 .sample_width(SampleWidth::_16bit)
29 .channels(Channels::MonoLeft);
30
31 let irq = interrupt::take!(I2S);
32 let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
33 let buffers_in = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
34 let mut full_duplex_stream = I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).full_duplex(
35 p.P0_29,
36 p.P0_28,
37 buffers_out,
38 buffers_in,
39 );
40
41 let mut modulator = SineOsc::new();
42 modulator.set_frequency(8.0, 1.0 / sample_rate as f32);
43 modulator.set_amplitude(1.0);
44
45 full_duplex_stream.start().await.expect("I2S Start");
46
47 loop {
48 let (buff_out, buff_in) = full_duplex_stream.buffers();
49 for i in 0..NUM_SAMPLES {
50 let modulation = (Sample::SCALE as f32 * bipolar_to_unipolar(modulator.generate())) as Sample;
51 buff_out[i] = buff_in[i] * modulation;
52 }
53
54 if let Err(err) = full_duplex_stream.send_and_receive().await {
55 error!("{}", err);
56 }
57 }
58}
59
60struct SineOsc {
61 amplitude: f32,
62 modulo: f32,
63 phase_inc: f32,
64}
65
66impl SineOsc {
67 const B: f32 = 4.0 / PI;
68 const C: f32 = -4.0 / (PI * PI);
69 const P: f32 = 0.225;
70
71 pub fn new() -> Self {
72 Self {
73 amplitude: 1.0,
74 modulo: 0.0,
75 phase_inc: 0.0,
76 }
77 }
78
79 pub fn set_frequency(&mut self, freq: f32, inv_sample_rate: f32) {
80 self.phase_inc = freq * inv_sample_rate;
81 }
82
83 pub fn set_amplitude(&mut self, amplitude: f32) {
84 self.amplitude = amplitude;
85 }
86
87 pub fn generate(&mut self) -> f32 {
88 let signal = self.parabolic_sin(self.modulo);
89 self.modulo += self.phase_inc;
90 if self.modulo < 0.0 {
91 self.modulo += 1.0;
92 } else if self.modulo > 1.0 {
93 self.modulo -= 1.0;
94 }
95 signal * self.amplitude
96 }
97
98 fn parabolic_sin(&mut self, modulo: f32) -> f32 {
99 let angle = PI - modulo * 2.0 * PI;
100 let y = Self::B * angle + Self::C * angle * abs(angle);
101 Self::P * (y * abs(y) - y) + y
102 }
103}
104
105#[inline]
106fn abs(value: f32) -> f32 {
107 if value < 0.0 {
108 -value
109 } else {
110 value
111 }
112}
113
114#[inline]
115fn bipolar_to_unipolar(value: f32) -> f32 {
116 (value + 1.0) / 2.0
117}
diff --git a/examples/nrf/src/bin/i2s_monitor.rs b/examples/nrf/src/bin/i2s_monitor.rs
new file mode 100644
index 000000000..48eb7d581
--- /dev/null
+++ b/examples/nrf/src/bin/i2s_monitor.rs
@@ -0,0 +1,115 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{debug, error, info};
6use embassy_executor::Spawner;
7use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
8use embassy_nrf::interrupt;
9use embassy_nrf::pwm::{Prescaler, SimplePwm};
10use {defmt_rtt as _, panic_probe as _};
11
12type Sample = i16;
13
14const NUM_SAMPLES: usize = 500;
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let p = embassy_nrf::init(Default::default());
19
20 let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
21
22 let sample_rate = master_clock.sample_rate();
23 info!("Sample rate: {}", sample_rate);
24
25 let config = Config::default()
26 .sample_width(SampleWidth::_16bit)
27 .channels(Channels::MonoLeft);
28
29 let irq = interrupt::take!(I2S);
30 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
31 let mut input_stream =
32 I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers);
33
34 // Configure the PWM to use the pins corresponding to the RGB leds
35 let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24);
36 pwm.set_prescaler(Prescaler::Div1);
37 pwm.set_max_duty(255);
38
39 let mut rms_online = RmsOnline::<NUM_SAMPLES>::default();
40
41 input_stream.start().await.expect("I2S Start");
42
43 loop {
44 let rms = rms_online.process(input_stream.buffer());
45 let rgb = rgb_from_rms(rms);
46
47 debug!("RMS: {}, RGB: {:?}", rms, rgb);
48 for i in 0..3 {
49 pwm.set_duty(i, rgb[i].into());
50 }
51
52 if let Err(err) = input_stream.receive().await {
53 error!("{}", err);
54 }
55 }
56}
57
58/// RMS from 0.0 until 0.75 will give green with a proportional intensity
59/// RMS from 0.75 until 0.9 will give a blend between orange and red proportionally to the intensity
60/// RMS above 0.9 will give a red with a proportional intensity
61fn rgb_from_rms(rms: f32) -> [u8; 3] {
62 if rms < 0.75 {
63 let intensity = rms / 0.75;
64 [0, (intensity * 165.0) as u8, 0]
65 } else if rms < 0.9 {
66 let intensity = (rms - 0.75) / 0.15;
67 [200, 165 - (165.0 * intensity) as u8, 0]
68 } else {
69 let intensity = (rms - 0.9) / 0.1;
70 [200 + (55.0 * intensity) as u8, 0, 0]
71 }
72}
73
74pub struct RmsOnline<const N: usize> {
75 pub squares: [f32; N],
76 pub head: usize,
77}
78
79impl<const N: usize> Default for RmsOnline<N> {
80 fn default() -> Self {
81 RmsOnline {
82 squares: [0.0; N],
83 head: 0,
84 }
85 }
86}
87
88impl<const N: usize> RmsOnline<N> {
89 pub fn reset(&mut self) {
90 self.squares = [0.0; N];
91 self.head = 0;
92 }
93
94 pub fn process(&mut self, buf: &[Sample]) -> f32 {
95 buf.iter()
96 .for_each(|sample| self.push(*sample as f32 / Sample::SCALE as f32));
97
98 let sum_of_squares = self.squares.iter().fold(0.0, |acc, v| acc + *v);
99 Self::approx_sqrt(sum_of_squares / N as f32)
100 }
101
102 pub fn push(&mut self, signal: f32) {
103 let square = signal * signal;
104 self.squares[self.head] = square;
105 self.head = (self.head + 1) % N;
106 }
107
108 /// Approximated sqrt taken from [micromath]
109 ///
110 /// [micromath]: https://docs.rs/micromath/latest/src/micromath/float/sqrt.rs.html#11-17
111 ///
112 fn approx_sqrt(value: f32) -> f32 {
113 f32::from_bits((value.to_bits() + 0x3f80_0000) >> 1)
114 }
115}
diff --git a/examples/nrf/src/bin/i2s_waveform.rs b/examples/nrf/src/bin/i2s_waveform.rs
new file mode 100644
index 000000000..1b0e8ebc8
--- /dev/null
+++ b/examples/nrf/src/bin/i2s_waveform.rs
@@ -0,0 +1,151 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::f32::consts::PI;
6
7use defmt::{error, info};
8use embassy_executor::Spawner;
9use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
10use embassy_nrf::interrupt;
11use {defmt_rtt as _, panic_probe as _};
12
13type Sample = i16;
14
15const NUM_SAMPLES: usize = 50;
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_nrf::init(Default::default());
20
21 let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
22
23 let sample_rate = master_clock.sample_rate();
24 info!("Sample rate: {}", sample_rate);
25
26 let config = Config::default()
27 .sample_width(SampleWidth::_16bit)
28 .channels(Channels::MonoLeft);
29
30 let irq = interrupt::take!(I2S);
31 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
32 let mut output_stream =
33 I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers);
34
35 let mut waveform = Waveform::new(1.0 / sample_rate as f32);
36
37 waveform.process(output_stream.buffer());
38
39 output_stream.start().await.expect("I2S Start");
40
41 loop {
42 waveform.process(output_stream.buffer());
43
44 if let Err(err) = output_stream.send().await {
45 error!("{}", err);
46 }
47 }
48}
49
50struct Waveform {
51 inv_sample_rate: f32,
52 carrier: SineOsc,
53 freq_mod: SineOsc,
54 amp_mod: SineOsc,
55}
56
57impl Waveform {
58 fn new(inv_sample_rate: f32) -> Self {
59 let mut carrier = SineOsc::new();
60 carrier.set_frequency(110.0, inv_sample_rate);
61
62 let mut freq_mod = SineOsc::new();
63 freq_mod.set_frequency(1.0, inv_sample_rate);
64 freq_mod.set_amplitude(1.0);
65
66 let mut amp_mod = SineOsc::new();
67 amp_mod.set_frequency(16.0, inv_sample_rate);
68 amp_mod.set_amplitude(0.5);
69
70 Self {
71 inv_sample_rate,
72 carrier,
73 freq_mod,
74 amp_mod,
75 }
76 }
77
78 fn process(&mut self, buf: &mut [Sample]) {
79 for sample in buf.chunks_mut(1) {
80 let freq_modulation = bipolar_to_unipolar(self.freq_mod.generate());
81 self.carrier
82 .set_frequency(110.0 + 440.0 * freq_modulation, self.inv_sample_rate);
83
84 let amp_modulation = bipolar_to_unipolar(self.amp_mod.generate());
85 self.carrier.set_amplitude(amp_modulation);
86
87 let signal = self.carrier.generate();
88
89 sample[0] = (Sample::SCALE as f32 * signal) as Sample;
90 }
91 }
92}
93
94struct SineOsc {
95 amplitude: f32,
96 modulo: f32,
97 phase_inc: f32,
98}
99
100impl SineOsc {
101 const B: f32 = 4.0 / PI;
102 const C: f32 = -4.0 / (PI * PI);
103 const P: f32 = 0.225;
104
105 pub fn new() -> Self {
106 Self {
107 amplitude: 1.0,
108 modulo: 0.0,
109 phase_inc: 0.0,
110 }
111 }
112
113 pub fn set_frequency(&mut self, freq: f32, inv_sample_rate: f32) {
114 self.phase_inc = freq * inv_sample_rate;
115 }
116
117 pub fn set_amplitude(&mut self, amplitude: f32) {
118 self.amplitude = amplitude;
119 }
120
121 pub fn generate(&mut self) -> f32 {
122 let signal = self.parabolic_sin(self.modulo);
123 self.modulo += self.phase_inc;
124 if self.modulo < 0.0 {
125 self.modulo += 1.0;
126 } else if self.modulo > 1.0 {
127 self.modulo -= 1.0;
128 }
129 signal * self.amplitude
130 }
131
132 fn parabolic_sin(&mut self, modulo: f32) -> f32 {
133 let angle = PI - modulo * 2.0 * PI;
134 let y = Self::B * angle + Self::C * angle * abs(angle);
135 Self::P * (y * abs(y) - y) + y
136 }
137}
138
139#[inline]
140fn abs(value: f32) -> f32 {
141 if value < 0.0 {
142 -value
143 } else {
144 value
145 }
146}
147
148#[inline]
149fn bipolar_to_unipolar(value: f32) -> f32 {
150 (value + 1.0) / 2.0
151}
diff --git a/examples/nrf/src/bin/spis.rs b/examples/nrf/src/bin/spis.rs
new file mode 100644
index 000000000..fe3b0c53d
--- /dev/null
+++ b/examples/nrf/src/bin/spis.rs
@@ -0,0 +1,27 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::spis::{Config, Spis};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default());
14 info!("Running!");
15
16 let irq = interrupt::take!(SPIM2_SPIS2_SPI2);
17 let mut spis = Spis::new(p.SPI2, irq, p.P0_31, p.P0_29, p.P0_28, p.P0_30, Config::default());
18
19 loop {
20 let mut rx_buf = [0_u8; 64];
21 let tx_buf = [1_u8, 2, 3, 4, 5, 6, 7, 8];
22 if let Ok((n_rx, n_tx)) = spis.transfer(&mut rx_buf, &tx_buf).await {
23 info!("RX: {:?}", rx_buf[..n_rx]);
24 info!("TX: {:?}", tx_buf[..n_tx]);
25 }
26 }
27}
diff --git a/examples/nrf/src/bin/twis.rs b/examples/nrf/src/bin/twis.rs
new file mode 100644
index 000000000..54cba9494
--- /dev/null
+++ b/examples/nrf/src/bin/twis.rs
@@ -0,0 +1,46 @@
1//! TWIS example
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_nrf::interrupt;
10use embassy_nrf::twis::{self, Command, Twis};
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_nrf::init(Default::default());
16
17 let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
18 let mut config = twis::Config::default();
19 // Set i2c address
20 config.address0 = 0x55;
21 let mut i2c = Twis::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
22
23 info!("Listening...");
24 loop {
25 let response = [1, 2, 3, 4, 5, 6, 7, 8];
26 // This buffer is used if the i2c master performs a Write or WriteRead
27 let mut buf = [0u8; 16];
28 match i2c.listen(&mut buf).await {
29 Ok(Command::Read) => {
30 info!("Got READ command. Respond with data:\n{:?}\n", response);
31 if let Err(e) = i2c.respond_to_read(&response).await {
32 error!("{:?}", e);
33 }
34 }
35 Ok(Command::Write(n)) => info!("Got WRITE command with data:\n{:?}\n", buf[..n]),
36 Ok(Command::WriteRead(n)) => {
37 info!("Got WRITE/READ command with data:\n{:?}", buf[..n]);
38 info!("Respond with data:\n{:?}\n", response);
39 if let Err(e) = i2c.respond_to_read(&response).await {
40 error!("{:?}", e);
41 }
42 }
43 Err(e) => error!("{:?}", e),
44 }
45 }
46}
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 31f688305..60a8ba94d 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -13,9 +13,10 @@ embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt"
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } 14embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
16embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" }
16 17
17defmt = "0.3" 18defmt = "0.3"
18defmt-rtt = "0.3" 19defmt-rtt = "0.4"
19 20
20cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 21cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
21cortex-m-rt = "0.7.0" 22cortex-m-rt = "0.7.0"
@@ -28,10 +29,11 @@ display-interface = "0.4.1"
28byte-slice-cast = { version = "1.2.0", default-features = false } 29byte-slice-cast = { version = "1.2.0", default-features = false }
29 30
30embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } 31embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
31embedded-hal-async = { version = "0.1.0-alpha.3" } 32embedded-hal-async = "0.2.0-alpha.0"
32embedded-io = { version = "0.3.1", features = ["async", "defmt"] } 33embedded-io = { version = "0.4.0", features = ["async", "defmt"] }
33embedded-storage = { version = "0.3" } 34embedded-storage = { version = "0.3" }
34static_cell = "1.0.0" 35static_cell = "1.0.0"
36log = "0.4"
35 37
36[profile.release] 38[profile.release]
37debug = true 39debug = true
diff --git a/examples/rp/src/bin/adc.rs b/examples/rp/src/bin/adc.rs
new file mode 100644
index 000000000..2a9e93732
--- /dev/null
+++ b/examples/rp/src/bin/adc.rs
@@ -0,0 +1,33 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_rp::adc::{Adc, Config};
8use embassy_rp::interrupt;
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let p = embassy_rp::init(Default::default());
15 let irq = interrupt::take!(ADC_IRQ_FIFO);
16 let mut adc = Adc::new(p.ADC, irq, Config::default());
17
18 let mut p26 = p.PIN_26;
19 let mut p27 = p.PIN_27;
20 let mut p28 = p.PIN_28;
21
22 loop {
23 let level = adc.read(&mut p26).await;
24 info!("Pin 26 ADC: {}", level);
25 let level = adc.read(&mut p27).await;
26 info!("Pin 27 ADC: {}", level);
27 let level = adc.read(&mut p28).await;
28 info!("Pin 28 ADC: {}", level);
29 let temp = adc.read_temperature().await;
30 info!("Temp: {}", temp);
31 Timer::after(Duration::from_secs(1)).await;
32 }
33}
diff --git a/examples/rp/src/bin/usb_logger.rs b/examples/rp/src/bin/usb_logger.rs
new file mode 100644
index 000000000..52417a02e
--- /dev/null
+++ b/examples/rp/src/bin/usb_logger.rs
@@ -0,0 +1,30 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use embassy_executor::Spawner;
6use embassy_rp::interrupt;
7use embassy_rp::peripherals::USB;
8use embassy_rp::usb::Driver;
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::task]
13async fn logger_task(driver: Driver<'static, USB>) {
14 embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver);
15}
16
17#[embassy_executor::main]
18async fn main(spawner: Spawner) {
19 let p = embassy_rp::init(Default::default());
20 let irq = interrupt::take!(USBCTRL_IRQ);
21 let driver = Driver::new(p.USB, irq);
22 spawner.spawn(logger_task(driver)).unwrap();
23
24 let mut counter = 0;
25 loop {
26 counter += 1;
27 log::info!("Tick {}", counter);
28 Timer::after(Duration::from_secs(1)).await;
29 }
30}
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml
index 790258382..41680f8f4 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["lo
9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "std", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "std", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] }
11embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dhcpv4", "pool-16"] } 11embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dhcpv4", "pool-16"] }
12embedded-io = { version = "0.3.1", features = ["async", "std", "futures"] } 12embedded-io = { version = "0.4.0", features = ["async", "std", "futures"] }
13critical-section = { version = "1.1", features = ["std"] } 13critical-section = { version = "1.1", features = ["std"] }
14 14
15async-io = "1.6.0" 15async-io = "1.6.0"
diff --git a/examples/stm32f0/.cargo/config.toml b/examples/stm32f0/.cargo/config.toml
index d1b1cd0bf..16abc29bc 100644
--- a/examples/stm32f0/.cargo/config.toml
+++ b/examples/stm32f0/.cargo/config.toml
@@ -1,5 +1,5 @@
1[target.thumbv6m-none-eabi] 1[target.thumbv6m-none-eabi]
2runner = 'probe-run --chip STM32F030F4Px' 2runner = 'probe-run --chip STM32F091RCTX'
3 3
4[build] 4[build]
5target = "thumbv6m-none-eabi" 5target = "thumbv6m-none-eabi"
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml
index a56c546ee..c10af1713 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -10,10 +10,10 @@ license = "MIT OR Apache-2.0"
10cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 10cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
11cortex-m-rt = "0.7.0" 11cortex-m-rt = "0.7.0"
12defmt = "0.3" 12defmt = "0.3"
13defmt-rtt = "0.3" 13defmt-rtt = "0.4"
14panic-probe = "0.3" 14panic-probe = "0.3"
15embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 15embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
16embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 16embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
17embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 17embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
18embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f030f4", "time-driver-any"] } 18embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any"] }
19 19
diff --git a/examples/stm32f0/src/bin/blinky.rs b/examples/stm32f0/src/bin/blinky.rs
new file mode 100644
index 000000000..9f923399c
--- /dev/null
+++ b/examples/stm32f0/src/bin/blinky.rs
@@ -0,0 +1,28 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_time::{Duration, Timer};
9use {defmt_rtt as _, panic_probe as _};
10
11// main is itself an async function.
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let p = embassy_stm32::init(Default::default());
15 info!("Hello World!");
16 //PA5 is the onboard LED on the Nucleo F091RC
17 let mut led = Output::new(p.PA5, Level::High, Speed::Low);
18
19 loop {
20 info!("high");
21 led.set_high();
22 Timer::after(Duration::from_millis(300)).await;
23
24 info!("low");
25 led.set_low();
26 Timer::after(Duration::from_millis(300)).await;
27 }
28}
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index 6be131f30..53f369b3a 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -13,7 +13,7 @@ embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defm
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14 14
15defmt = "0.3" 15defmt = "0.3"
16defmt-rtt = "0.3" 16defmt-rtt = "0.4"
17 17
18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
19cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml
index f6adda2a3..afaf9a0c9 100644
--- a/examples/stm32f2/Cargo.toml
+++ b/examples/stm32f2/Cargo.toml
@@ -11,7 +11,7 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
12 12
13defmt = "0.3" 13defmt = "0.3"
14defmt-rtt = "0.3" 14defmt-rtt = "0.4"
15 15
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0" 17cortex-m-rt = "0.7.0"
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml
index 27188dd19..69ebef786 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -13,7 +13,7 @@ embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defm
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14 14
15defmt = "0.3" 15defmt = "0.3"
16defmt-rtt = "0.3" 16defmt-rtt = "0.4"
17 17
18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
19cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index b05457eaa..62d3f08df 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -12,12 +12,12 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de
12embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 12embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
15defmt-rtt = "0.3" 15defmt-rtt = "0.4"
16 16
17cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 17cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
18cortex-m-rt = "0.7.0" 18cortex-m-rt = "0.7.0"
19embedded-hal = "0.2.6" 19embedded-hal = "0.2.6"
20embedded-io = "0.3.1" 20embedded-io = "0.4.0"
21panic-probe = { version = "0.3", features = ["print-defmt"] } 21panic-probe = { version = "0.3", features = ["print-defmt"] }
22futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 22futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
23heapless = { version = "0.7.5", default-features = false } 23heapless = { version = "0.7.5", default-features = false }
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index b14afd2fe..f4d674cdc 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -10,10 +10,10 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "net", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "net", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] }
12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } 12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
13embedded-io = { version = "0.3.1", features = ["async"] } 13embedded-io = { version = "0.4.0", features = ["async"] }
14 14
15defmt = "0.3" 15defmt = "0.3"
16defmt-rtt = "0.3" 16defmt-rtt = "0.4"
17 17
18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
19cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml
index f5673718d..e7273c9fc 100644
--- a/examples/stm32g0/Cargo.toml
+++ b/examples/stm32g0/Cargo.toml
@@ -11,7 +11,7 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] }
12 12
13defmt = "0.3" 13defmt = "0.3"
14defmt-rtt = "0.3" 14defmt-rtt = "0.4"
15 15
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0" 17cortex-m-rt = "0.7.0"
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index ecda28805..8a57a8ef0 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -12,7 +12,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["
12embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } 12embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" }
13 13
14defmt = "0.3" 14defmt = "0.3"
15defmt-rtt = "0.3" 15defmt-rtt = "0.4"
16 16
17cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 17cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
18cortex-m-rt = "0.7.0" 18cortex-m-rt = "0.7.0"
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index 0dccff6e8..11ce35053 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -10,17 +10,17 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16", "unstable-traits"] } 12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16", "unstable-traits"] }
13embedded-io = { version = "0.3.1", features = ["async"] } 13embedded-io = { version = "0.4.0", features = ["async"] }
14 14
15defmt = "0.3" 15defmt = "0.3"
16defmt-rtt = "0.3" 16defmt-rtt = "0.4"
17 17
18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
19cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
20embedded-hal = "0.2.6" 20embedded-hal = "0.2.6"
21embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } 21embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
22embedded-hal-async = { version = "=0.1.0-alpha.3" } 22embedded-hal-async = { version = "=0.2.0-alpha.0" }
23embedded-nal-async = "0.2.0" 23embedded-nal-async = "0.3.0"
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/stm32h7/src/bin/wdg.rs b/examples/stm32h7/src/bin/wdg.rs
new file mode 100644
index 000000000..2b0301aad
--- /dev/null
+++ b/examples/stm32h7/src/bin/wdg.rs
@@ -0,0 +1,24 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::wdg::IndependentWatchdog;
8use embassy_time::{Duration, Timer};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default());
14 info!("Hello World!");
15
16 let mut wdg = IndependentWatchdog::new(p.IWDG1, 20_000_000);
17
18 unsafe { wdg.unleash() };
19
20 loop {
21 Timer::after(Duration::from_secs(1)).await;
22 unsafe { wdg.pet() };
23 }
24}
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index 8b00773be..86933a629 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -19,10 +19,10 @@ lorawan-device = { version = "0.8.0", default-features = false, features = ["asy
19lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"], optional = true } 19lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"], optional = true }
20 20
21defmt = "0.3" 21defmt = "0.3"
22defmt-rtt = "0.3" 22defmt-rtt = "0.4"
23 23
24embedded-storage = "0.3.0" 24embedded-storage = "0.3.0"
25embedded-io = "0.3.1" 25embedded-io = "0.4.0"
26 26
27cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 27cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
28cortex-m-rt = "0.7.0" 28cortex-m-rt = "0.7.0"
diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml
index 9460febf5..6e3b2103c 100644
--- a/examples/stm32l1/Cargo.toml
+++ b/examples/stm32l1/Cargo.toml
@@ -11,7 +11,7 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] }
12 12
13defmt = "0.3" 13defmt = "0.3"
14defmt-rtt = "0.3" 14defmt-rtt = "0.4"
15 15
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0" 17cortex-m-rt = "0.7.0"
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index 83d456b26..45d3dd366 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -14,13 +14,13 @@ embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal"
14embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits"] } 14embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits"] }
15 15
16defmt = "0.3" 16defmt = "0.3"
17defmt-rtt = "0.3" 17defmt-rtt = "0.4"
18 18
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.9" } 22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
23embedded-hal-async = { version = "=0.1.0-alpha.3" } 23embedded-hal-async = { version = "=0.2.0-alpha.0" }
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/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index 848723f8b..73ad50787 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -17,7 +17,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
17usbd-hid = "0.6.0" 17usbd-hid = "0.6.0"
18 18
19defmt = "0.3" 19defmt = "0.3"
20defmt-rtt = "0.3" 20defmt-rtt = "0.4"
21panic-probe = { version = "0.3", features = ["print-defmt"] } 21panic-probe = { version = "0.3", features = ["print-defmt"] }
22 22
23cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 23cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
@@ -26,5 +26,5 @@ embedded-hal = "0.2.6"
26futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 26futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
27heapless = { version = "0.7.5", default-features = false } 27heapless = { version = "0.7.5", default-features = false }
28rand_core = { version = "0.6.3", default-features = false } 28rand_core = { version = "0.6.3", default-features = false }
29embedded-io = { version = "0.3.1", features = ["async"] } 29embedded-io = { version = "0.4.0", features = ["async"] }
30static_cell = "1.0" 30static_cell = "1.0"
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml
index 3d704011b..d88fdda50 100644
--- a/examples/stm32u5/Cargo.toml
+++ b/examples/stm32u5/Cargo.toml
@@ -11,7 +11,7 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] }
12 12
13defmt = "0.3" 13defmt = "0.3"
14defmt-rtt = "0.3" 14defmt-rtt = "0.4"
15 15
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0" 17cortex-m-rt = "0.7.0"
@@ -21,8 +21,3 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
21heapless = { version = "0.7.5", default-features = false } 21heapless = { version = "0.7.5", default-features = false }
22 22
23micromath = "2.0.0" 23micromath = "2.0.0"
24
25#[patch.crates-io]
26#defmt = { git="https://github.com/knurling-rs/defmt.git" }
27#defmt-rtt = { git="https://github.com/knurling-rs/defmt.git" }
28
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index 5b96fa191..e27b4527c 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -11,7 +11,7 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55cc", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55cc", "time-driver-any", "exti"] }
12 12
13defmt = "0.3" 13defmt = "0.3"
14defmt-rtt = "0.3" 14defmt-rtt = "0.4"
15 15
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0" 17cortex-m-rt = "0.7.0"
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml
index c827d2b71..690481bbf 100644
--- a/examples/stm32wl/Cargo.toml
+++ b/examples/stm32wl/Cargo.toml
@@ -15,7 +15,7 @@ lorawan-device = { version = "0.8.0", default-features = false, features = ["asy
15lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"] } 15lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"] }
16 16
17defmt = "0.3" 17defmt = "0.3"
18defmt-rtt = "0.3" 18defmt-rtt = "0.4"
19 19
20cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 20cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
21cortex-m-rt = "0.7.0" 21cortex-m-rt = "0.7.0"
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index c05aac3fc..55539405f 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-2022-10-25" 4channel = "nightly-2022-11-22"
5components = [ "rust-src", "rustfmt" ] 5components = [ "rust-src", "rustfmt" ]
6targets = [ 6targets = [
7 "thumbv7em-none-eabi", 7 "thumbv7em-none-eabi",
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index 069b7fb8c..a07b479e4 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -12,16 +12,16 @@ embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightl
12embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 12embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
13 13
14defmt = "0.3.0" 14defmt = "0.3.0"
15defmt-rtt = "0.3.0" 15defmt-rtt = "0.4"
16 16
17cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 17cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
18cortex-m-rt = "0.7.0" 18cortex-m-rt = "0.7.0"
19embedded-hal = "0.2.6" 19embedded-hal = "0.2.6"
20embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } 20embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
21embedded-hal-async = { version = "=0.1.0-alpha.3" } 21embedded-hal-async = { version = "=0.2.0-alpha.0" }
22panic-probe = { version = "0.3.0", features = ["print-defmt"] } 22panic-probe = { version = "0.3.0", features = ["print-defmt"] }
23futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 23futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
24embedded-io = { version = "0.3.1", features = ["async"] } 24embedded-io = { version = "0.4.0", features = ["async"] }
25embedded-storage = { version = "0.3" } 25embedded-storage = { version = "0.3" }
26 26
27[profile.dev] 27[profile.dev]
diff --git a/tests/rp/src/bin/gpio.rs b/tests/rp/src/bin/gpio.rs
index af22fe27d..80e92d0fd 100644
--- a/tests/rp/src/bin/gpio.rs
+++ b/tests/rp/src/bin/gpio.rs
@@ -78,6 +78,7 @@ async fn main(_spawner: Spawner) {
78 a.set_as_input(); 78 a.set_as_input();
79 79
80 // When an OutputOpenDrain is high, it doesn't drive the pin. 80 // When an OutputOpenDrain is high, it doesn't drive the pin.
81 b.set_high();
81 a.set_pull(Pull::Up); 82 a.set_pull(Pull::Up);
82 delay(); 83 delay();
83 assert!(a.is_high()); 84 assert!(a.is_high());
@@ -85,9 +86,8 @@ async fn main(_spawner: Spawner) {
85 delay(); 86 delay();
86 assert!(a.is_low()); 87 assert!(a.is_low());
87 88
88 b.set_low();
89
90 // When an OutputOpenDrain is low, it drives the pin low. 89 // When an OutputOpenDrain is low, it drives the pin low.
90 b.set_low();
91 a.set_pull(Pull::Up); 91 a.set_pull(Pull::Up);
92 delay(); 92 delay();
93 assert!(a.is_low()); 93 assert!(a.is_low());
@@ -95,14 +95,36 @@ async fn main(_spawner: Spawner) {
95 delay(); 95 delay();
96 assert!(a.is_low()); 96 assert!(a.is_low());
97 97
98 // Check high again
98 b.set_high(); 99 b.set_high();
99
100 a.set_pull(Pull::Up); 100 a.set_pull(Pull::Up);
101 delay(); 101 delay();
102 assert!(a.is_high()); 102 assert!(a.is_high());
103 a.set_pull(Pull::Down); 103 a.set_pull(Pull::Down);
104 delay(); 104 delay();
105 assert!(a.is_low()); 105 assert!(a.is_low());
106
107 // When an OutputOpenDrain is high, it reads the input value in the pin.
108 b.set_high();
109 a.set_as_input();
110 a.set_pull(Pull::Up);
111 delay();
112 assert!(b.is_high());
113 a.set_as_output();
114 a.set_low();
115 delay();
116 assert!(b.is_low());
117
118 // When an OutputOpenDrain is low, it always reads low.
119 b.set_low();
120 a.set_as_input();
121 a.set_pull(Pull::Up);
122 delay();
123 assert!(b.is_low());
124 a.set_as_output();
125 a.set_low();
126 delay();
127 assert!(b.is_low());
106 } 128 }
107 129
108 // FLEX 130 // FLEX
diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs
index 9cc20bb98..bea9283e7 100644
--- a/tests/rp/src/bin/uart_buffered.rs
+++ b/tests/rp/src/bin/uart_buffered.rs
@@ -5,7 +5,7 @@
5use defmt::{assert_eq, *}; 5use defmt::{assert_eq, *};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_rp::interrupt; 7use embassy_rp::interrupt;
8use embassy_rp::uart::{BufferedUart, Config, State, Uart}; 8use embassy_rp::uart::{BufferedUart, Config};
9use embedded_io::asynch::{Read, Write}; 9use embedded_io::asynch::{Read, Write};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
@@ -17,25 +17,22 @@ async fn main(_spawner: Spawner) {
17 let (tx, rx, uart) = (p.PIN_0, p.PIN_1, p.UART0); 17 let (tx, rx, uart) = (p.PIN_0, p.PIN_1, p.UART0);
18 18
19 let config = Config::default(); 19 let config = Config::default();
20 let uart = Uart::new_blocking(uart, tx, rx, config);
21
22 let irq = interrupt::take!(UART0_IRQ); 20 let irq = interrupt::take!(UART0_IRQ);
23 let tx_buf = &mut [0u8; 16]; 21 let tx_buf = &mut [0u8; 16];
24 let rx_buf = &mut [0u8; 16]; 22 let rx_buf = &mut [0u8; 16];
25 let mut state = State::new(); 23 let mut uart = BufferedUart::new(uart, irq, tx, rx, tx_buf, rx_buf, config);
26 let mut uart = BufferedUart::new(&mut state, uart, irq, tx_buf, rx_buf);
27 24
28 // Make sure we send more bytes than fits in the FIFO, to test the actual 25 // Make sure we send more bytes than fits in the FIFO, to test the actual
29 // bufferedUart. 26 // bufferedUart.
30 27
31 let data = [ 28 let data = [
32 1_u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 29 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
33 30, 31, 32, 30 30, 31,
34 ]; 31 ];
35 uart.write_all(&data).await.unwrap(); 32 uart.write_all(&data).await.unwrap();
36 info!("Done writing"); 33 info!("Done writing");
37 34
38 let mut buf = [0; 32]; 35 let mut buf = [0; 31];
39 uart.read_exact(&mut buf).await.unwrap(); 36 uart.read_exact(&mut buf).await.unwrap();
40 assert_eq!(buf, data); 37 assert_eq!(buf, data);
41 38
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 602c1fb57..08a775eae 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -20,13 +20,13 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de
20embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-tim2"] } 20embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-tim2"] }
21 21
22defmt = "0.3.0" 22defmt = "0.3.0"
23defmt-rtt = "0.3.0" 23defmt-rtt = "0.4"
24 24
25cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 25cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
26cortex-m-rt = "0.7.0" 26cortex-m-rt = "0.7.0"
27embedded-hal = "0.2.6" 27embedded-hal = "0.2.6"
28embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } 28embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
29embedded-hal-async = { version = "=0.1.0-alpha.3" } 29embedded-hal-async = { version = "=0.2.0-alpha.0" }
30panic-probe = { version = "0.3.0", features = ["print-defmt"] } 30panic-probe = { version = "0.3.0", features = ["print-defmt"] }
31 31
32[profile.dev] 32[profile.dev]