diff options
| author | Dion Dokter <[email protected]> | 2022-12-09 11:04:55 +0100 |
|---|---|---|
| committer | Dion Dokter <[email protected]> | 2022-12-09 11:04:55 +0100 |
| commit | f22297e3d62975a810f4bc7588ede421f14ebd93 (patch) | |
| tree | 4690d5c574013afae63bc8eabc290f547cc046a8 | |
| parent | 1d2f97b4e226871014c2cf470070343df15d74a0 (diff) | |
| parent | 58ab82904970f2df3984e54c722955a7b7c81391 (diff) | |
Merge branch 'master' into nrf91/53-nvmc
157 files changed, 6699 insertions, 2224 deletions
| @@ -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 | ---- |
| 24 | include::example$basic/src/main.rs[lines="11..12"] | 24 | include::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 | ---- |
| 33 | include::example$basic/src/main.rs[lines="13..22"] | 33 | include::example$basic/src/main.rs[lines="12..20"] |
| 34 | ---- | 34 | ---- |
| 35 | 35 | ||
| 36 | An 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. | 36 | An 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 | ---- |
| 48 | include::example$basic/src/main.rs[lines="23..-1"] | 48 | include::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: | 51 | What 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 | ||
| 54 | fn embassy_config() -> embassy_nrf::config::Config { | ||
| 55 | embassy_nrf::config::Config::default() | ||
| 56 | } | ||
| 57 | |||
| 58 | #[embassy_executor::main(config = "embassy_config()")] | ||
| 59 | async fn main(_spawner: Spawner, p: embassy_nrf::Peripherals) { | ||
| 60 | // ... | ||
| 61 | } | ||
| 62 | ``` | ||
| 63 | |||
| 64 | What 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 | ---- |
| 79 | include::example$basic/Cargo.toml[lines="8..9"] | 66 | include::example$basic/Cargo.toml[lines="9..11"] |
| 80 | ---- | 67 | ---- |
| 81 | 68 | ||
| 82 | Depending on your microcontroller, you may need to replace `embassy-nrf` with something else (`embassy-stm32` for STM32. Remember to update feature flags as well). | 69 | Depending 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 | ||
| 19 | In 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 | In 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 | ||
| 11 | The 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 | 11 | The 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 |
| 12 | to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code. | 12 | to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code. |
| 13 | 13 | ||
| 14 | Writing 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. | 14 | Writing 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: | |||
| 20 | include::example$layer-by-layer/blinky-pac/src/main.rs[] | 20 | include::example$layer-by-layer/blinky-pac/src/main.rs[] |
| 21 | ---- | 21 | ---- |
| 22 | 22 | ||
| 23 | As 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. | 23 | As 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 | ||
| 25 | Another 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. | 25 | Another 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 | ||
| 29 | To simplify our application, we can use the HAL instead. The HAL exposes higher level APIs that handle details such | 29 | To 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: | |||
| 39 | include::example$layer-by-layer/blinky-hal/src/main.rs[] | 39 | include::example$layer-by-layer/blinky-hal/src/main.rs[] |
| 40 | ---- | 40 | ---- |
| 41 | 41 | ||
| 42 | As 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. | 42 | As 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 | ||
| 44 | The same downside from the PAC example still applies though: the application is busy looping and consuming more power than necessary. | 44 | The 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 | ||
| 7 | STM32 microcontrollers comes in many families and flavors, and supporting all of them is a big undertaking. Embassy has taken advantage of the fact | 7 | STM32 microcontrollers come in many families, and flavors and supporting all of them is a big undertaking. Embassy has taken advantage of the fact |
| 8 | that the STM32 peripheral versions are shared across chip families. Instead of re-implementing the SPI | 8 | that the STM32 peripheral versions are shared across chip families. Instead of re-implementing the SPI |
| 9 | peripheral for every STM32 chip family, embassy have a single SPI implementation that depends on | 9 | peripheral for every STM32 chip family, embassy has a single SPI implementation that depends on |
| 10 | code-generated register types that are identical for STM32 families with the same version of a given peripheral. | 10 | code-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] |
| 2 | edition = "2021" | 2 | edition = "2021" |
| 3 | name = "embassy-boot" | 3 | name = "embassy-boot" |
| 4 | version = "0.1.0" | 4 | version = "0.1.1" |
| 5 | description = "Bootloader using Embassy" | 5 | description = "A lightweight bootloader supporting firmware updates in a power-fail-safe way, with trial boots and rollbacks." |
| 6 | license = "MIT OR Apache-2.0" | 6 | license = "MIT OR Apache-2.0" |
| 7 | repository = "https://github.com/embassy-rs/embassy" | ||
| 8 | categories = [ | ||
| 9 | "embedded", | ||
| 10 | "no-std", | ||
| 11 | "asynchronous", | ||
| 12 | ] | ||
| 7 | 13 | ||
| 8 | [package.metadata.embassy_docs] | 14 | [package.metadata.embassy_docs] |
| 9 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-v$VERSION/embassy-boot/boot/src/" | 15 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-v$VERSION/embassy-boot/boot/src/" |
| 10 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot/boot/src/" | 16 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot/boot/src/" |
| 11 | target = "thumbv7em-none-eabi" | 17 | target = "thumbv7em-none-eabi" |
| 18 | features = ["defmt"] | ||
| 19 | |||
| 20 | [package.metadata.docs.rs] | ||
| 21 | features = ["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")] |
| 5 | mod fmt; | 5 | mod fmt; |
| 6 | 6 | ||
| 7 | use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; | 7 | use 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 | |||
| 3 | An [Embassy](https://embassy.dev) project. | ||
| 4 | |||
| 5 | An 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 | |||
| 20 | This 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 | |||
| 26 | at 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")] |
| 5 | mod fmt; | 5 | mod fmt; |
| 6 | 6 | ||
| 7 | pub use embassy_boot::{AlignedBuffer, BootFlash, FirmwareUpdater, FlashConfig, Partition, SingleFlashConfig}; | 7 | pub 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] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-boot-rp" | ||
| 4 | version = "0.1.0" | ||
| 5 | description = "Bootloader lib for RP2040 chips" | ||
| 6 | license = "MIT OR Apache-2.0" | ||
| 7 | |||
| 8 | [package.metadata.embassy_docs] | ||
| 9 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-rp-v$VERSION/src/" | ||
| 10 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot/rp/src/" | ||
| 11 | target = "thumbv6m-none-eabi" | ||
| 12 | |||
| 13 | [lib] | ||
| 14 | |||
| 15 | [dependencies] | ||
| 16 | defmt = { version = "0.3", optional = true } | ||
| 17 | defmt-rtt = { version = "0.4", optional = true } | ||
| 18 | log = { version = "0.4", optional = true } | ||
| 19 | |||
| 20 | embassy-sync = { path = "../../embassy-sync" } | ||
| 21 | embassy-rp = { path = "../../embassy-rp", default-features = false, features = ["nightly"] } | ||
| 22 | embassy-boot = { path = "../boot", default-features = false } | ||
| 23 | cortex-m = { version = "0.7.6" } | ||
| 24 | cortex-m-rt = { version = "0.7" } | ||
| 25 | embedded-storage = "0.3.0" | ||
| 26 | embedded-storage-async = "0.3.0" | ||
| 27 | cfg-if = "1.0.0" | ||
| 28 | |||
| 29 | [features] | ||
| 30 | defmt = [ | ||
| 31 | "dep:defmt", | ||
| 32 | "embassy-boot/defmt", | ||
| 33 | "embassy-rp/defmt", | ||
| 34 | ] | ||
| 35 | log = [ | ||
| 36 | "dep:log", | ||
| 37 | "embassy-boot/log", | ||
| 38 | "embassy-rp/log", | ||
| 39 | ] | ||
| 40 | debug = ["defmt-rtt"] | ||
| 41 | |||
| 42 | [profile.dev] | ||
| 43 | debug = 2 | ||
| 44 | debug-assertions = true | ||
| 45 | incremental = false | ||
| 46 | opt-level = 'z' | ||
| 47 | overflow-checks = true | ||
| 48 | |||
| 49 | [profile.release] | ||
| 50 | codegen-units = 1 | ||
| 51 | debug = 2 | ||
| 52 | debug-assertions = false | ||
| 53 | incremental = false | ||
| 54 | lto = 'fat' | ||
| 55 | opt-level = 'z' | ||
| 56 | overflow-checks = false | ||
| 57 | |||
| 58 | # do not optimize proc-macro crates = faster builds from scratch | ||
| 59 | [profile.dev.build-override] | ||
| 60 | codegen-units = 8 | ||
| 61 | debug = false | ||
| 62 | debug-assertions = false | ||
| 63 | opt-level = 0 | ||
| 64 | overflow-checks = false | ||
| 65 | |||
| 66 | [profile.release.build-override] | ||
| 67 | codegen-units = 8 | ||
| 68 | debug = false | ||
| 69 | debug-assertions = false | ||
| 70 | opt-level = 0 | ||
| 71 | overflow-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 | |||
| 3 | An [Embassy](https://embassy.dev) project. | ||
| 4 | |||
| 5 | An adaptation of `embassy-boot` for RP2040. | ||
| 6 | |||
| 7 | NOTE: 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 | |||
| 20 | This 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 | |||
| 26 | at 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 @@ | |||
| 1 | use std::env; | ||
| 2 | |||
| 3 | fn 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"))] | ||
| 5 | compile_error!("You may not enable both `defmt` and `log` features."); | ||
| 6 | |||
| 7 | macro_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 | |||
| 18 | macro_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 | |||
| 29 | macro_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 | |||
| 40 | macro_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 | |||
| 51 | macro_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 | |||
| 62 | macro_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 | |||
| 73 | macro_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 | |||
| 84 | macro_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 | |||
| 95 | macro_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 | |||
| 106 | macro_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 | |||
| 119 | macro_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 | |||
| 132 | macro_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 | |||
| 145 | macro_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 | |||
| 158 | macro_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")] | ||
| 172 | macro_rules! unwrap { | ||
| 173 | ($($x:tt)*) => { | ||
| 174 | ::defmt::unwrap!($($x)*) | ||
| 175 | }; | ||
| 176 | } | ||
| 177 | |||
| 178 | #[cfg(not(feature = "defmt"))] | ||
| 179 | macro_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)] | ||
| 199 | pub struct NoneError; | ||
| 200 | |||
| 201 | pub trait Try { | ||
| 202 | type Ok; | ||
| 203 | type Error; | ||
| 204 | fn into_result(self) -> Result<Self::Ok, Self::Error>; | ||
| 205 | } | ||
| 206 | |||
| 207 | impl<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 | |||
| 217 | impl<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")] | ||
| 5 | mod fmt; | ||
| 6 | |||
| 7 | pub use embassy_boot::{AlignedBuffer, BootFlash, FirmwareUpdater, FlashConfig, Partition, SingleFlashConfig, State}; | ||
| 8 | use embassy_rp::flash::{ERASE_SIZE, WRITE_SIZE}; | ||
| 9 | |||
| 10 | /// A bootloader for RP2040 devices. | ||
| 11 | pub struct BootLoader { | ||
| 12 | boot: embassy_boot::BootLoader, | ||
| 13 | magic: AlignedBuffer<WRITE_SIZE>, | ||
| 14 | page: AlignedBuffer<ERASE_SIZE>, | ||
| 15 | } | ||
| 16 | |||
| 17 | impl 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 | |||
| 53 | impl 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] |
| 17 | defmt = { version = "0.3", optional = true } | 17 | defmt = { version = "0.3", optional = true } |
| 18 | defmt-rtt = { version = "0.3", optional = true } | 18 | defmt-rtt = { version = "0.4", optional = true } |
| 19 | log = { version = "0.4", optional = true } | 19 | log = { version = "0.4", optional = true } |
| 20 | 20 | ||
| 21 | embassy-sync = { path = "../../embassy-sync" } | 21 | embassy-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 | ||
| 3 | The bootloader uses `embassy-boot` to interact with the flash. | 3 | An [Embassy](https://embassy.dev) project. |
| 4 | 4 | ||
| 5 | # Usage | 5 | An adaptation of `embassy-boot` for STM32. |
| 6 | 6 | ||
| 7 | Flash the bootloader | 7 | ## Features |
| 8 | 8 | ||
| 9 | ``` | 9 | * Configure bootloader partitions based on linker script. |
| 10 | cargo 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 | |||
| 18 | This 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 | |||
| 24 | at 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")] |
| 5 | mod fmt; | 5 | mod fmt; |
| 6 | 6 | ||
| 7 | pub use embassy_boot::{AlignedBuffer, BootFlash, FirmwareUpdater, FlashConfig, Partition, SingleFlashConfig, State}; | 7 | pub 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"] | |||
| 20 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } | 20 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } |
| 21 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 21 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 22 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 22 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } |
| 23 | embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true } | 23 | embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true } |
| 24 | embedded-storage = "0.3.0" | 24 | embedded-storage = "0.3.0" |
| 25 | embedded-storage-async = { version = "0.3.0", optional = true } | 25 | embedded-storage-async = { version = "0.3.0", optional = true } |
| 26 | nb = "1.0.0" | 26 | nb = "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 | //! ``` |
| 25 | use core::future::Future; | ||
| 26 | 25 | ||
| 27 | use embassy_sync::blocking_mutex::raw::RawMutex; | 26 | use embassy_sync::blocking_mutex::raw::RawMutex; |
| 28 | use embassy_sync::mutex::Mutex; | 27 | use 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] |
| 2 | name = "embassy-executor" | 2 | name = "embassy-executor" |
| 3 | version = "0.1.0" | 3 | version = "0.1.1" |
| 4 | edition = "2021" | 4 | edition = "2021" |
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | description = "async/await executor designed for embedded usage" | |
| 7 | repository = "https://github.com/embassy-rs/embassy" | ||
| 8 | categories = [ | ||
| 9 | "embedded", | ||
| 10 | "no-std", | ||
| 11 | "asynchronous", | ||
| 12 | ] | ||
| 7 | 13 | ||
| 8 | [package.metadata.embassy_docs] | 14 | [package.metadata.embassy_docs] |
| 9 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/" | 15 | src_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] | ||
| 31 | features = ["std", "nightly", "defmt"] | ||
| 32 | |||
| 24 | [features] | 33 | [features] |
| 25 | default = [] | 34 | default = [] |
| 26 | std = ["embassy-macros/std", "critical-section/std"] | 35 | std = ["critical-section/std"] |
| 27 | wasm = ["dep:wasm-bindgen", "dep:js-sys", "embassy-macros/wasm"] | 36 | wasm = ["dep:wasm-bindgen", "dep:js-sys"] |
| 28 | 37 | ||
| 29 | # Enable nightly-only features | 38 | # Enable nightly-only features |
| 30 | nightly = [] | 39 | nightly = [] |
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 @@ | |||
| 8 | pub(crate) mod fmt; | 8 | pub(crate) mod fmt; |
| 9 | 9 | ||
| 10 | #[cfg(feature = "nightly")] | 10 | #[cfg(feature = "nightly")] |
| 11 | pub use embassy_macros::{main, task}; | 11 | pub use embassy_macros::task; |
| 12 | 12 | ||
| 13 | cfg_if::cfg_if! { | 13 | cfg_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 @@ | |||
| 1 | use core::slice; | ||
| 2 | use 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). | ||
| 16 | pub struct RingBuffer { | ||
| 17 | buf: AtomicPtr<u8>, | ||
| 18 | len: AtomicUsize, | ||
| 19 | start: AtomicUsize, | ||
| 20 | end: AtomicUsize, | ||
| 21 | } | ||
| 22 | |||
| 23 | pub struct Reader<'a>(&'a RingBuffer); | ||
| 24 | pub struct Writer<'a>(&'a RingBuffer); | ||
| 25 | |||
| 26 | impl 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 | |||
| 110 | impl<'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 | |||
| 178 | impl<'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)] | ||
| 248 | mod 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. |
| 5 | pub(crate) mod fmt; | 5 | pub(crate) mod fmt; |
| 6 | 6 | ||
| 7 | pub mod atomic_ring_buffer; | ||
| 7 | pub mod drop; | 8 | pub mod drop; |
| 8 | mod macros; | 9 | mod macros; |
| 9 | mod peripheral; | 10 | mod 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" } | |||
| 32 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } | 32 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } |
| 33 | embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } | 33 | embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } |
| 34 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 34 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } |
| 35 | embedded-hal-async = { version = "=0.1.0-alpha.3" } | 35 | embedded-hal-async = { version = "=0.2.0-alpha.0" } |
| 36 | embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common", default-features = false } | 36 | embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common", default-features = false } |
| 37 | futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } | 37 | futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } |
| 38 | embedded-hal = { version = "0.2", features = ["unproven"] } | 38 | embedded-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" | |||
| 3 | version = "0.1.0" | 3 | version = "0.1.0" |
| 4 | edition = "2021" | 4 | edition = "2021" |
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | description = "macros for creating the entry point and tasks for embassy-executor" | ||
| 7 | repository = "https://github.com/embassy-rs/embassy" | ||
| 8 | categories = [ | ||
| 9 | "embedded", | ||
| 10 | "no-std", | ||
| 11 | "asynchronous", | ||
| 12 | ] | ||
| 6 | 13 | ||
| 7 | [dependencies] | 14 | [dependencies] |
| 8 | syn = { version = "1.0.76", features = ["full", "extra-traits"] } | 15 | syn = { version = "1.0.76", features = ["full", "extra-traits"] } |
| @@ -14,8 +21,5 @@ proc-macro2 = "1.0.29" | |||
| 14 | proc-macro = true | 21 | proc-macro = true |
| 15 | 22 | ||
| 16 | [features] | 23 | [features] |
| 17 | std = [] | ||
| 18 | wasm = [] | ||
| 19 | |||
| 20 | # Enabling this cause interrupt::take! to require embassy-executor | 24 | # Enabling this cause interrupt::take! to require embassy-executor |
| 21 | rtos-trace-interrupt = [] | 25 | rtos-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 | |||
| 3 | An [Embassy](https://embassy.dev) project. | ||
| 4 | |||
| 5 | Macros for creating the main entry point and tasks that can be spawned by `embassy-executor`. | ||
| 6 | |||
| 7 | NOTE: 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 | |||
| 11 | The `task` and `main` macros require the type alias impl trait (TAIT) nightly feature in order to compile. | ||
| 12 | |||
| 13 | ## License | ||
| 14 | |||
| 15 | This 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 | |||
| 21 | at 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")] | ||
| 1 | extern crate proc_macro; | 2 | extern crate proc_macro; |
| 2 | 3 | ||
| 3 | use proc_macro::TokenStream; | 4 | use proc_macro::TokenStream; |
| @@ -6,6 +7,36 @@ mod macros; | |||
| 6 | mod util; | 7 | mod util; |
| 7 | use macros::*; | 8 | use 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] |
| 10 | pub fn task(args: TokenStream, item: TokenStream) -> TokenStream { | 41 | pub 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] | ||
| 67 | pub 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] | ||
| 92 | pub 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] | ||
| 117 | pub 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] |
| 18 | pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { | 142 | pub 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)] |
| 8 | struct Args {} | 8 | struct Args {} |
| 9 | 9 | ||
| 10 | pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, TokenStream> { | 10 | pub 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 { | 23 | pub 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()?; | 36 | pub 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")))] | 52 | pub 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")))] | 65 | pub 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 | ||
| 43 | embassy-time = { version = "0.1.0", path = "../embassy-time" } | 43 | embassy-time = { version = "0.1.0", path = "../embassy-time" } |
| 44 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } | 44 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } |
| 45 | embedded-io = { version = "0.3.1", optional = true } | 45 | embedded-io = { version = "0.4.0", optional = true } |
| 46 | 46 | ||
| 47 | managed = { version = "0.8.0", default-features = false, features = [ "map" ] } | 47 | managed = { version = "0.8.0", default-features = false, features = [ "map" ] } |
| 48 | heapless = { version = "0.7.5", default-features = false } | 48 | heapless = { version = "0.7.5", default-features = false } |
| @@ -52,12 +52,12 @@ stable_deref_trait = { version = "1.2.0", default-features = false } | |||
| 52 | futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } | 52 | futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } |
| 53 | atomic-pool = "1.0" | 53 | atomic-pool = "1.0" |
| 54 | atomic-polyfill = "1.0.1" | 54 | atomic-polyfill = "1.0.1" |
| 55 | embedded-nal-async = { version = "0.2.0", optional = true } | 55 | embedded-nal-async = { version = "0.3.0", optional = true } |
| 56 | 56 | ||
| 57 | [dependencies.smoltcp] | 57 | [dependencies.smoltcp] |
| 58 | version = "0.8.0" | 58 | version = "0.8.0" |
| 59 | git = "https://github.com/smoltcp-rs/smoltcp" | 59 | git = "https://github.com/smoltcp-rs/smoltcp" |
| 60 | rev = "ed0cf16750a42f30e31fcaf5347915592924b1e3" | 60 | rev = "b7a7c4b1c56e8d4c2524c1e3a056c745a13cc09f" |
| 61 | default-features = false | 61 | default-features = false |
| 62 | features = [ | 62 | features = [ |
| 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 | ||
| 17 | pub trait Device { | 15 | pub 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 | ||
| 28 | impl<T: ?Sized + Device> Device for &'static mut T { | 26 | impl<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 | ||
| 66 | impl<'a, D: Device + 'static> SmolDevice<'a> for DeviceAdapter<D> { | 64 | impl<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. |
| 5 | pub(crate) mod fmt; | 9 | pub(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 @@ | |||
| 1 | use core::cell::UnsafeCell; | 1 | use core::cell::RefCell; |
| 2 | use core::future::{poll_fn, Future}; | 2 | use core::future::{poll_fn, Future}; |
| 3 | use core::task::{Context, Poll}; | 3 | use core::task::{Context, Poll}; |
| 4 | 4 | ||
| @@ -62,8 +62,8 @@ pub enum ConfigStrategy { | |||
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | pub struct Stack<D: Device> { | 64 | pub 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 | ||
| 69 | struct Inner<D: Device> { | 69 | struct 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 | ||
| 84 | unsafe impl<D: Device> Send for Stack<D> {} | ||
| 85 | |||
| 86 | impl<D: Device + 'static> Stack<D> { | 84 | impl<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 @@ | |||
| 1 | use core::cell::UnsafeCell; | 1 | use core::cell::RefCell; |
| 2 | use core::future::poll_fn; | 2 | use core::future::poll_fn; |
| 3 | use core::mem; | 3 | use core::mem; |
| 4 | use core::task::Poll; | 4 | use core::task::Poll; |
| @@ -68,8 +68,7 @@ impl<'a> TcpWriter<'a> { | |||
| 68 | 68 | ||
| 69 | impl<'a> TcpSocket<'a> { | 69 | impl<'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 | ||
| 192 | impl<'a> Drop for TcpSocket<'a> { | 191 | impl<'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)] |
| 203 | struct TcpIo<'a> { | 200 | struct TcpIo<'a> { |
| 204 | stack: &'a UnsafeCell<SocketStack>, | 201 | stack: &'a RefCell<SocketStack>, |
| 205 | handle: SocketHandle, | 202 | handle: SocketHandle, |
| 206 | } | 203 | } |
| 207 | 204 | ||
| 208 | impl<'d> TcpIo<'d> { | 205 | impl<'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")] |
| 273 | mod embedded_io_impls { | 268 | mod 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"))] |
| 360 | pub mod client { | 329 | pub 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 @@ | |||
| 1 | use core::cell::UnsafeCell; | 1 | use core::cell::RefCell; |
| 2 | use core::future::poll_fn; | 2 | use core::future::poll_fn; |
| 3 | use core::mem; | 3 | use core::mem; |
| 4 | use core::task::Poll; | 4 | use core::task::Poll; |
| @@ -27,7 +27,7 @@ pub enum Error { | |||
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | pub struct UdpSocket<'a> { | 29 | pub 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 | ||
| 151 | impl Drop for UdpSocket<'_> { | 146 | impl 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 | ||
| 76 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 76 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 77 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} | 77 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} |
| 78 | embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true} | 78 | embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} |
| 79 | embedded-io = { version = "0.3.1", features = ["async"], optional = true } | 79 | embedded-io = { version = "0.4.0", features = ["async"], optional = true } |
| 80 | 80 | ||
| 81 | defmt = { version = "0.3", optional = true } | 81 | defmt = { version = "0.3", optional = true } |
| 82 | log = { version = "0.4.14", optional = true } | 82 | log = { 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 | ||
| 16 | use core::cell::RefCell; | 16 | use core::cell::RefCell; |
| 17 | use core::cmp::min; | 17 | use core::cmp::min; |
| 18 | use core::future::{poll_fn, Future}; | 18 | use core::future::poll_fn; |
| 19 | use core::sync::atomic::{compiler_fence, Ordering}; | 19 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 20 | use core::task::Poll; | 20 | use 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 | ||
| 343 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarte<'d, U, T> { | 343 | impl<'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 | ||
| 353 | impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarteRx<'u, 'd, U, T> { | 349 | impl<'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 | ||
| 363 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarte<'d, U, T> { | 355 | impl<'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 | ||
| 377 | impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarteRx<'u, 'd, U, T> { | 365 | impl<'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 | ||
| 391 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarte<'d, U, T> { | 375 | impl<'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 | ||
| 409 | impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarteTx<'u, 'd, U, T> { | 385 | impl<'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 | ||
| 132 | impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); | 132 | impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); |
| 133 | 133 | ||
| 134 | impl_spis!(SPI0, SPIS0, SPIM0_SPIS0_SPI0); | ||
| 135 | |||
| 134 | impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); | 136 | impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); |
| 135 | 137 | ||
| 138 | impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0); | ||
| 139 | |||
| 136 | impl_timer!(TIMER0, TIMER0, TIMER0); | 140 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 137 | impl_timer!(TIMER1, TIMER1, TIMER1); | 141 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 138 | impl_timer!(TIMER2, TIMER2, TIMER2); | 142 | impl_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 | ||
| 138 | impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); | 138 | impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); |
| 139 | 139 | ||
| 140 | impl_spis!(SPI0, SPIS0, SPIM0_SPIS0_SPI0); | ||
| 141 | |||
| 140 | impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); | 142 | impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); |
| 141 | 143 | ||
| 144 | impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0); | ||
| 145 | |||
| 142 | impl_pwm!(PWM0, PWM0, PWM0); | 146 | impl_pwm!(PWM0, PWM0, PWM0); |
| 143 | 147 | ||
| 144 | impl_timer!(TIMER0, TIMER0, TIMER0); | 148 | impl_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); | |||
| 138 | impl_spim!(TWISPI0, SPIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); | 138 | impl_spim!(TWISPI0, SPIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); |
| 139 | impl_spim!(SPI1, SPIM1, SPIM1_SPIS1_SPI1); | 139 | impl_spim!(SPI1, SPIM1, SPIM1_SPIS1_SPI1); |
| 140 | 140 | ||
| 141 | impl_spis!(TWISPI0, SPIS0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); | ||
| 142 | impl_spis!(SPI1, SPIS1, SPIM1_SPIS1_SPI1); | ||
| 143 | |||
| 141 | impl_twim!(TWISPI0, TWIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); | 144 | impl_twim!(TWISPI0, TWIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); |
| 142 | 145 | ||
| 146 | impl_twis!(TWISPI0, TWIS0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); | ||
| 147 | |||
| 143 | impl_pwm!(PWM0, PWM0, PWM0); | 148 | impl_pwm!(PWM0, PWM0, PWM0); |
| 144 | 149 | ||
| 145 | impl_timer!(TIMER0, TIMER0, TIMER0); | 150 | impl_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); | |||
| 136 | impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 136 | impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); |
| 137 | impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 137 | impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); |
| 138 | 138 | ||
| 139 | impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 140 | impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 141 | |||
| 139 | impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 142 | impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); |
| 140 | impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 143 | impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); |
| 141 | 144 | ||
| 145 | impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 146 | impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 147 | |||
| 142 | impl_timer!(TIMER0, TIMER0, TIMER0); | 148 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 143 | impl_timer!(TIMER1, TIMER1, TIMER1); | 149 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 144 | impl_timer!(TIMER2, TIMER2, TIMER2); | 150 | impl_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 | ||
| 143 | impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | 146 | impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); |
| @@ -146,9 +149,16 @@ impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | |||
| 146 | impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 149 | impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); |
| 147 | impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); | 150 | impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); |
| 148 | 151 | ||
| 152 | impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 153 | impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 154 | impl_spis!(SPI2, SPIS2, SPIM2_SPIS2_SPI2); | ||
| 155 | |||
| 149 | impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 156 | impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); |
| 150 | impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 157 | impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); |
| 151 | 158 | ||
| 159 | impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 160 | impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 161 | |||
| 152 | impl_pwm!(PWM0, PWM0, PWM0); | 162 | impl_pwm!(PWM0, PWM0, PWM0); |
| 153 | impl_pwm!(PWM1, PWM1, PWM1); | 163 | impl_pwm!(PWM1, PWM1, PWM1); |
| 154 | impl_pwm!(PWM2, PWM2, PWM2); | 164 | impl_pwm!(PWM2, PWM2, PWM2); |
| @@ -234,6 +244,8 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5); | |||
| 234 | impl_saadc_input!(P0_30, ANALOG_INPUT6); | 244 | impl_saadc_input!(P0_30, ANALOG_INPUT6); |
| 235 | impl_saadc_input!(P0_31, ANALOG_INPUT7); | 245 | impl_saadc_input!(P0_31, ANALOG_INPUT7); |
| 236 | 246 | ||
| 247 | impl_i2s!(I2S, I2S, I2S); | ||
| 248 | |||
| 237 | pub mod irqs { | 249 | pub 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); | |||
| 174 | impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); | 177 | impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); |
| 175 | impl_spim!(SPI3, SPIM3, SPIM3); | 178 | impl_spim!(SPI3, SPIM3, SPIM3); |
| 176 | 179 | ||
| 180 | impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 181 | impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 182 | impl_spis!(SPI2, SPIS2, SPIM2_SPIS2_SPI2); | ||
| 183 | |||
| 177 | impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 184 | impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); |
| 178 | impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 185 | impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); |
| 179 | 186 | ||
| 187 | impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 188 | impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 189 | |||
| 180 | impl_pwm!(PWM0, PWM0, PWM0); | 190 | impl_pwm!(PWM0, PWM0, PWM0); |
| 181 | impl_pwm!(PWM1, PWM1, PWM1); | 191 | impl_pwm!(PWM1, PWM1, PWM1); |
| 182 | impl_pwm!(PWM2, PWM2, PWM2); | 192 | impl_pwm!(PWM2, PWM2, PWM2); |
| @@ -280,6 +290,8 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5); | |||
| 280 | impl_saadc_input!(P0_30, ANALOG_INPUT6); | 290 | impl_saadc_input!(P0_30, ANALOG_INPUT6); |
| 281 | impl_saadc_input!(P0_31, ANALOG_INPUT7); | 291 | impl_saadc_input!(P0_31, ANALOG_INPUT7); |
| 282 | 292 | ||
| 293 | impl_i2s!(I2S, I2S, I2S); | ||
| 294 | |||
| 283 | pub mod irqs { | 295 | pub 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); | |||
| 177 | impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); | 180 | impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); |
| 178 | impl_spim!(SPI3, SPIM3, SPIM3); | 181 | impl_spim!(SPI3, SPIM3, SPIM3); |
| 179 | 182 | ||
| 183 | impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 184 | impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 185 | impl_spis!(SPI2, SPIS2, SPIM2_SPIS2_SPI2); | ||
| 186 | |||
| 180 | impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 187 | impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); |
| 181 | impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 188 | impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); |
| 182 | 189 | ||
| 190 | impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 191 | impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 192 | |||
| 183 | impl_pwm!(PWM0, PWM0, PWM0); | 193 | impl_pwm!(PWM0, PWM0, PWM0); |
| 184 | impl_pwm!(PWM1, PWM1, PWM1); | 194 | impl_pwm!(PWM1, PWM1, PWM1); |
| 185 | impl_pwm!(PWM2, PWM2, PWM2); | 195 | impl_pwm!(PWM2, PWM2, PWM2); |
| @@ -285,6 +295,8 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5); | |||
| 285 | impl_saadc_input!(P0_30, ANALOG_INPUT6); | 295 | impl_saadc_input!(P0_30, ANALOG_INPUT6); |
| 286 | impl_saadc_input!(P0_31, ANALOG_INPUT7); | 296 | impl_saadc_input!(P0_31, ANALOG_INPUT7); |
| 287 | 297 | ||
| 298 | impl_i2s!(I2S, I2S, I2S); | ||
| 299 | |||
| 288 | pub mod irqs { | 300 | pub 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); | |||
| 366 | impl_spim!(UARTETWISPI2, SPIM2, SERIAL2); | 366 | impl_spim!(UARTETWISPI2, SPIM2, SERIAL2); |
| 367 | impl_spim!(UARTETWISPI3, SPIM3, SERIAL3); | 367 | impl_spim!(UARTETWISPI3, SPIM3, SERIAL3); |
| 368 | 368 | ||
| 369 | impl_spis!(UARTETWISPI0, SPIS0, SERIAL0); | ||
| 370 | impl_spis!(UARTETWISPI1, SPIS1, SERIAL1); | ||
| 371 | impl_spis!(UARTETWISPI2, SPIS2, SERIAL2); | ||
| 372 | impl_spis!(UARTETWISPI3, SPIS3, SERIAL3); | ||
| 373 | |||
| 369 | impl_twim!(UARTETWISPI0, TWIM0, SERIAL0); | 374 | impl_twim!(UARTETWISPI0, TWIM0, SERIAL0); |
| 370 | impl_twim!(UARTETWISPI1, TWIM1, SERIAL1); | 375 | impl_twim!(UARTETWISPI1, TWIM1, SERIAL1); |
| 371 | impl_twim!(UARTETWISPI2, TWIM2, SERIAL2); | 376 | impl_twim!(UARTETWISPI2, TWIM2, SERIAL2); |
| 372 | impl_twim!(UARTETWISPI3, TWIM3, SERIAL3); | 377 | impl_twim!(UARTETWISPI3, TWIM3, SERIAL3); |
| 373 | 378 | ||
| 379 | impl_twis!(UARTETWISPI0, TWIS0, SERIAL0); | ||
| 380 | impl_twis!(UARTETWISPI1, TWIS1, SERIAL1); | ||
| 381 | impl_twis!(UARTETWISPI2, TWIS2, SERIAL2); | ||
| 382 | impl_twis!(UARTETWISPI3, TWIS3, SERIAL3); | ||
| 383 | |||
| 374 | impl_pwm!(PWM0, PWM0, PWM0); | 384 | impl_pwm!(PWM0, PWM0, PWM0); |
| 375 | impl_pwm!(PWM1, PWM1, PWM1); | 385 | impl_pwm!(PWM1, PWM1, PWM1); |
| 376 | impl_pwm!(PWM2, PWM2, PWM2); | 386 | impl_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 | ||
| 244 | impl_uarte!(UARTETWISPI0, UARTE0, SERIAL0); | 244 | impl_uarte!(UARTETWISPI0, UARTE0, SERIAL0); |
| 245 | impl_spim!(UARTETWISPI0, SPIM0, SERIAL0); | 245 | impl_spim!(UARTETWISPI0, SPIM0, SERIAL0); |
| 246 | impl_spis!(UARTETWISPI0, SPIS0, SERIAL0); | ||
| 246 | impl_twim!(UARTETWISPI0, TWIM0, SERIAL0); | 247 | impl_twim!(UARTETWISPI0, TWIM0, SERIAL0); |
| 248 | impl_twis!(UARTETWISPI0, TWIS0, SERIAL0); | ||
| 247 | 249 | ||
| 248 | impl_timer!(TIMER0, TIMER0, TIMER0); | 250 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 249 | impl_timer!(TIMER1, TIMER1, TIMER1); | 251 | impl_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); | |||
| 280 | impl_spim!(UARTETWISPI2, SPIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); | 280 | impl_spim!(UARTETWISPI2, SPIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); |
| 281 | impl_spim!(UARTETWISPI3, SPIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); | 281 | impl_spim!(UARTETWISPI3, SPIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); |
| 282 | 282 | ||
| 283 | impl_spis!(UARTETWISPI0, SPIS0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); | ||
| 284 | impl_spis!(UARTETWISPI1, SPIS1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); | ||
| 285 | impl_spis!(UARTETWISPI2, SPIS2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); | ||
| 286 | impl_spis!(UARTETWISPI3, SPIS3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); | ||
| 287 | |||
| 283 | impl_twim!(UARTETWISPI0, TWIM0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); | 288 | impl_twim!(UARTETWISPI0, TWIM0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); |
| 284 | impl_twim!(UARTETWISPI1, TWIM1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); | 289 | impl_twim!(UARTETWISPI1, TWIM1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); |
| 285 | impl_twim!(UARTETWISPI2, TWIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); | 290 | impl_twim!(UARTETWISPI2, TWIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); |
| 286 | impl_twim!(UARTETWISPI3, TWIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); | 291 | impl_twim!(UARTETWISPI3, TWIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); |
| 287 | 292 | ||
| 293 | impl_twis!(UARTETWISPI0, TWIS0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); | ||
| 294 | impl_twis!(UARTETWISPI1, TWIS1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); | ||
| 295 | impl_twis!(UARTETWISPI2, TWIS2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); | ||
| 296 | impl_twis!(UARTETWISPI3, TWIS3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); | ||
| 297 | |||
| 288 | impl_pwm!(PWM0, PWM0, PWM0); | 298 | impl_pwm!(PWM0, PWM0, PWM0); |
| 289 | impl_pwm!(PWM1, PWM1, PWM1); | 299 | impl_pwm!(PWM1, PWM1, PWM1); |
| 290 | impl_pwm!(PWM2, PWM2, PWM2); | 300 | impl_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; | |||
| 2 | use core::future::{poll_fn, Future}; | 2 | use core::future::{poll_fn, Future}; |
| 3 | use core::task::{Context, Poll}; | 3 | use core::task::{Context, Poll}; |
| 4 | 4 | ||
| 5 | use embassy_hal_common::{impl_peripheral, Peripheral, PeripheralRef}; | 5 | use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; |
| 6 | use embassy_sync::waitqueue::AtomicWaker; | 6 | use embassy_sync::waitqueue::AtomicWaker; |
| 7 | 7 | ||
| 8 | use crate::gpio::sealed::Pin as _; | 8 | use 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 |
| 150 | pub struct InputChannel<'d, C: Channel, T: GpioPin> { | 150 | pub 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 | ||
| 164 | impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { | 164 | impl<'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 |
| 217 | pub struct OutputChannel<'d, C: Channel, T: GpioPin> { | 219 | pub 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 | ||
| 231 | impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { | 233 | impl<'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"))] |
| 472 | mod eha { | 475 | mod 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 | |||
| 5 | use core::future::poll_fn; | ||
| 6 | use core::marker::PhantomData; | ||
| 7 | use core::mem::size_of; | ||
| 8 | use core::ops::{Deref, DerefMut}; | ||
| 9 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 10 | use core::task::Poll; | ||
| 11 | |||
| 12 | use embassy_cortex_m::interrupt::InterruptExt; | ||
| 13 | use embassy_hal_common::drop::OnDrop; | ||
| 14 | use embassy_hal_common::{into_ref, PeripheralRef}; | ||
| 15 | |||
| 16 | use crate::gpio::{AnyPin, Pin as GpioPin}; | ||
| 17 | use crate::interrupt::Interrupt; | ||
| 18 | use crate::pac::i2s::RegisterBlock; | ||
| 19 | use crate::util::{slice_in_ram_or, slice_ptr_parts}; | ||
| 20 | use crate::{Peripheral, EASY_DMA_SIZE}; | ||
| 21 | |||
| 22 | pub 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] | ||
| 27 | pub enum Error { | ||
| 28 | BufferTooLong, | ||
| 29 | BufferZeroLength, | ||
| 30 | BufferNotInDataMemory, | ||
| 31 | BufferMisaligned, | ||
| 32 | BufferLengthMisaligned, | ||
| 33 | } | ||
| 34 | |||
| 35 | /// I2S configuration. | ||
| 36 | #[derive(Clone)] | ||
| 37 | #[non_exhaustive] | ||
| 38 | pub struct Config { | ||
| 39 | pub sample_width: SampleWidth, | ||
| 40 | pub align: Align, | ||
| 41 | pub format: Format, | ||
| 42 | pub channels: Channels, | ||
| 43 | } | ||
| 44 | |||
| 45 | impl 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 | |||
| 67 | impl 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)] | ||
| 80 | pub struct MasterClock { | ||
| 81 | freq: MckFreq, | ||
| 82 | ratio: Ratio, | ||
| 83 | } | ||
| 84 | |||
| 85 | impl MasterClock { | ||
| 86 | pub fn new(freq: MckFreq, ratio: Ratio) -> Self { | ||
| 87 | Self { freq, ratio } | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | impl 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)] | ||
| 99 | pub 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 | |||
| 115 | impl 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 | |||
| 137 | impl 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)] | ||
| 148 | pub enum Ratio { | ||
| 149 | _32x, | ||
| 150 | _48x, | ||
| 151 | _64x, | ||
| 152 | _96x, | ||
| 153 | _128x, | ||
| 154 | _192x, | ||
| 155 | _256x, | ||
| 156 | _384x, | ||
| 157 | _512x, | ||
| 158 | } | ||
| 159 | |||
| 160 | impl 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 | |||
| 173 | impl 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)] | ||
| 185 | pub enum ApproxSampleRate { | ||
| 186 | _11025, | ||
| 187 | _16000, | ||
| 188 | _22050, | ||
| 189 | _32000, | ||
| 190 | _44100, | ||
| 191 | _48000, | ||
| 192 | } | ||
| 193 | |||
| 194 | impl 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 | |||
| 213 | impl 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)] | ||
| 225 | pub 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 | |||
| 239 | impl ExactSampleRate { | ||
| 240 | pub fn sample_rate(&self) -> u32 { | ||
| 241 | MasterClock::from(*self).sample_rate() | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | impl 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)] | ||
| 265 | pub enum SampleWidth { | ||
| 266 | _8bit, | ||
| 267 | _16bit, | ||
| 268 | _24bit, | ||
| 269 | } | ||
| 270 | |||
| 271 | impl 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)] | ||
| 279 | pub enum Align { | ||
| 280 | Left, | ||
| 281 | Right, | ||
| 282 | } | ||
| 283 | |||
| 284 | impl 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)] | ||
| 295 | pub enum Format { | ||
| 296 | I2S, | ||
| 297 | Aligned, | ||
| 298 | } | ||
| 299 | |||
| 300 | impl 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)] | ||
| 311 | pub enum Channels { | ||
| 312 | Stereo, | ||
| 313 | MonoLeft, | ||
| 314 | MonoRight, | ||
| 315 | } | ||
| 316 | |||
| 317 | impl 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. | ||
| 324 | pub 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 | |||
| 336 | impl<'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 | ||
| 676 | pub 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 | |||
| 681 | impl<'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 | ||
| 730 | pub 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 | |||
| 735 | impl<'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) | ||
| 785 | pub 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 | |||
| 791 | impl<'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. | ||
| 845 | struct Device<T>(&'static RegisterBlock, PhantomData<T>); | ||
| 846 | |||
| 847 | impl<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 | ||
| 1005 | pub trait Sample: Sized + Copy + Default { | ||
| 1006 | const WIDTH: usize; | ||
| 1007 | const SCALE: Self; | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | impl Sample for i8 { | ||
| 1011 | const WIDTH: usize = 8; | ||
| 1012 | const SCALE: Self = 1 << (Self::WIDTH - 1); | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | impl Sample for i16 { | ||
| 1016 | const WIDTH: usize = 16; | ||
| 1017 | const SCALE: Self = 1 << (Self::WIDTH - 1); | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | impl 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))] | ||
| 1028 | pub struct AlignedBuffer<T: Sample, const N: usize>([T; N]); | ||
| 1029 | |||
| 1030 | impl<T: Sample, const N: usize> AlignedBuffer<T, N> { | ||
| 1031 | pub fn new(array: [T; N]) -> Self { | ||
| 1032 | Self(array) | ||
| 1033 | } | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | impl<T: Sample, const N: usize> Default for AlignedBuffer<T, N> { | ||
| 1037 | fn default() -> Self { | ||
| 1038 | Self([T::default(); N]) | ||
| 1039 | } | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | impl<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 | |||
| 1049 | impl<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 | |||
| 1055 | pub struct MultiBuffering<S: Sample, const NB: usize, const NS: usize> { | ||
| 1056 | buffers: [AlignedBuffer<S, NS>; NB], | ||
| 1057 | index: usize, | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | impl<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 | |||
| 1092 | pub(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 | |||
| 1122 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | ||
| 1123 | type Interrupt: Interrupt; | ||
| 1124 | } | ||
| 1125 | |||
| 1126 | macro_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; | |||
| 74 | pub mod gpio; | 78 | pub mod gpio; |
| 75 | #[cfg(feature = "gpiote")] | 79 | #[cfg(feature = "gpiote")] |
| 76 | pub mod gpiote; | 80 | pub mod gpiote; |
| 81 | #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] | ||
| 82 | pub mod i2s; | ||
| 77 | pub mod nvmc; | 83 | pub 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")))] |
| 96 | pub mod saadc; | 102 | pub mod saadc; |
| 97 | pub mod spim; | 103 | pub mod spim; |
| 104 | pub mod spis; | ||
| 98 | #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] | 105 | #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] |
| 99 | pub mod temp; | 106 | pub mod temp; |
| 100 | pub mod timer; | 107 | pub mod timer; |
| 101 | pub mod twim; | 108 | pub mod twim; |
| 109 | pub mod twis; | ||
| 102 | pub mod uarte; | 110 | pub 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"))] |
| 479 | mod eha { | 479 | mod 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] | ||
| 2 | use core::future::poll_fn; | ||
| 3 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 4 | use core::task::Poll; | ||
| 5 | |||
| 6 | use embassy_embedded_hal::SetConfig; | ||
| 7 | use embassy_hal_common::{into_ref, PeripheralRef}; | ||
| 8 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | ||
| 9 | |||
| 10 | use crate::chip::FORCE_COPY_BUFFER_SIZE; | ||
| 11 | use crate::gpio::sealed::Pin as _; | ||
| 12 | use crate::gpio::{self, AnyPin, Pin as GpioPin}; | ||
| 13 | use crate::interrupt::{Interrupt, InterruptExt}; | ||
| 14 | use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; | ||
| 15 | use crate::{pac, Peripheral}; | ||
| 16 | |||
| 17 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 18 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 19 | #[non_exhaustive] | ||
| 20 | pub 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. | ||
| 30 | pub struct Spis<'d, T: Instance> { | ||
| 31 | _p: PeripheralRef<'d, T>, | ||
| 32 | } | ||
| 33 | |||
| 34 | #[non_exhaustive] | ||
| 35 | pub struct Config { | ||
| 36 | pub mode: Mode, | ||
| 37 | pub orc: u8, | ||
| 38 | pub def: u8, | ||
| 39 | pub auto_acquire: bool, | ||
| 40 | } | ||
| 41 | |||
| 42 | impl 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 | |||
| 53 | impl<'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 | |||
| 431 | impl<'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 | |||
| 448 | pub(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 | |||
| 471 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | ||
| 472 | type Interrupt: Interrupt; | ||
| 473 | } | ||
| 474 | |||
| 475 | macro_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 | |||
| 494 | impl<'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 { | |||
| 841 | mod eha { | 841 | mod 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 | ||
| 9 | use core::future::{poll_fn, Future}; | ||
| 10 | use core::sync::atomic::compiler_fence; | ||
| 11 | use core::sync::atomic::Ordering::SeqCst; | ||
| 12 | use core::task::Poll; | ||
| 13 | |||
| 14 | use embassy_hal_common::{into_ref, PeripheralRef}; | ||
| 15 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 16 | #[cfg(feature = "time")] | ||
| 17 | use embassy_time::{Duration, Instant}; | ||
| 18 | |||
| 19 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | ||
| 20 | use crate::gpio::Pin as GpioPin; | ||
| 21 | use crate::interrupt::{Interrupt, InterruptExt}; | ||
| 22 | use crate::util::slice_in_ram_or; | ||
| 23 | use crate::{gpio, pac, Peripheral}; | ||
| 24 | |||
| 25 | #[non_exhaustive] | ||
| 26 | pub 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 | |||
| 36 | impl 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))] | ||
| 52 | enum 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] | ||
| 60 | pub 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))] | ||
| 73 | pub 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. | ||
| 82 | pub struct Twis<'d, T: Instance> { | ||
| 83 | _p: PeripheralRef<'d, T>, | ||
| 84 | } | ||
| 85 | |||
| 86 | impl<'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 | |||
| 702 | impl<'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 | |||
| 719 | pub(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 | |||
| 740 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | ||
| 741 | type Interrupt: Interrupt; | ||
| 742 | } | ||
| 743 | |||
| 744 | macro_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 | ||
| 3 | use core::future::{poll_fn, Future}; | 3 | use core::future::poll_fn; |
| 4 | use core::marker::PhantomData; | 4 | use core::marker::PhantomData; |
| 5 | use core::mem::MaybeUninit; | 5 | use core::mem::MaybeUninit; |
| 6 | use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; | 6 | use 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. |
| 29 | pub trait UsbSupply { | 29 | pub 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 | ||
| 38 | pub struct Driver<'d, T: Instance, P: UsbSupply> { | 34 | pub 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 | ||
| 291 | impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> { | 287 | impl<'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 | ||
| 714 | impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | 699 | impl<'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 | ||
| 729 | impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | 710 | impl<'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 | ||
| 751 | impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | 728 | impl<'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] |
| 16 | defmt = ["dep:defmt", "embassy-usb-driver?/defmt"] | 16 | defmt = ["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" | |||
| 53 | critical-section = "1.1" | 53 | critical-section = "1.1" |
| 54 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 54 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 55 | chrono = { version = "0.4", default-features = false, optional = true } | 55 | chrono = { version = "0.4", default-features = false, optional = true } |
| 56 | embedded-io = { version = "0.3.1", features = ["async"], optional = true } | 56 | embedded-io = { version = "0.4.0", features = ["async"], optional = true } |
| 57 | embedded-storage = { version = "0.3" } | 57 | embedded-storage = { version = "0.3" } |
| 58 | rand_core = "0.6.4" | ||
| 58 | 59 | ||
| 59 | rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] } | 60 | rp2040-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 | ||
| 62 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 63 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 63 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} | 64 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} |
| 64 | embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true} | 65 | embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} |
| 65 | embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} | 66 | embedded-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 @@ | |||
| 1 | use core::future::poll_fn; | ||
| 2 | use core::marker::PhantomData; | ||
| 3 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 4 | use core::task::Poll; | ||
| 5 | |||
| 6 | use embassy_hal_common::into_ref; | ||
| 7 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 8 | use embedded_hal_02::adc::{Channel, OneShot}; | ||
| 9 | |||
| 10 | use crate::interrupt::{self, InterruptExt}; | ||
| 11 | use crate::peripherals::ADC; | ||
| 12 | use crate::{pac, peripherals, Peripheral}; | ||
| 13 | static WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 14 | |||
| 15 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 16 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 17 | #[non_exhaustive] | ||
| 18 | pub enum Error { | ||
| 19 | // No errors for now | ||
| 20 | } | ||
| 21 | |||
| 22 | #[non_exhaustive] | ||
| 23 | pub struct Config {} | ||
| 24 | |||
| 25 | impl Default for Config { | ||
| 26 | fn default() -> Self { | ||
| 27 | Self {} | ||
| 28 | } | ||
| 29 | } | ||
| 30 | pub struct Adc<'d> { | ||
| 31 | phantom: PhantomData<&'d ADC>, | ||
| 32 | } | ||
| 33 | |||
| 34 | impl<'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 | |||
| 148 | macro_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 | |||
| 159 | impl_pin!(PIN_26, 0); | ||
| 160 | impl_pin!(PIN_27, 1); | ||
| 161 | impl_pin!(PIN_28, 2); | ||
| 162 | impl_pin!(PIN_29, 3); | ||
| 163 | |||
| 164 | impl<WORD, PIN> OneShot<Adc<'static>, WORD, PIN> for Adc<'static> | ||
| 165 | where | ||
| 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}; | |||
| 5 | const XOSC_MHZ: u32 = 12; | 5 | const XOSC_MHZ: u32 = 12; |
| 6 | 6 | ||
| 7 | /// safety: must be called exactly once at bootup | 7 | /// safety: must be called exactly once at bootup |
| 8 | pub unsafe fn init() { | 8 | pub(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. | ||
| 205 | pub struct RoscRng; | ||
| 206 | |||
| 207 | impl 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 | |||
| 219 | impl 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 { | |||
| 870 | mod eh1 { | 892 | mod 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"))] |
| 719 | mod nightly { | 719 | mod 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. |
| 5 | pub(crate) mod fmt; | 6 | pub(crate) mod fmt; |
| 6 | 7 | ||
| 7 | mod intrinsics; | 8 | mod intrinsics; |
| 8 | 9 | ||
| 10 | pub mod adc; | ||
| 9 | pub mod dma; | 11 | pub mod dma; |
| 10 | pub mod gpio; | 12 | pub mod gpio; |
| 11 | pub mod i2c; | 13 | pub mod i2c; |
| @@ -19,7 +21,7 @@ pub mod uart; | |||
| 19 | #[cfg(feature = "nightly")] | 21 | #[cfg(feature = "nightly")] |
| 20 | pub mod usb; | 22 | pub mod usb; |
| 21 | 23 | ||
| 22 | mod clocks; | 24 | pub mod clocks; |
| 23 | pub mod flash; | 25 | pub mod flash; |
| 24 | mod reset; | 26 | mod 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)] |
| 169 | pub enum RtcError { | 169 | pub 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"))] |
| 556 | mod eha { | 556 | mod 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 @@ | |||
| 1 | use core::future::{poll_fn, Future}; | 1 | use core::future::{poll_fn, Future}; |
| 2 | use core::task::{Poll, Waker}; | 2 | use core::slice; |
| 3 | use core::task::Poll; | ||
| 3 | 4 | ||
| 4 | use atomic_polyfill::{compiler_fence, Ordering}; | 5 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; |
| 5 | use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; | 6 | use embassy_hal_common::atomic_ring_buffer::RingBuffer; |
| 6 | use embassy_hal_common::ring_buffer::RingBuffer; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 7 | use embassy_sync::waitqueue::WakerRegistration; | ||
| 8 | 8 | ||
| 9 | use super::*; | 9 | use super::*; |
| 10 | 10 | ||
| 11 | pub struct State<'d, T: Instance>(StateStorage<FullStateInner<'d, T>>); | 11 | pub struct State { |
| 12 | impl<'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 | |||
| 18 | pub struct RxState<'d, T: Instance>(StateStorage<RxStateInner<'d, T>>); | ||
| 19 | impl<'d, T: Instance> RxState<'d, T> { | ||
| 20 | pub const fn new() -> Self { | ||
| 21 | Self(StateStorage::new()) | ||
| 22 | } | ||
| 23 | } | 16 | } |
| 24 | 17 | ||
| 25 | pub struct TxState<'d, T: Instance>(StateStorage<TxStateInner<'d, T>>); | 18 | impl State { |
| 26 | impl<'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 | ||
| 32 | struct RxStateInner<'d, T: Instance> { | ||
| 33 | phantom: PhantomData<&'d mut T>, | ||
| 34 | |||
| 35 | waker: WakerRegistration, | ||
| 36 | buf: RingBuffer<'d>, | ||
| 37 | } | ||
| 38 | |||
| 39 | struct TxStateInner<'d, T: Instance> { | ||
| 40 | phantom: PhantomData<&'d mut T>, | ||
| 41 | |||
| 42 | waker: WakerRegistration, | ||
| 43 | buf: RingBuffer<'d>, | ||
| 44 | } | ||
| 45 | |||
| 46 | struct FullStateInner<'d, T: Instance> { | ||
| 47 | rx: RxStateInner<'d, T>, | ||
| 48 | tx: TxStateInner<'d, T>, | ||
| 49 | } | ||
| 50 | |||
| 51 | unsafe impl<'d, T: Instance> Send for RxStateInner<'d, T> {} | ||
| 52 | unsafe impl<'d, T: Instance> Sync for RxStateInner<'d, T> {} | ||
| 53 | |||
| 54 | unsafe impl<'d, T: Instance> Send for TxStateInner<'d, T> {} | ||
| 55 | unsafe impl<'d, T: Instance> Sync for TxStateInner<'d, T> {} | ||
| 56 | |||
| 57 | unsafe impl<'d, T: Instance> Send for FullStateInner<'d, T> {} | ||
| 58 | unsafe impl<'d, T: Instance> Sync for FullStateInner<'d, T> {} | ||
| 59 | |||
| 60 | pub struct BufferedUart<'d, T: Instance> { | 29 | pub struct BufferedUart<'d, T: Instance> { |
| 61 | inner: PeripheralMutex<'d, FullStateInner<'d, T>>, | 30 | phantom: PhantomData<&'d mut T>, |
| 62 | } | 31 | } |
| 63 | 32 | ||
| 64 | pub struct BufferedUartRx<'d, T: Instance> { | 33 | pub struct BufferedUartRx<'d, T: Instance> { |
| 65 | inner: PeripheralMutex<'d, RxStateInner<'d, T>>, | 34 | phantom: PhantomData<&'d mut T>, |
| 66 | } | 35 | } |
| 67 | 36 | ||
| 68 | pub struct BufferedUartTx<'d, T: Instance> { | 37 | pub struct BufferedUartTx<'d, T: Instance> { |
| 69 | inner: PeripheralMutex<'d, TxStateInner<'d, T>>, | 38 | phantom: PhantomData<&'d mut T>, |
| 70 | } | 39 | } |
| 71 | 40 | ||
| 72 | impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {} | ||
| 73 | impl<'d, T: Instance> Unpin for BufferedUartRx<'d, T> {} | ||
| 74 | impl<'d, T: Instance> Unpin for BufferedUartTx<'d, T> {} | ||
| 75 | |||
| 76 | impl<'d, T: Instance> BufferedUart<'d, T> { | 41 | impl<'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 | ||
| 112 | impl<'d, T: Instance> BufferedUartRx<'d, T> { | 131 | impl<'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 | ||
| 140 | impl<'d, T: Instance> BufferedUartTx<'d, T> { | 231 | impl<'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 | ||
| 167 | impl<'d, T: Instance> PeripheralState for FullStateInner<'d, T> | 290 | fn write<'a>(buf: &'a [u8]) -> impl Future<Output = Result<usize, Error>> + 'a { |
| 168 | where | 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 | ||
| 178 | impl<'d, T: Instance> RxStateInner<'d, T> | 310 | fn flush() -> impl Future<Output = Result<(), Error>> { |
| 179 | where | 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>> { | 323 | impl<'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 { | 334 | impl<'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 | ||
| 223 | impl<'d, T: Instance> PeripheralState for RxStateInner<'d, T> | 345 | impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { |
| 224 | where | 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 | ||
| 284 | impl<'d, T: Instance> TxStateInner<'d, T> | 356 | pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) { |
| 285 | where | 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 | ||
| 313 | impl<'d, T: Instance> PeripheralState for TxStateInner<'d, T> | 397 | let mut rx_writer = s.rx_buf.writer(); |
| 314 | where | 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 | ||
| 357 | impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { | 441 | impl<'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 | ||
| 378 | impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUartRx<'d, T> { | 447 | impl<'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 | ||
| 399 | impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> { | 453 | impl<'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 | ||
| 421 | impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUartRx<'d, T> { | 463 | impl<'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 | ||
| 443 | impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { | 473 | impl<'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 | ||
| 467 | impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUartTx<'d, T> { | 483 | impl<'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; | |||
| 7 | use crate::gpio::AnyPin; | 7 | use crate::gpio::AnyPin; |
| 8 | use crate::{pac, peripherals, Peripheral}; | 8 | use crate::{pac, peripherals, Peripheral}; |
| 9 | 9 | ||
| 10 | #[cfg(feature = "nightly")] | ||
| 11 | mod buffered; | ||
| 12 | #[cfg(feature = "nightly")] | ||
| 13 | pub use buffered::{BufferedUart, BufferedUartRx, BufferedUartTx}; | ||
| 14 | |||
| 10 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 15 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 11 | pub enum DataBits { | 16 | pub 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> { | |||
| 273 | impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { | 278 | impl<'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")] | ||
| 615 | mod buffered; | ||
| 616 | #[cfg(feature = "nightly")] | ||
| 617 | pub use buffered::*; | ||
| 618 | |||
| 619 | mod sealed { | 625 | mod 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 @@ | |||
| 1 | use core::future::{poll_fn, Future}; | 1 | use core::future::poll_fn; |
| 2 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 3 | use core::slice; | 3 | use core::slice; |
| 4 | use core::sync::atomic::Ordering; | 4 | use core::sync::atomic::Ordering; |
| @@ -352,9 +352,7 @@ pub struct Bus<'d, T: Instance> { | |||
| 352 | } | 352 | } |
| 353 | 353 | ||
| 354 | impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | 354 | impl<'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 | ||
| 565 | impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | 546 | impl<'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 | ||
| 610 | impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | 587 | impl<'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 | ||
| 663 | impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | 636 | impl<'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 | ||
| 45 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 45 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 46 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} | 46 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} |
| 47 | embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true} | 47 | embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} |
| 48 | embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} | 48 | embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true} |
| 49 | 49 | ||
| 50 | embedded-storage = "0.3.0" | 50 | embedded-storage = "0.3.0" |
| @@ -67,7 +67,7 @@ nb = "1.0.0" | |||
| 67 | stm32-fmc = "0.2.4" | 67 | stm32-fmc = "0.2.4" |
| 68 | seq-macro = "0.3.0" | 68 | seq-macro = "0.3.0" |
| 69 | cfg-if = "1.0.0" | 69 | cfg-if = "1.0.0" |
| 70 | embedded-io = { version = "0.3.1", features = ["async"], optional = true } | 70 | embedded-io = { version = "0.4.0", features = ["async"], optional = true } |
| 71 | 71 | ||
| 72 | [build-dependencies] | 72 | [build-dependencies] |
| 73 | proc-macro2 = "1.0.36" | 73 | proc-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 @@ | |||
| 3 | use core::sync::atomic::{fence, Ordering}; | 3 | use core::sync::atomic::{fence, Ordering}; |
| 4 | use core::task::Waker; | 4 | use core::task::Waker; |
| 5 | 5 | ||
| 6 | use embassy_cortex_m::interrupt::Priority; | ||
| 6 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 7 | 8 | ||
| 8 | use super::{TransferOptions, Word, WordSize}; | 9 | use super::{TransferOptions, Word, WordSize}; |
| @@ -38,10 +39,12 @@ impl State { | |||
| 38 | static STATE: State = State::new(); | 39 | static STATE: State = State::new(); |
| 39 | 40 | ||
| 40 | /// safety: must be called only once | 41 | /// safety: must be called only once |
| 41 | pub(crate) unsafe fn init() { | 42 | pub(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 @@ | |||
| 1 | use core::sync::atomic::{fence, Ordering}; | 1 | use core::sync::atomic::{fence, Ordering}; |
| 2 | use core::task::Waker; | 2 | use core::task::Waker; |
| 3 | 3 | ||
| 4 | use embassy_cortex_m::interrupt::Priority; | ||
| 4 | use embassy_sync::waitqueue::AtomicWaker; | 5 | use embassy_sync::waitqueue::AtomicWaker; |
| 5 | 6 | ||
| 6 | use super::{Burst, FlowControl, Request, TransferOptions, Word, WordSize}; | 7 | use super::{Burst, FlowControl, Request, TransferOptions, Word, WordSize}; |
| @@ -67,10 +68,12 @@ impl State { | |||
| 67 | static STATE: State = State::new(); | 68 | static STATE: State = State::new(); |
| 68 | 69 | ||
| 69 | /// safety: must be called only once | 70 | /// safety: must be called only once |
| 70 | pub(crate) unsafe fn init() { | 71 | pub(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; | |||
| 12 | use core::pin::Pin; | 12 | use core::pin::Pin; |
| 13 | use core::task::{Context, Poll, Waker}; | 13 | use core::task::{Context, Poll, Waker}; |
| 14 | 14 | ||
| 15 | #[cfg(any(dma, bdma))] | ||
| 16 | use embassy_cortex_m::interrupt::Priority; | ||
| 15 | use embassy_hal_common::{impl_peripheral, into_ref}; | 17 | use embassy_hal_common::{impl_peripheral, into_ref}; |
| 16 | 18 | ||
| 17 | #[cfg(dmamux)] | 19 | #[cfg(dmamux)] |
| @@ -294,11 +296,11 @@ pub struct NoDma; | |||
| 294 | impl_peripheral!(NoDma); | 296 | impl_peripheral!(NoDma); |
| 295 | 297 | ||
| 296 | // safety: must be called only once at startup | 298 | // safety: must be called only once at startup |
| 297 | pub(crate) unsafe fn init() { | 299 | pub(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"))] |
| 169 | mod eha { | 169 | mod 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"))] |
| 1050 | mod eha { | 1050 | mod 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. |
| 5 | pub mod fmt; | 9 | pub mod fmt; |
| @@ -75,6 +79,8 @@ pub(crate) mod _generated { | |||
| 75 | // Reexports | 79 | // Reexports |
| 76 | pub use _generated::{peripherals, Peripherals}; | 80 | pub use _generated::{peripherals, Peripherals}; |
| 77 | pub use embassy_cortex_m::executor; | 81 | pub use embassy_cortex_m::executor; |
| 82 | #[cfg(any(dma, bdma))] | ||
| 83 | use embassy_cortex_m::interrupt::Priority; | ||
| 78 | pub use embassy_cortex_m::interrupt::_export::interrupt; | 84 | pub use embassy_cortex_m::interrupt::_export::interrupt; |
| 79 | pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | 85 | pub 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 | ||
| 92 | impl Default for Config { | 102 | impl 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; | |||
| 18 | use crate::time::Hertz; | 18 | use crate::time::Hertz; |
| 19 | use crate::{peripherals, Peripheral}; | 19 | use crate::{peripherals, Peripheral}; |
| 20 | 20 | ||
| 21 | /// Frequency used for SD Card initialization. Must be no higher than 400 kHz. | ||
| 22 | const 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}; | |||
| 8 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | 8 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; |
| 9 | 9 | ||
| 10 | use self::sealed::WordSize; | 10 | use self::sealed::WordSize; |
| 11 | use crate::dma::{slice_ptr_parts, NoDma, Transfer}; | 11 | use crate::dma::{slice_ptr_parts, Transfer}; |
| 12 | use crate::gpio::sealed::{AFType, Pin as _}; | 12 | use crate::gpio::sealed::{AFType, Pin as _}; |
| 13 | use crate::gpio::AnyPin; | 13 | use crate::gpio::AnyPin; |
| 14 | use crate::pac::spi::{regs, vals, Spi as Regs}; | 14 | use 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"))] |
| 887 | mod eha { | 887 | mod 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 @@ | |||
| 1 | use core::cell::RefCell; | 1 | use core::cell::RefCell; |
| 2 | use core::future::{poll_fn, Future}; | 2 | use core::future::poll_fn; |
| 3 | use core::task::Poll; | 3 | use core::task::Poll; |
| 4 | 4 | ||
| 5 | use atomic_polyfill::{compiler_fence, Ordering}; | 5 | use 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 | ||
| 341 | impl<'d, T: BasicInstance> embedded_io::asynch::Read for BufferedUart<'d, T> { | 344 | impl<'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 | ||
| 351 | impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Read for BufferedUartRx<'u, 'd, T> { | 350 | impl<'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 | ||
| 361 | impl<'d, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUart<'d, T> { | 356 | impl<'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 | ||
| 375 | impl<'u, 'd, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUartRx<'u, 'd, T> { | 366 | impl<'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 | ||
| 389 | impl<'d, T: BasicInstance> embedded_io::asynch::Write for BufferedUart<'d, T> { | 376 | impl<'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 | ||
| 407 | impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Write for BufferedUartTx<'u, 'd, T> { | 386 | impl<'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 | ||
| 3 | use core::future::{poll_fn, Future}; | 3 | use core::future::poll_fn; |
| 4 | use core::marker::PhantomData; | 4 | use core::marker::PhantomData; |
| 5 | use core::sync::atomic::Ordering; | 5 | use core::sync::atomic::Ordering; |
| 6 | use core::task::Poll; | 6 | use core::task::Poll; |
| @@ -429,9 +429,7 @@ pub struct Bus<'d, T: Instance> { | |||
| 429 | } | 429 | } |
| 430 | 430 | ||
| 431 | impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | 431 | impl<'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 | ||
| 726 | impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | 706 | impl<'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 | ||
| 769 | impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | 745 | impl<'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 | ||
| 825 | impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | 797 | impl<'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> { | |||
| 13 | const MAX_RL: u16 = 0xFFF; | 13 | const 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 |
| 16 | const fn max_timeout(prescaler: u8) -> u32 { | 16 | const 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 |
| 21 | const fn reload_value(prescaler: u8, timeout_us: u32) -> u16 { | 21 | const 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" | |||
| 35 | critical-section = "1.1" | 35 | critical-section = "1.1" |
| 36 | heapless = "0.7.5" | 36 | heapless = "0.7.5" |
| 37 | cfg-if = "1.0.0" | 37 | cfg-if = "1.0.0" |
| 38 | embedded-io = "0.3.1" | 38 | embedded-io = "0.4.0" |
| 39 | 39 | ||
| 40 | [dev-dependencies] | 40 | [dev-dependencies] |
| 41 | futures-executor = { version = "0.3.17", features = [ "thread-pool" ] } | 41 | futures-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 | |||
| 352 | mod io_impls { | 352 | mod 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 | ||
| 59 | impl<M, T> Default for Signal<M, T> | ||
| 60 | where | ||
| 61 | M: RawMutex, | ||
| 62 | { | ||
| 63 | fn default() -> Self { | ||
| 64 | Self::new() | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 59 | impl<M, T: Send> Signal<M, T> | 68 | impl<M, T: Send> Signal<M, T> |
| 60 | where | 69 | where |
| 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; | |||
| 6 | use crate::blocking_mutex::Mutex; | 6 | use 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)] |
| 10 | pub struct WakerRegistration { | 10 | pub 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 | ||
| 135 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } | 135 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } |
| 136 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} | 136 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true} |
| 137 | embedded-hal-async = { version = "=0.1.0-alpha.3", optional = true} | 137 | embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true} |
| 138 | 138 | ||
| 139 | futures-util = { version = "0.3.17", default-features = false } | 139 | futures-util = { version = "0.3.17", default-features = false } |
| 140 | embassy-sync = { version = "0.1", path = "../embassy-sync" } | 140 | embassy-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"))] |
| 35 | mod eha { | 35 | mod 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)] | |
| 3 | use 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 | ||
| 157 | pub trait Bus { | 157 | pub 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 | ||
| 215 | pub trait Endpoint { | 202 | pub 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 | ||
| 227 | pub trait EndpointOut: Endpoint { | 210 | pub 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 | ||
| 239 | pub trait ControlPipe { | 218 | pub 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 | ||
| 284 | pub trait EndpointIn: Endpoint { | 247 | pub 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] | ||
| 2 | name = "embassy-usb-logger" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | |||
| 6 | [dependencies] | ||
| 7 | embassy-usb = { version = "0.1.0", path = "../embassy-usb" } | ||
| 8 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } | ||
| 9 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } | ||
| 10 | futures = { version = "0.3", default-features = false } | ||
| 11 | static_cell = "1" | ||
| 12 | usbd-hid = "0.6.0" | ||
| 13 | log = "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 | |||
| 3 | USB implementation of the `log` crate. This logger can be used by any device that implements `embassy-usb`. When running, | ||
| 4 | it will output all logging done through the `log` facade to the USB serial peripheral. | ||
| 5 | |||
| 6 | ## Usage | ||
| 7 | |||
| 8 | Add 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] | ||
| 12 | async 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 | |||
| 5 | use core::fmt::Write as _; | ||
| 6 | |||
| 7 | use embassy_futures::join::join; | ||
| 8 | use embassy_sync::pipe::Pipe; | ||
| 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||
| 10 | use embassy_usb::driver::Driver; | ||
| 11 | use embassy_usb::{Builder, Config}; | ||
| 12 | use log::{Metadata, Record}; | ||
| 13 | |||
| 14 | type CS = embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 15 | |||
| 16 | /// The logger state containing buffers that must live as long as the USB peripheral. | ||
| 17 | pub 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 | |||
| 25 | impl<'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. | ||
| 39 | pub struct UsbLogger<const N: usize> { | ||
| 40 | buffer: Pipe<CS, N>, | ||
| 41 | } | ||
| 42 | |||
| 43 | impl<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 | |||
| 101 | impl<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 | |||
| 115 | struct Writer<'d, const N: usize>(&'d Pipe<CS, N>); | ||
| 116 | |||
| 117 | impl<'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] | ||
| 138 | macro_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" } | |||
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
| 16 | defmt-rtt = { version = "0.3", optional = true } | 16 | defmt-rtt = { version = "0.4", optional = true } |
| 17 | panic-reset = { version = "0.1.1" } | 17 | panic-reset = { version = "0.1.1" } |
| 18 | embedded-hal = { version = "0.2.6" } | 18 | embedded-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] | ||
| 2 | build-std = ["core"] | ||
| 3 | build-std-features = ["panic_immediate_abort"] | ||
| 4 | |||
| 5 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 6 | runner = "probe-run --chip RP2040" | ||
| 7 | |||
| 8 | [build] | ||
| 9 | target = "thumbv6m-none-eabi" | ||
| 10 | |||
| 11 | [env] | ||
| 12 | DEFMT_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] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-boot-rp-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync" } | ||
| 9 | embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } | ||
| 10 | embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly"] } | ||
| 11 | embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", "unstable-traits", "nightly"] } | ||
| 12 | embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp" } | ||
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | ||
| 14 | |||
| 15 | defmt = "0.3" | ||
| 16 | defmt-rtt = "0.4" | ||
| 17 | panic-probe = { version = "0.3", features = ["print-defmt"], optional = true } | ||
| 18 | panic-reset = { version = "0.1.1", optional = true } | ||
| 19 | embedded-hal = { version = "0.2.6" } | ||
| 20 | |||
| 21 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | ||
| 22 | cortex-m-rt = "0.7.0" | ||
| 23 | |||
| 24 | [features] | ||
| 25 | default = ["panic-reset"] | ||
| 26 | debug = [ | ||
| 27 | "embassy-rp/defmt", | ||
| 28 | "embassy-boot-rp/defmt", | ||
| 29 | "panic-probe" | ||
| 30 | ] | ||
| 31 | |||
| 32 | [profile.release] | ||
| 33 | debug = 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 | |||
| 3 | Example for Raspberry Pi Pico demonstrating the bootloader. The example consists of application binaries, 'a' | ||
| 4 | which waits for 5 seconds before flashing the 'b' binary, which blinks the LED. | ||
| 5 | |||
| 6 | NOTE: 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 | ||
| 18 | cargo flash --manifest-path ../../bootloader/rp/Cargo.toml --release --chip RP2040 | ||
| 19 | |||
| 20 | # Build 'b' | ||
| 21 | cargo build --release --bin b | ||
| 22 | |||
| 23 | # Generate binary for 'b' | ||
| 24 | cargo objcopy --release --bin b -- -O binary b.bin | ||
| 25 | |||
| 26 | # Flash `a` (which includes b.bin) | ||
| 27 | cargo 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 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn 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 @@ | |||
| 1 | MEMORY | ||
| 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 | |||
| 5 | use defmt_rtt as _; | ||
| 6 | use embassy_boot_rp::*; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_rp::flash::Flash; | ||
| 9 | use embassy_rp::gpio::{Level, Output}; | ||
| 10 | use embassy_time::{Duration, Timer}; | ||
| 11 | #[cfg(feature = "panic-probe")] | ||
| 12 | use panic_probe as _; | ||
| 13 | #[cfg(feature = "panic-reset")] | ||
| 14 | use panic_reset as _; | ||
| 15 | |||
| 16 | static APP_B: &[u8] = include_bytes!("../../b.bin"); | ||
| 17 | const FLASH_SIZE: usize = 2 * 1024 * 1024; | ||
| 18 | |||
| 19 | #[embassy_executor::main] | ||
| 20 | async 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 | |||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_rp::gpio; | ||
| 7 | use embassy_time::{Duration, Timer}; | ||
| 8 | use gpio::{Level, Output}; | ||
| 9 | use {defmt_rtt as _, panic_reset as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async 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 | |||
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
| 16 | defmt-rtt = { version = "0.3", optional = true } | 16 | defmt-rtt = { version = "0.4", optional = true } |
| 17 | panic-reset = { version = "0.1.1" } | 17 | panic-reset = { version = "0.1.1" } |
| 18 | embedded-hal = { version = "0.2.6" } | 18 | embedded-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 | |||
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
| 16 | defmt-rtt = { version = "0.3", optional = true } | 16 | defmt-rtt = { version = "0.4", optional = true } |
| 17 | panic-reset = { version = "0.1.1" } | 17 | panic-reset = { version = "0.1.1" } |
| 18 | embedded-hal = { version = "0.2.6" } | 18 | embedded-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 | |||
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
| 16 | defmt-rtt = { version = "0.3", optional = true } | 16 | defmt-rtt = { version = "0.4", optional = true } |
| 17 | panic-reset = { version = "0.1.1" } | 17 | panic-reset = { version = "0.1.1" } |
| 18 | embedded-hal = { version = "0.2.6" } | 18 | embedded-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 | |||
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
| 16 | defmt-rtt = { version = "0.3", optional = true } | 16 | defmt-rtt = { version = "0.4", optional = true } |
| 17 | panic-reset = { version = "0.1.1" } | 17 | panic-reset = { version = "0.1.1" } |
| 18 | embedded-hal = { version = "0.2.6" } | 18 | embedded-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 | |||
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
| 16 | defmt-rtt = { version = "0.3", optional = true } | 16 | defmt-rtt = { version = "0.4", optional = true } |
| 17 | panic-reset = { version = "0.1.1" } | 17 | panic-reset = { version = "0.1.1" } |
| 18 | embedded-hal = { version = "0.2.6" } | 18 | embedded-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 | |||
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
| 16 | defmt-rtt = { version = "0.3", optional = true } | 16 | defmt-rtt = { version = "0.4", optional = true } |
| 17 | panic-reset = { version = "0.1.1" } | 17 | panic-reset = { version = "0.1.1" } |
| 18 | embedded-hal = { version = "0.2.6" } | 18 | embedded-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 | |||
| 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } |
| 14 | 14 | ||
| 15 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
| 16 | defmt-rtt = { version = "0.3", optional = true } | 16 | defmt-rtt = { version = "0.4", optional = true } |
| 17 | panic-reset = { version = "0.1.1" } | 17 | panic-reset = { version = "0.1.1" } |
| 18 | embedded-hal = { version = "0.2.6" } | 18 | embedded-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] |
| 9 | defmt = { version = "0.3", optional = true } | 9 | defmt = { version = "0.3", optional = true } |
| 10 | defmt-rtt = { version = "0.3", optional = true } | 10 | defmt-rtt = { version = "0.4", optional = true } |
| 11 | 11 | ||
| 12 | embassy-nrf = { path = "../../../../embassy-nrf", default-features = false, features = ["nightly"] } | 12 | embassy-nrf = { path = "../../../../embassy-nrf", default-features = false, features = ["nightly"] } |
| 13 | embassy-boot-nrf = { path = "../../../../embassy-boot/nrf", default-features = false } | 13 | embassy-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"))'] | ||
| 2 | runner = "probe-run --chip RP2040" | ||
| 3 | |||
| 4 | [build] | ||
| 5 | target = "thumbv6m-none-eabi" | ||
| 6 | |||
| 7 | [env] | ||
| 8 | DEFMT_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] | ||
| 2 | edition = "2021" | ||
| 3 | name = "rp-bootloader-example" | ||
| 4 | version = "0.1.0" | ||
| 5 | description = "Example bootloader for RP2040 chips" | ||
| 6 | license = "MIT OR Apache-2.0" | ||
| 7 | |||
| 8 | [dependencies] | ||
| 9 | defmt = { version = "0.3", optional = true } | ||
| 10 | defmt-rtt = { version = "0.4", optional = true } | ||
| 11 | |||
| 12 | embassy-rp = { path = "../../../../embassy-rp", default-features = false, features = ["nightly"] } | ||
| 13 | embassy-boot-rp = { path = "../../../../embassy-boot/rp", default-features = false } | ||
| 14 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | ||
| 15 | cortex-m-rt = { version = "0.7" } | ||
| 16 | embedded-storage = "0.3.0" | ||
| 17 | embedded-storage-async = "0.3.0" | ||
| 18 | cfg-if = "1.0.0" | ||
| 19 | |||
| 20 | [features] | ||
| 21 | defmt = [ | ||
| 22 | "dep:defmt", | ||
| 23 | "embassy-boot-rp/defmt", | ||
| 24 | "embassy-rp/defmt", | ||
| 25 | ] | ||
| 26 | debug = ["defmt-rtt", "defmt"] | ||
| 27 | |||
| 28 | [profile.release] | ||
| 29 | debug = 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 | |||
| 3 | The bootloader uses `embassy-boot` to interact with the flash. | ||
| 4 | |||
| 5 | # Usage | ||
| 6 | |||
| 7 | Flashing the bootloader | ||
| 8 | |||
| 9 | ``` | ||
| 10 | cargo flash --release --chip RP2040 | ||
| 11 | ``` | ||
| 12 | |||
| 13 | To debug, use `cargo run` and enable the debug feature flag | ||
| 14 | |||
| 15 | ``` rust | ||
| 16 | cargo 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 @@ | |||
| 1 | use std::env; | ||
| 2 | use std::fs::File; | ||
| 3 | use std::io::Write; | ||
| 4 | use std::path::PathBuf; | ||
| 5 | |||
| 6 | fn 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 @@ | |||
| 1 | MEMORY | ||
| 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 | |||
| 4 | use cortex_m_rt::{entry, exception}; | ||
| 5 | #[cfg(feature = "defmt")] | ||
| 6 | use defmt_rtt as _; | ||
| 7 | use embassy_boot_rp::*; | ||
| 8 | use embassy_rp::flash::{Flash, ERASE_SIZE}; | ||
| 9 | use embassy_rp::peripherals::FLASH; | ||
| 10 | |||
| 11 | const FLASH_SIZE: usize = 2 * 1024 * 1024; | ||
| 12 | |||
| 13 | #[entry] | ||
| 14 | fn 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")] | ||
| 36 | unsafe extern "C" fn HardFault() { | ||
| 37 | cortex_m::peripheral::SCB::sys_reset(); | ||
| 38 | } | ||
| 39 | |||
| 40 | #[exception] | ||
| 41 | unsafe 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] | ||
| 49 | fn 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] |
| 9 | defmt = { version = "0.3", optional = true } | 9 | defmt = { version = "0.3", optional = true } |
| 10 | defmt-rtt = { version = "0.3", optional = true } | 10 | defmt-rtt = { version = "0.4", optional = true } |
| 11 | 11 | ||
| 12 | embassy-stm32 = { path = "../../../../embassy-stm32", default-features = false, features = ["nightly"] } | 12 | embassy-stm32 = { path = "../../../../embassy-stm32", default-features = false, features = ["nightly"] } |
| 13 | embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32", default-features = false } | 13 | embassy-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 | |||
| 17 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } | 17 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } |
| 18 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true } | 18 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true } |
| 19 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } | 19 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } |
| 20 | embedded-io = "0.3.1" | 20 | embedded-io = "0.4.0" |
| 21 | embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true } | 21 | embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true } |
| 22 | 22 | ||
| 23 | lorawan-device = { version = "0.8.0", default-features = false, features = ["async"], optional = true } | 23 | lorawan-device = { version = "0.8.0", default-features = false, features = ["async"], optional = true } |
| 24 | lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"], optional = true } | 24 | lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"], optional = true } |
| 25 | 25 | ||
| 26 | defmt = "0.3" | 26 | defmt = "0.3" |
| 27 | defmt-rtt = "0.3" | 27 | defmt-rtt = "0.4" |
| 28 | 28 | ||
| 29 | static_cell = "1.0" | 29 | static_cell = "1.0" |
| 30 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 30 | cortex-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 | |||
| 34 | rand = { version = "0.8.4", default-features = false } | 34 | rand = { version = "0.8.4", default-features = false } |
| 35 | embedded-storage = "0.3.0" | 35 | embedded-storage = "0.3.0" |
| 36 | usbd-hid = "0.6.0" | 36 | usbd-hid = "0.6.0" |
| 37 | serde = { version = "1.0.136", default-features = false } | 37 | serde = { 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 | |||
| 5 | use core::f32::consts::PI; | ||
| 6 | |||
| 7 | use defmt::{error, info}; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S}; | ||
| 10 | use embassy_nrf::interrupt; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | type Sample = i16; | ||
| 14 | |||
| 15 | const NUM_BUFFERS: usize = 2; | ||
| 16 | const NUM_SAMPLES: usize = 4; | ||
| 17 | |||
| 18 | #[embassy_executor::main] | ||
| 19 | async 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 | |||
| 60 | struct SineOsc { | ||
| 61 | amplitude: f32, | ||
| 62 | modulo: f32, | ||
| 63 | phase_inc: f32, | ||
| 64 | } | ||
| 65 | |||
| 66 | impl 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] | ||
| 106 | fn abs(value: f32) -> f32 { | ||
| 107 | if value < 0.0 { | ||
| 108 | -value | ||
| 109 | } else { | ||
| 110 | value | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | #[inline] | ||
| 115 | fn 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 | |||
| 5 | use defmt::{debug, error, info}; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; | ||
| 8 | use embassy_nrf::interrupt; | ||
| 9 | use embassy_nrf::pwm::{Prescaler, SimplePwm}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | type Sample = i16; | ||
| 13 | |||
| 14 | const NUM_SAMPLES: usize = 500; | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async 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 | ||
| 61 | fn 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 | |||
| 74 | pub struct RmsOnline<const N: usize> { | ||
| 75 | pub squares: [f32; N], | ||
| 76 | pub head: usize, | ||
| 77 | } | ||
| 78 | |||
| 79 | impl<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 | |||
| 88 | impl<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 | |||
| 5 | use core::f32::consts::PI; | ||
| 6 | |||
| 7 | use defmt::{error, info}; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; | ||
| 10 | use embassy_nrf::interrupt; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | type Sample = i16; | ||
| 14 | |||
| 15 | const NUM_SAMPLES: usize = 50; | ||
| 16 | |||
| 17 | #[embassy_executor::main] | ||
| 18 | async 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 | |||
| 50 | struct Waveform { | ||
| 51 | inv_sample_rate: f32, | ||
| 52 | carrier: SineOsc, | ||
| 53 | freq_mod: SineOsc, | ||
| 54 | amp_mod: SineOsc, | ||
| 55 | } | ||
| 56 | |||
| 57 | impl 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 | |||
| 94 | struct SineOsc { | ||
| 95 | amplitude: f32, | ||
| 96 | modulo: f32, | ||
| 97 | phase_inc: f32, | ||
| 98 | } | ||
| 99 | |||
| 100 | impl 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] | ||
| 140 | fn abs(value: f32) -> f32 { | ||
| 141 | if value < 0.0 { | ||
| 142 | -value | ||
| 143 | } else { | ||
| 144 | value | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | #[inline] | ||
| 149 | fn 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 | |||
| 5 | use defmt::info; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_nrf::interrupt; | ||
| 8 | use embassy_nrf::spis::{Config, Spis}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async 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 | |||
| 7 | use defmt::*; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_nrf::interrupt; | ||
| 10 | use embassy_nrf::twis::{self, Command, Twis}; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async 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" | |||
| 13 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 13 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
| 14 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } | 14 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } |
| 15 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 15 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 16 | embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" } | ||
| 16 | 17 | ||
| 17 | defmt = "0.3" | 18 | defmt = "0.3" |
| 18 | defmt-rtt = "0.3" | 19 | defmt-rtt = "0.4" |
| 19 | 20 | ||
| 20 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 21 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 21 | cortex-m-rt = "0.7.0" | 22 | cortex-m-rt = "0.7.0" |
| @@ -28,10 +29,11 @@ display-interface = "0.4.1" | |||
| 28 | byte-slice-cast = { version = "1.2.0", default-features = false } | 29 | byte-slice-cast = { version = "1.2.0", default-features = false } |
| 29 | 30 | ||
| 30 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 31 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } |
| 31 | embedded-hal-async = { version = "0.1.0-alpha.3" } | 32 | embedded-hal-async = "0.2.0-alpha.0" |
| 32 | embedded-io = { version = "0.3.1", features = ["async", "defmt"] } | 33 | embedded-io = { version = "0.4.0", features = ["async", "defmt"] } |
| 33 | embedded-storage = { version = "0.3" } | 34 | embedded-storage = { version = "0.3" } |
| 34 | static_cell = "1.0.0" | 35 | static_cell = "1.0.0" |
| 36 | log = "0.4" | ||
| 35 | 37 | ||
| 36 | [profile.release] | 38 | [profile.release] |
| 37 | debug = true | 39 | debug = 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 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::adc::{Adc, Config}; | ||
| 8 | use embassy_rp::interrupt; | ||
| 9 | use embassy_time::{Duration, Timer}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async 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 | |||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_rp::interrupt; | ||
| 7 | use embassy_rp::peripherals::USB; | ||
| 8 | use embassy_rp::usb::Driver; | ||
| 9 | use embassy_time::{Duration, Timer}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::task] | ||
| 13 | async fn logger_task(driver: Driver<'static, USB>) { | ||
| 14 | embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver); | ||
| 15 | } | ||
| 16 | |||
| 17 | #[embassy_executor::main] | ||
| 18 | async 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 | |||
| 9 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "std", "nightly", "integrated-timers"] } | 9 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "std", "nightly", "integrated-timers"] } |
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] } |
| 11 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dhcpv4", "pool-16"] } | 11 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dhcpv4", "pool-16"] } |
| 12 | embedded-io = { version = "0.3.1", features = ["async", "std", "futures"] } | 12 | embedded-io = { version = "0.4.0", features = ["async", "std", "futures"] } |
| 13 | critical-section = { version = "1.1", features = ["std"] } | 13 | critical-section = { version = "1.1", features = ["std"] } |
| 14 | 14 | ||
| 15 | async-io = "1.6.0" | 15 | async-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] |
| 2 | runner = 'probe-run --chip STM32F030F4Px' | 2 | runner = 'probe-run --chip STM32F091RCTX' |
| 3 | 3 | ||
| 4 | [build] | 4 | [build] |
| 5 | target = "thumbv6m-none-eabi" | 5 | target = "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" | |||
| 10 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 10 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 11 | cortex-m-rt = "0.7.0" | 11 | cortex-m-rt = "0.7.0" |
| 12 | defmt = "0.3" | 12 | defmt = "0.3" |
| 13 | defmt-rtt = "0.3" | 13 | defmt-rtt = "0.4" |
| 14 | panic-probe = "0.3" | 14 | panic-probe = "0.3" |
| 15 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } | 15 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } |
| 16 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } | 16 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } |
| 17 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 17 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 18 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f030f4", "time-driver-any"] } | 18 | embassy-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 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 8 | use embassy_time::{Duration, Timer}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | // main is itself an async function. | ||
| 12 | #[embassy_executor::main] | ||
| 13 | async 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 | |||
| 13 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 13 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 14 | 14 | ||
| 15 | defmt = "0.3" | 15 | defmt = "0.3" |
| 16 | defmt-rtt = "0.3" | 16 | defmt-rtt = "0.4" |
| 17 | 17 | ||
| 18 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 18 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 19 | cortex-m-rt = "0.7.0" | 19 | cortex-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 | |||
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } |
| 12 | 12 | ||
| 13 | defmt = "0.3" | 13 | defmt = "0.3" |
| 14 | defmt-rtt = "0.3" | 14 | defmt-rtt = "0.4" |
| 15 | 15 | ||
| 16 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 16 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 17 | cortex-m-rt = "0.7.0" | 17 | cortex-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 | |||
| 13 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 13 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 14 | 14 | ||
| 15 | defmt = "0.3" | 15 | defmt = "0.3" |
| 16 | defmt-rtt = "0.3" | 16 | defmt-rtt = "0.4" |
| 17 | 17 | ||
| 18 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 18 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 19 | cortex-m-rt = "0.7.0" | 19 | cortex-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 | |||
| 12 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] } | 12 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] } |
| 13 | 13 | ||
| 14 | defmt = "0.3" | 14 | defmt = "0.3" |
| 15 | defmt-rtt = "0.3" | 15 | defmt-rtt = "0.4" |
| 16 | 16 | ||
| 17 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 17 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 18 | cortex-m-rt = "0.7.0" | 18 | cortex-m-rt = "0.7.0" |
| 19 | embedded-hal = "0.2.6" | 19 | embedded-hal = "0.2.6" |
| 20 | embedded-io = "0.3.1" | 20 | embedded-io = "0.4.0" |
| 21 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 21 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 22 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 22 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 23 | heapless = { version = "0.7.5", default-features = false } | 23 | heapless = { 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 | |||
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "net", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "net", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] } |
| 12 | embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } | 12 | embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } |
| 13 | embedded-io = { version = "0.3.1", features = ["async"] } | 13 | embedded-io = { version = "0.4.0", features = ["async"] } |
| 14 | 14 | ||
| 15 | defmt = "0.3" | 15 | defmt = "0.3" |
| 16 | defmt-rtt = "0.3" | 16 | defmt-rtt = "0.4" |
| 17 | 17 | ||
| 18 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 18 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 19 | cortex-m-rt = "0.7.0" | 19 | cortex-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 | |||
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] } |
| 12 | 12 | ||
| 13 | defmt = "0.3" | 13 | defmt = "0.3" |
| 14 | defmt-rtt = "0.3" | 14 | defmt-rtt = "0.4" |
| 15 | 15 | ||
| 16 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 16 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 17 | cortex-m-rt = "0.7.0" | 17 | cortex-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 = [" | |||
| 12 | embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } | 12 | embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } |
| 13 | 13 | ||
| 14 | defmt = "0.3" | 14 | defmt = "0.3" |
| 15 | defmt-rtt = "0.3" | 15 | defmt-rtt = "0.4" |
| 16 | 16 | ||
| 17 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 17 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 18 | cortex-m-rt = "0.7.0" | 18 | cortex-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 | |||
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } |
| 12 | embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16", "unstable-traits"] } | 12 | embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16", "unstable-traits"] } |
| 13 | embedded-io = { version = "0.3.1", features = ["async"] } | 13 | embedded-io = { version = "0.4.0", features = ["async"] } |
| 14 | 14 | ||
| 15 | defmt = "0.3" | 15 | defmt = "0.3" |
| 16 | defmt-rtt = "0.3" | 16 | defmt-rtt = "0.4" |
| 17 | 17 | ||
| 18 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 18 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 19 | cortex-m-rt = "0.7.0" | 19 | cortex-m-rt = "0.7.0" |
| 20 | embedded-hal = "0.2.6" | 20 | embedded-hal = "0.2.6" |
| 21 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 21 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } |
| 22 | embedded-hal-async = { version = "=0.1.0-alpha.3" } | 22 | embedded-hal-async = { version = "=0.2.0-alpha.0" } |
| 23 | embedded-nal-async = "0.2.0" | 23 | embedded-nal-async = "0.3.0" |
| 24 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 24 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 25 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 25 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 26 | heapless = { version = "0.7.5", default-features = false } | 26 | heapless = { 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 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::wdg::IndependentWatchdog; | ||
| 8 | use embassy_time::{Duration, Timer}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async 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 | |||
| 19 | lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"], optional = true } | 19 | lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"], optional = true } |
| 20 | 20 | ||
| 21 | defmt = "0.3" | 21 | defmt = "0.3" |
| 22 | defmt-rtt = "0.3" | 22 | defmt-rtt = "0.4" |
| 23 | 23 | ||
| 24 | embedded-storage = "0.3.0" | 24 | embedded-storage = "0.3.0" |
| 25 | embedded-io = "0.3.1" | 25 | embedded-io = "0.4.0" |
| 26 | 26 | ||
| 27 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 27 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 28 | cortex-m-rt = "0.7.0" | 28 | cortex-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 | |||
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } |
| 12 | 12 | ||
| 13 | defmt = "0.3" | 13 | defmt = "0.3" |
| 14 | defmt-rtt = "0.3" | 14 | defmt-rtt = "0.4" |
| 15 | 15 | ||
| 16 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 16 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 17 | cortex-m-rt = "0.7.0" | 17 | cortex-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" | |||
| 14 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits"] } | 14 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits"] } |
| 15 | 15 | ||
| 16 | defmt = "0.3" | 16 | defmt = "0.3" |
| 17 | defmt-rtt = "0.3" | 17 | defmt-rtt = "0.4" |
| 18 | 18 | ||
| 19 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 19 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 20 | cortex-m-rt = "0.7.0" | 20 | cortex-m-rt = "0.7.0" |
| 21 | embedded-hal = "0.2.6" | 21 | embedded-hal = "0.2.6" |
| 22 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 22 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } |
| 23 | embedded-hal-async = { version = "=0.1.0-alpha.3" } | 23 | embedded-hal-async = { version = "=0.2.0-alpha.0" } |
| 24 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 24 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 25 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 25 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 26 | heapless = { version = "0.7.5", default-features = false } | 26 | heapless = { 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" } | |||
| 17 | usbd-hid = "0.6.0" | 17 | usbd-hid = "0.6.0" |
| 18 | 18 | ||
| 19 | defmt = "0.3" | 19 | defmt = "0.3" |
| 20 | defmt-rtt = "0.3" | 20 | defmt-rtt = "0.4" |
| 21 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 21 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 22 | 22 | ||
| 23 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 23 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| @@ -26,5 +26,5 @@ embedded-hal = "0.2.6" | |||
| 26 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 26 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 27 | heapless = { version = "0.7.5", default-features = false } | 27 | heapless = { version = "0.7.5", default-features = false } |
| 28 | rand_core = { version = "0.6.3", default-features = false } | 28 | rand_core = { version = "0.6.3", default-features = false } |
| 29 | embedded-io = { version = "0.3.1", features = ["async"] } | 29 | embedded-io = { version = "0.4.0", features = ["async"] } |
| 30 | static_cell = "1.0" | 30 | static_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 | |||
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } |
| 12 | 12 | ||
| 13 | defmt = "0.3" | 13 | defmt = "0.3" |
| 14 | defmt-rtt = "0.3" | 14 | defmt-rtt = "0.4" |
| 15 | 15 | ||
| 16 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 16 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 17 | cortex-m-rt = "0.7.0" | 17 | cortex-m-rt = "0.7.0" |
| @@ -21,8 +21,3 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa | |||
| 21 | heapless = { version = "0.7.5", default-features = false } | 21 | heapless = { version = "0.7.5", default-features = false } |
| 22 | 22 | ||
| 23 | micromath = "2.0.0" | 23 | micromath = "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 | |||
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55cc", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55cc", "time-driver-any", "exti"] } |
| 12 | 12 | ||
| 13 | defmt = "0.3" | 13 | defmt = "0.3" |
| 14 | defmt-rtt = "0.3" | 14 | defmt-rtt = "0.4" |
| 15 | 15 | ||
| 16 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 16 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 17 | cortex-m-rt = "0.7.0" | 17 | cortex-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 | |||
| 15 | lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"] } | 15 | lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"] } |
| 16 | 16 | ||
| 17 | defmt = "0.3" | 17 | defmt = "0.3" |
| 18 | defmt-rtt = "0.3" | 18 | defmt-rtt = "0.4" |
| 19 | 19 | ||
| 20 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 20 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 21 | cortex-m-rt = "0.7.0" | 21 | cortex-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] |
| 4 | channel = "nightly-2022-10-25" | 4 | channel = "nightly-2022-11-22" |
| 5 | components = [ "rust-src", "rustfmt" ] | 5 | components = [ "rust-src", "rustfmt" ] |
| 6 | targets = [ | 6 | targets = [ |
| 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 | |||
| 12 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 12 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 13 | 13 | ||
| 14 | defmt = "0.3.0" | 14 | defmt = "0.3.0" |
| 15 | defmt-rtt = "0.3.0" | 15 | defmt-rtt = "0.4" |
| 16 | 16 | ||
| 17 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 17 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 18 | cortex-m-rt = "0.7.0" | 18 | cortex-m-rt = "0.7.0" |
| 19 | embedded-hal = "0.2.6" | 19 | embedded-hal = "0.2.6" |
| 20 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 20 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } |
| 21 | embedded-hal-async = { version = "=0.1.0-alpha.3" } | 21 | embedded-hal-async = { version = "=0.2.0-alpha.0" } |
| 22 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } | 22 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } |
| 23 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 23 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 24 | embedded-io = { version = "0.3.1", features = ["async"] } | 24 | embedded-io = { version = "0.4.0", features = ["async"] } |
| 25 | embedded-storage = { version = "0.3" } | 25 | embedded-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 @@ | |||
| 5 | use defmt::{assert_eq, *}; | 5 | use defmt::{assert_eq, *}; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_rp::interrupt; | 7 | use embassy_rp::interrupt; |
| 8 | use embassy_rp::uart::{BufferedUart, Config, State, Uart}; | 8 | use embassy_rp::uart::{BufferedUart, Config}; |
| 9 | use embedded_io::asynch::{Read, Write}; | 9 | use embedded_io::asynch::{Read, Write}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {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 | |||
| 20 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-tim2"] } | 20 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-tim2"] } |
| 21 | 21 | ||
| 22 | defmt = "0.3.0" | 22 | defmt = "0.3.0" |
| 23 | defmt-rtt = "0.3.0" | 23 | defmt-rtt = "0.4" |
| 24 | 24 | ||
| 25 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 25 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 26 | cortex-m-rt = "0.7.0" | 26 | cortex-m-rt = "0.7.0" |
| 27 | embedded-hal = "0.2.6" | 27 | embedded-hal = "0.2.6" |
| 28 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 28 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } |
| 29 | embedded-hal-async = { version = "=0.1.0-alpha.3" } | 29 | embedded-hal-async = { version = "=0.2.0-alpha.0" } |
| 30 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } | 30 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } |
| 31 | 31 | ||
| 32 | [profile.dev] | 32 | [profile.dev] |
