mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-21 22:32:29 +00:00
Merge branch 'master' into stm-dualcore
This commit is contained in:
commit
ab4d378dda
17
ci.sh
17
ci.sh
@ -2,11 +2,13 @@
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
# check-cfg is stable on rustc 1.79 but not cargo 1.79.
|
||||
# however, our cargo-batch is currently based on cargo 1.80, which does support check-cfg.
|
||||
# so, force build.rs scripts to emit check-cfg commands.
|
||||
# when 1.80 hits stable we can make build.rs unconditionally emit check-cfg and remove all this.
|
||||
export EMBASSY_FORCE_CHECK_CFG=1
|
||||
if ! command -v cargo-batch &> /dev/null; then
|
||||
echo "cargo-batch could not be found. Install it with the following command:"
|
||||
echo ""
|
||||
echo " cargo install --git https://github.com/embassy-rs/cargo-batch cargo --bin cargo-batch --locked"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export RUSTFLAGS=-Dwarnings
|
||||
export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info
|
||||
@ -175,6 +177,7 @@ cargo batch \
|
||||
--- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'overclock' \
|
||||
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
|
||||
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
|
||||
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \
|
||||
--- build --release --manifest-path embassy-boot-rp/Cargo.toml --target thumbv6m-none-eabi \
|
||||
--- build --release --manifest-path embassy-boot-stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
|
||||
--- build --release --manifest-path docs/examples/basic/Cargo.toml --target thumbv7em-none-eabi \
|
||||
@ -186,6 +189,8 @@ cargo batch \
|
||||
--- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \
|
||||
--- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \
|
||||
--- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9160 \
|
||||
--- build --release --manifest-path examples/nrf9151/s/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9151/s \
|
||||
--- build --release --manifest-path examples/nrf9151/ns/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9151/ns \
|
||||
--- build --release --manifest-path examples/nrf51/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/nrf51 \
|
||||
--- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \
|
||||
--- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \
|
||||
@ -214,6 +219,7 @@ cargo batch \
|
||||
--- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wl \
|
||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \
|
||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \
|
||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns,skip-include --out-dir out/examples/boot/nrf9120 \
|
||||
--- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \
|
||||
--- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \
|
||||
--- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \
|
||||
@ -225,6 +231,7 @@ cargo batch \
|
||||
--- build --release --manifest-path examples/boot/application/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32wb-dfu \
|
||||
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
|
||||
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
|
||||
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \
|
||||
--- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \
|
||||
--- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
|
||||
--- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg \
|
||||
|
@ -16,7 +16,7 @@ overclock = []
|
||||
|
||||
[dependencies]
|
||||
cyw43 = { version = "0.1.0", path = "../cyw43" }
|
||||
embassy-rp = { version = "0.1.0", path = "../embassy-rp" }
|
||||
embassy-rp = { version = "0.2.0", path = "../embassy-rp" }
|
||||
pio-proc = "0.2"
|
||||
pio = "0.2.1"
|
||||
fixed = "1.23.1"
|
||||
|
@ -17,10 +17,10 @@ log = ["dep:log"]
|
||||
firmware-logs = []
|
||||
|
||||
[dependencies]
|
||||
embassy-time = { version = "0.3.1", path = "../embassy-time"}
|
||||
embassy-time = { version = "0.3.2", path = "../embassy-time"}
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync"}
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
||||
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"}
|
||||
embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"}
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.17", optional = true }
|
||||
|
@ -42,9 +42,11 @@ pub enum ScanType {
|
||||
Passive,
|
||||
}
|
||||
|
||||
/// Scan options.
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct ScanOptions {
|
||||
/// SSID to scan for.
|
||||
pub ssid: Option<heapless::String<32>>,
|
||||
/// If set to `None`, all APs will be returned. If set to `Some`, only APs
|
||||
/// with the specified BSSID will be returned.
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ use ioctl::IoctlState;
|
||||
|
||||
use crate::bus::Bus;
|
||||
pub use crate::bus::SpiBusCyw43;
|
||||
pub use crate::control::{AddMulticastAddressError, Control, Error as ControlError, Scanner};
|
||||
pub use crate::control::{AddMulticastAddressError, Control, Error as ControlError, ScanOptions, Scanner};
|
||||
pub use crate::runner::Runner;
|
||||
pub use crate::structs::BssInfo;
|
||||
|
||||
|
@ -6,9 +6,9 @@ version = "0.1.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
embassy-executor = { version = "0.5.0", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] }
|
||||
embassy-time = { version = "0.3.1", path = "../../../embassy-time", features = ["defmt"] }
|
||||
embassy-nrf = { version = "0.1.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] }
|
||||
embassy-executor = { version = "0.6.0", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] }
|
||||
embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt"] }
|
||||
embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] }
|
||||
|
||||
defmt = "0.3"
|
||||
defmt-rtt = "0.3"
|
||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
||||
cortex-m = "0.7"
|
||||
cortex-m-rt = "0.7"
|
||||
embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] }
|
||||
embassy-executor = { version = "0.5.0", features = ["arch-cortex-m", "executor-thread"] }
|
||||
embassy-executor = { version = "0.6.0", features = ["arch-cortex-m", "executor-thread"] }
|
||||
|
||||
defmt = "0.3.0"
|
||||
defmt-rtt = "0.3.0"
|
||||
|
@ -4,7 +4,7 @@ So you've got one of the examples running, but what now? Let's go through a simp
|
||||
|
||||
== Main
|
||||
|
||||
The full example can be found link:https://github.com/embassy-rs/embassy/tree/master/docs/examples/basic[here].
|
||||
The full example can be found link:https://github.com/embassy-rs/embassy/tree/main/docs/examples/basic[here].
|
||||
|
||||
NOTE: If you’re using VS Code and rust-analyzer to view and edit the examples, you may need to make some changes to `.vscode/settings.json` to tell it which project we’re working on. Follow the instructions commented in that file to get rust-analyzer working correctly.
|
||||
|
||||
|
@ -352,8 +352,13 @@ There are two main ways to handle concurrency in Embassy:
|
||||
|
||||
In general, either of these approaches will work. The main differences of these approaches are:
|
||||
|
||||
When using **separate tasks**, each task needs its own RAM allocation, so there's a little overhead for each task, so one task that does three things will likely be a little bit smaller than three tasks that do one thing (not a lot, probably a couple dozen bytes). In contrast, with **multiple futures in one task**, you don't need multiple task allocations, and it will generally be easier to share data, or use borrowed resources, inside of a single task.
|
||||
When using **separate tasks**, each task needs its own RAM allocation, so there's a little overhead for each task, so one task that does three things will likely be a little bit smaller than three tasks that do one thing (not a lot, probably a couple dozen bytes). In contrast, with **multiple futures in one task**, you don't need multiple task allocations, and it will generally be easier to share data, or use borrowed resources, inside of a single task.
|
||||
An example showcasing some methods for sharing things between tasks link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/sharing.rs[can be found here].
|
||||
|
||||
But when it comes to "waking" tasks, for example when a data transfer is complete or a button is pressed, it's faster to wake a dedicated task, because that task does not need to check which future is actually ready. `join` and `select` must check ALL of the futures they are managing to see which one (or which ones) are ready to do more work. This is because all Rust executors (like Embassy or Tokio) only have the ability to wake tasks, not specific futures. This means you will use slightly less CPU time juggling futures when using dedicated tasks.
|
||||
|
||||
Practically, there's not a LOT of difference either way - so go with what makes it easier for you and your code first, but there will be some details that are slightly different in each case.
|
||||
|
||||
== splitting peripherals resources between tasks
|
||||
|
||||
There are two ways to split resources between tasks, either manually assigned or by a convenient macro. See link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/assign_resources.rs[this example]
|
@ -1,6 +1,6 @@
|
||||
= Starting a new project
|
||||
|
||||
Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project.
|
||||
Once you’ve successfully xref:#_getting_started[run some example projects], the next step is to make a standalone Embassy project.
|
||||
|
||||
== Tools for generating Embassy projects
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
= Embassy nRF HAL
|
||||
|
||||
The link:https://github.com/embassy-rs/embassy/tree/master/embassy-nrf[Embassy nRF HAL] is based on the PACs (Peripheral Access Crate) from link:https://github.com/nrf-rs/[nrf-rs].
|
||||
The link:https://github.com/embassy-rs/embassy/tree/main/embassy-nrf[Embassy nRF HAL] is based on the PACs (Peripheral Access Crate) from link:https://github.com/nrf-rs/[nrf-rs].
|
||||
|
||||
== Timer driver
|
||||
|
||||
|
@ -48,7 +48,7 @@ link:https://github.com/lora-rs/lora-rs[lora-rs] supports LoRa networking on a w
|
||||
link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
|
||||
|
||||
=== Bootloader and DFU
|
||||
link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
|
||||
link:https://github.com/embassy-rs/embassy/tree/main/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
|
||||
|
||||
== What is DMA?
|
||||
|
||||
|
@ -8,7 +8,7 @@ The following examples shows different ways to use the on-board LED on a Raspber
|
||||
|
||||
Using mutual exclusion is the simplest way to share a peripheral.
|
||||
|
||||
TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here].
|
||||
TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here].
|
||||
[,rust]
|
||||
----
|
||||
use defmt::*;
|
||||
@ -78,7 +78,7 @@ To indicate that the pin will be set to an Output. The `AnyPin` could have been
|
||||
|
||||
A channel is another way to ensure exclusive access to a resource. Using a channel is great in the cases where the access can happen at a later point in time, allowing you to enqueue operations and do other things.
|
||||
|
||||
TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here].
|
||||
TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here].
|
||||
[,rust]
|
||||
----
|
||||
use defmt::*;
|
||||
@ -126,3 +126,9 @@ async fn toggle_led(control: Sender<'static, ThreadModeRawMutex, LedState, 64>,
|
||||
|
||||
This example replaces the Mutex with a Channel, and uses another task (the main loop) to drive the LED. The advantage of this approach is that only a single task references the peripheral, separating concerns. However, using a Mutex has a lower overhead and might be necessary if you need to ensure
|
||||
that the operation is completed before continuing to do other work in your task.
|
||||
|
||||
An example showcasing more methods for sharing link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/sharing.rs[can be found here].
|
||||
|
||||
== Sharing an I2C or SPI bus between multiple devices
|
||||
|
||||
An example of how to deal with multiple devices sharing a common I2C or SPI bus link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/shared_bus.rs[can be found here].
|
||||
|
@ -1,6 +1,6 @@
|
||||
= Embassy STM32 HAL
|
||||
|
||||
The link:https://github.com/embassy-rs/embassy/tree/master/embassy-stm32[Embassy STM32 HAL] is based on the `stm32-metapac` project.
|
||||
The link:https://github.com/embassy-rs/embassy/tree/main/embassy-stm32[Embassy STM32 HAL] is based on the `stm32-metapac` project.
|
||||
|
||||
== The infinite variant problem
|
||||
|
||||
|
@ -16,7 +16,7 @@ The `embassy::time::Timer` type provides two timing methods.
|
||||
|
||||
An example of a delay is provided as follows:
|
||||
|
||||
TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here].
|
||||
TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here].
|
||||
[,rust]
|
||||
----
|
||||
use embassy::executor::{task, Executor};
|
||||
@ -41,7 +41,7 @@ that expect a generic delay implementation to be provided.
|
||||
|
||||
An example of how this can be used:
|
||||
|
||||
TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here].
|
||||
TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here].
|
||||
[,rust]
|
||||
----
|
||||
use embassy::executor::{task, Executor};
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "embassy-boot-nrf"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
description = "Bootloader lib for nRF chips"
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/embassy-rs/embassy"
|
||||
@ -25,8 +25,8 @@ defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.17", optional = true }
|
||||
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||
embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", default-features = false }
|
||||
embassy-boot = { version = "0.2.0", path = "../embassy-boot" }
|
||||
embassy-nrf = { version = "0.2.0", path = "../embassy-nrf", default-features = false }
|
||||
embassy-boot = { version = "0.3.0", path = "../embassy-boot" }
|
||||
cortex-m = { version = "0.7.6" }
|
||||
cortex-m-rt = { version = "0.7" }
|
||||
embedded-storage = "0.3.1"
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "embassy-boot-rp"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
description = "Bootloader lib for RP2040 chips"
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/embassy-rs/embassy"
|
||||
@ -24,9 +24,9 @@ defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4", optional = true }
|
||||
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||
embassy-rp = { version = "0.1.0", path = "../embassy-rp", default-features = false }
|
||||
embassy-boot = { version = "0.2.0", path = "../embassy-boot" }
|
||||
embassy-time = { version = "0.3.1", path = "../embassy-time" }
|
||||
embassy-rp = { version = "0.2.0", path = "../embassy-rp", default-features = false }
|
||||
embassy-boot = { version = "0.3.0", path = "../embassy-boot" }
|
||||
embassy-time = { version = "0.3.2", path = "../embassy-time" }
|
||||
|
||||
cortex-m = { version = "0.7.6" }
|
||||
cortex-m-rt = { version = "0.7" }
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ log = { version = "0.4", optional = true }
|
||||
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false }
|
||||
embassy-boot = { version = "0.2.0", path = "../embassy-boot" }
|
||||
embassy-boot = { version = "0.3.0", path = "../embassy-boot" }
|
||||
cortex-m = { version = "0.7.6" }
|
||||
cortex-m-rt = { version = "0.7" }
|
||||
embedded-storage = "0.3.1"
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "embassy-boot"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
description = "A lightweight bootloader supporting firmware updates in a power-fail-safe way, with trial boots and rollbacks."
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/embassy-rs/embassy"
|
||||
@ -28,7 +28,7 @@ defmt = { version = "0.3", optional = true }
|
||||
digest = "0.10"
|
||||
log = { version = "0.4", optional = true }
|
||||
ed25519-dalek = { version = "2", default_features = false, features = ["digest"], optional = true }
|
||||
embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
embassy-embedded-hal = { version = "0.2.0", path = "../embassy-embedded-hal" }
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||
embedded-storage = "0.3.1"
|
||||
embedded-storage-async = { version = "0.4.1" }
|
||||
|
@ -236,10 +236,10 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S
|
||||
///
|
||||
pub fn prepare_boot(&mut self, aligned_buf: &mut [u8]) -> Result<State, BootError> {
|
||||
const {
|
||||
assert!(Self::PAGE_SIZE % ACTIVE::WRITE_SIZE as u32 == 0);
|
||||
assert!(Self::PAGE_SIZE % ACTIVE::ERASE_SIZE as u32 == 0);
|
||||
assert!(Self::PAGE_SIZE % DFU::WRITE_SIZE as u32 == 0);
|
||||
assert!(Self::PAGE_SIZE % DFU::ERASE_SIZE as u32 == 0);
|
||||
core::assert!(Self::PAGE_SIZE % ACTIVE::WRITE_SIZE as u32 == 0);
|
||||
core::assert!(Self::PAGE_SIZE % ACTIVE::ERASE_SIZE as u32 == 0);
|
||||
core::assert!(Self::PAGE_SIZE % DFU::WRITE_SIZE as u32 == 0);
|
||||
core::assert!(Self::PAGE_SIZE % DFU::ERASE_SIZE as u32 == 0);
|
||||
}
|
||||
|
||||
// Ensure we have enough progress pages to store copy progress
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
21
embassy-embedded-hal/CHANGELOG.md
Normal file
21
embassy-embedded-hal/CHANGELOG.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Changelog for embassy-embedded-hal
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 0.2.0 - 2024-08-05
|
||||
|
||||
- Add Clone derive to flash Partition in embassy-embedded-hal
|
||||
- Add support for all word sizes to async shared spi
|
||||
- Add Copy and 'static constraint to Word type in SPI structs
|
||||
- Improve flexibility by introducing SPI word size as a generic parameter
|
||||
- Allow changing Spi/I2cDeviceWithConfig's config at runtime
|
||||
- Impl `MultiwriteNorFlash` for `BlockingAsync`
|
||||
|
||||
## 0.1.0 - 2024-01-10
|
||||
|
||||
- First release
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "embassy-embedded-hal"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "Collection of utilities to use `embedded-hal` and `embedded-storage` traits with Embassy."
|
||||
@ -29,7 +29,7 @@ default = ["time"]
|
||||
[dependencies]
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||
embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true }
|
||||
embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true }
|
||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
|
||||
"unproven",
|
||||
] }
|
||||
|
@ -18,6 +18,16 @@ pub struct Partition<'a, M: RawMutex, T: NorFlash> {
|
||||
size: u32,
|
||||
}
|
||||
|
||||
impl<'a, M: RawMutex, T: NorFlash> Clone for Partition<'a, M, T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
flash: self.flash,
|
||||
offset: self.offset,
|
||||
size: self.size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, M: RawMutex, T: NorFlash> Partition<'a, M, T> {
|
||||
/// Create a new partition
|
||||
pub const fn new(flash: &'a Mutex<M, T>, offset: u32, size: u32) -> Self {
|
||||
|
@ -19,6 +19,16 @@ pub struct BlockingPartition<'a, M: RawMutex, T: NorFlash> {
|
||||
size: u32,
|
||||
}
|
||||
|
||||
impl<'a, M: RawMutex, T: NorFlash> Clone for BlockingPartition<'a, M, T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
flash: self.flash,
|
||||
offset: self.offset,
|
||||
size: self.size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, M: RawMutex, T: NorFlash> BlockingPartition<'a, M, T> {
|
||||
/// Create a new partition
|
||||
pub const fn new(flash: &'a Mutex<M, RefCell<T>>, offset: u32, size: u32) -> Self {
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "embassy-executor-macros"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "macros for creating the entry point and tasks for embassy-executor"
|
||||
|
@ -70,7 +70,7 @@ pub fn wasm() -> TokenStream {
|
||||
let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(::embassy_executor::Executor::new()));
|
||||
|
||||
executor.start(|spawner| {
|
||||
spawner.spawn(__embassy_main(spawner)).unwrap();
|
||||
spawner.must_spawn(__embassy_main(spawner));
|
||||
});
|
||||
|
||||
Ok(())
|
||||
|
@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 0.6.0 - 2024-08-05
|
||||
|
||||
- Add collapse_debuginfo to fmt.rs macros.
|
||||
- initial support for avr
|
||||
- use nightly waker_getters APIs
|
||||
|
||||
## 0.5.0 - 2024-01-11
|
||||
|
||||
- Updated to `embassy-time-driver 0.1`, `embassy-time-queue-driver 0.1`, compatible with `embassy-time v0.3` and higher.
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "embassy-executor"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "async/await executor designed for embedded usage"
|
||||
@ -33,7 +33,7 @@ defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
rtos-trace = { version = "0.1.2", optional = true }
|
||||
|
||||
embassy-executor-macros = { version = "0.4.0", path = "../embassy-executor-macros" }
|
||||
embassy-executor-macros = { version = "0.5.0", path = "../embassy-executor-macros" }
|
||||
embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true }
|
||||
embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true }
|
||||
critical-section = "1.1"
|
||||
|
@ -8,8 +8,6 @@
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::process::Command;
|
||||
|
||||
/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
|
||||
/// them (`cargo:rust-check-cfg=cfg(X)`).
|
||||
@ -17,7 +15,6 @@ use std::process::Command;
|
||||
pub struct CfgSet {
|
||||
enabled: HashSet<String>,
|
||||
declared: HashSet<String>,
|
||||
emit_declared: bool,
|
||||
}
|
||||
|
||||
impl CfgSet {
|
||||
@ -25,7 +22,6 @@ impl CfgSet {
|
||||
Self {
|
||||
enabled: HashSet::new(),
|
||||
declared: HashSet::new(),
|
||||
emit_declared: is_rustc_nightly(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +45,7 @@ impl CfgSet {
|
||||
///
|
||||
/// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
|
||||
pub fn declare(&mut self, cfg: impl AsRef<str>) {
|
||||
if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared {
|
||||
if self.declared.insert(cfg.as_ref().to_owned()) {
|
||||
println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
|
||||
}
|
||||
}
|
||||
@ -69,21 +65,6 @@ impl CfgSet {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_rustc_nightly() -> bool {
|
||||
if env::var_os("EMBASSY_FORCE_CHECK_CFG").is_some() {
|
||||
return true;
|
||||
}
|
||||
|
||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
|
||||
|
||||
let output = Command::new(rustc)
|
||||
.arg("--version")
|
||||
.output()
|
||||
.expect("failed to run `rustc --version`");
|
||||
|
||||
String::from_utf8_lossy(&output.stdout).contains("nightly")
|
||||
}
|
||||
|
||||
/// Sets configs that describe the target platform.
|
||||
pub fn set_target_cfgs(cfgs: &mut CfgSet) {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "embassy-hal-internal"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "Internal implementation details for Embassy HALs. DO NOT USE DIRECTLY."
|
||||
|
@ -8,8 +8,6 @@
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::process::Command;
|
||||
|
||||
/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
|
||||
/// them (`cargo:rust-check-cfg=cfg(X)`).
|
||||
@ -17,7 +15,6 @@ use std::process::Command;
|
||||
pub struct CfgSet {
|
||||
enabled: HashSet<String>,
|
||||
declared: HashSet<String>,
|
||||
emit_declared: bool,
|
||||
}
|
||||
|
||||
impl CfgSet {
|
||||
@ -25,7 +22,6 @@ impl CfgSet {
|
||||
Self {
|
||||
enabled: HashSet::new(),
|
||||
declared: HashSet::new(),
|
||||
emit_declared: is_rustc_nightly(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +45,7 @@ impl CfgSet {
|
||||
///
|
||||
/// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
|
||||
pub fn declare(&mut self, cfg: impl AsRef<str>) {
|
||||
if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared {
|
||||
if self.declared.insert(cfg.as_ref().to_owned()) {
|
||||
println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
|
||||
}
|
||||
}
|
||||
@ -69,21 +65,6 @@ impl CfgSet {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_rustc_nightly() -> bool {
|
||||
if env::var_os("EMBASSY_FORCE_CHECK_CFG").is_some() {
|
||||
return true;
|
||||
}
|
||||
|
||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
|
||||
|
||||
let output = Command::new(rustc)
|
||||
.arg("--version")
|
||||
.output()
|
||||
.expect("failed to run `rustc --version`");
|
||||
|
||||
String::from_utf8_lossy(&output.stdout).contains("nightly")
|
||||
}
|
||||
|
||||
/// Sets configs that describe the target platform.
|
||||
pub fn set_target_cfgs(cfgs: &mut CfgSet) {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,8 @@ log = { version = "0.4", default-features = false, optional = true }
|
||||
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
|
||||
embedded-hal-async = { version = "1.0" }
|
||||
embedded-hal-bus = { version = "0.1", features = ["async"] }
|
||||
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
|
||||
embassy-time = { version = "0.3.1", path = "../embassy-time" }
|
||||
embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" }
|
||||
embassy-time = { version = "0.3.2", path = "../embassy-time" }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
bitfield = "0.14.0"
|
||||
|
||||
|
@ -21,7 +21,7 @@ APL can be used in [`intrinsic safety applications/explosion hazardous areas`](h
|
||||
|
||||
## Supported SPI modes
|
||||
|
||||
`ADIN1110` supports two SPI modes. `Generic` and [`OPEN Alliance 10BASE-T1x MAC-PHY serial interface`](https://opensig.org/download/document/OPEN_Alliance_10BASET1x_MAC-PHY_Serial_Interface_V1.1.pdf)
|
||||
`ADIN1110` supports two SPI modes. `Generic` and [`OPEN Alliance 10BASE-T1x MAC-PHY serial interface`](https://opensig.org/wp-content/uploads/2023/12/OPEN_Alliance_10BASET1x_MAC-PHY_Serial_Interface_V1.1.pdf)
|
||||
|
||||
Both modes support with and without additional CRC.
|
||||
Currently only `Generic` SPI with or without CRC is supported.
|
||||
|
@ -16,7 +16,7 @@ const CRC8X_TABLE: [u8; 256] = [
|
||||
0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3,
|
||||
];
|
||||
|
||||
/// Calculate the crc of a pease of data.
|
||||
/// Calculate the crc of a piece of data.
|
||||
pub fn crc8(data: &[u8]) -> u8 {
|
||||
data.iter().fold(0, |crc, &byte| CRC8X_TABLE[usize::from(byte ^ crc)])
|
||||
}
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 0.3.0 - 2024-08-05
|
||||
|
||||
- Add collapse_debuginfo to fmt.rs macros.
|
||||
- Update embassy-sync version
|
||||
|
||||
## 0.2.0 - 2023-10-18
|
||||
|
||||
- Update `embassy-net-driver` to v0.2
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "embassy-net-driver-channel"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack."
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ documentation = "https://docs.embassy.dev/embassy-net-enc28j60"
|
||||
embedded-hal = { version = "1.0" }
|
||||
embedded-hal-async = { version = "1.0" }
|
||||
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
||||
embassy-time = { version = "0.3.1", path = "../embassy-time" }
|
||||
embassy-time = { version = "0.3.2", path = "../embassy-time" }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -17,10 +17,10 @@ log = [ "dep:log" ]
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
|
||||
embassy-time = { version = "0.3.1", path = "../embassy-time" }
|
||||
embassy-time = { version = "0.3.2", path = "../embassy-time" }
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync"}
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
||||
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"}
|
||||
embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"}
|
||||
|
||||
embedded-hal = { version = "1.0" }
|
||||
embedded-hal-async = { version = "1.0" }
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
|
||||
embedded-io-async = { version = "0.6.1" }
|
||||
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
|
||||
embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
ppproto = { version = "0.1.2"}
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -12,8 +12,8 @@ documentation = "https://docs.embassy.dev/embassy-net-wiznet"
|
||||
[dependencies]
|
||||
embedded-hal = { version = "1.0" }
|
||||
embedded-hal-async = { version = "1.0" }
|
||||
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
|
||||
embassy-time = { version = "0.3.1", path = "../embassy-time" }
|
||||
embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" }
|
||||
embassy-time = { version = "0.3.2", path = "../embassy-time" }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
defmt = { version = "0.3", optional = true }
|
||||
|
||||
|
@ -72,7 +72,7 @@ smoltcp = { version = "0.11.0", default-features = false, features = [
|
||||
] }
|
||||
|
||||
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
||||
embassy-time = { version = "0.3.1", path = "../embassy-time" }
|
||||
embassy-time = { version = "0.3.2", path = "../embassy-time" }
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||
embedded-io-async = { version = "0.6.1" }
|
||||
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,8 @@ use embassy_sync::waitqueue::WakerRegistration;
|
||||
use embassy_time::{Instant, Timer};
|
||||
#[allow(unused_imports)]
|
||||
use heapless::Vec;
|
||||
#[cfg(feature = "dns")]
|
||||
pub use smoltcp::config::DNS_MAX_SERVER_COUNT;
|
||||
#[cfg(feature = "igmp")]
|
||||
pub use smoltcp::iface::MulticastError;
|
||||
#[allow(unused_imports)]
|
||||
@ -414,7 +416,7 @@ impl<D: Driver> Stack<D> {
|
||||
/// ```ignore
|
||||
/// let config = embassy_net::Config::dhcpv4(Default::default());
|
||||
///// Init network stack
|
||||
/// static RESOURCES: StaticCell<embassy_net::StackResources<2> = StaticCell::new();
|
||||
/// static RESOURCES: StaticCell<embassy_net::StackResources<2>> = StaticCell::new();
|
||||
/// static STACK: StaticCell<embassy_net::Stack> = StaticCell::new();
|
||||
/// let stack = &*STACK.init(embassy_net::Stack::new(
|
||||
/// device,
|
||||
@ -823,9 +825,17 @@ impl<D: Driver> Inner<D> {
|
||||
|
||||
// Apply DNS servers
|
||||
#[cfg(feature = "dns")]
|
||||
s.sockets
|
||||
.get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket)
|
||||
.update_servers(&dns_servers[..]);
|
||||
if !dns_servers.is_empty() {
|
||||
let count = if dns_servers.len() > DNS_MAX_SERVER_COUNT {
|
||||
warn!("Number of DNS servers exceeds DNS_MAX_SERVER_COUNT, truncating list.");
|
||||
DNS_MAX_SERVER_COUNT
|
||||
} else {
|
||||
dns_servers.len()
|
||||
};
|
||||
s.sockets
|
||||
.get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket)
|
||||
.update_servers(&dns_servers[..count]);
|
||||
}
|
||||
|
||||
self.config_waker.wake();
|
||||
}
|
||||
|
@ -660,12 +660,25 @@ pub mod client {
|
||||
pub struct TcpClient<'d, D: Driver, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> {
|
||||
stack: &'d Stack<D>,
|
||||
state: &'d TcpClientState<N, TX_SZ, RX_SZ>,
|
||||
socket_timeout: Option<Duration>,
|
||||
}
|
||||
|
||||
impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClient<'d, D, N, TX_SZ, RX_SZ> {
|
||||
/// Create a new `TcpClient`.
|
||||
pub fn new(stack: &'d Stack<D>, state: &'d TcpClientState<N, TX_SZ, RX_SZ>) -> Self {
|
||||
Self { stack, state }
|
||||
Self {
|
||||
stack,
|
||||
state,
|
||||
socket_timeout: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the timeout for each socket created by this `TcpClient`.
|
||||
///
|
||||
/// If the timeout is set, the socket will be closed if no data is received for the
|
||||
/// specified duration.
|
||||
pub fn set_timeout(&mut self, timeout: Option<Duration>) {
|
||||
self.socket_timeout = timeout;
|
||||
}
|
||||
}
|
||||
|
||||
@ -691,6 +704,7 @@ pub mod client {
|
||||
};
|
||||
let remote_endpoint = (addr, remote.port());
|
||||
let mut socket = TcpConnection::new(&self.stack, self.state)?;
|
||||
socket.socket.set_timeout(self.socket_timeout.clone());
|
||||
socket
|
||||
.socket
|
||||
.connect(remote_endpoint)
|
||||
|
@ -7,24 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## Unreleased
|
||||
|
||||
- Drop `sealed` mod
|
||||
- nrf52840: Add dcdc voltage parameter to configure REG0 regulator
|
||||
- radio: Add support for IEEE 802.15.4 and BLE via radio peripheral
|
||||
- spim: Reduce trace-level messages ("Copying SPIM tx buffer..")
|
||||
- uart: Add support for rx- or tx-only BufferedUart
|
||||
- uart: Implement splitting Rx/Tx
|
||||
- spi: Allow specifying OutputDrive for SPI spins
|
||||
- pdm: Fix gain register value derivation
|
||||
- spim: Implement chunked DMA transfers
|
||||
- spi: Add bounds checks for EasyDMA buffer size
|
||||
- uarte: Add support for handling RX errors
|
||||
- nrf51: Implement support for nrf51 chip
|
||||
- pwm: Expose `duty` method
|
||||
- pwm: Fix infinite loop
|
||||
- spi: Add support for configuring bit order for bus
|
||||
- pwm: Expose `pwm::PWM_CLK_HZ` and add `is_enabled` method
|
||||
- gpio: Drop GPIO Pin generics (API break)
|
||||
- pwm: Allow specifying OutputDrive for PWM channels
|
||||
## 0.2.0 - 2024-08-05
|
||||
|
||||
- Support for NRF chips:
|
||||
- nrf51
|
||||
- nrf9151
|
||||
- Support for new peripherals:
|
||||
- EGU
|
||||
- radio - low-level support for IEEE 802.15.4 and BLE via radio peripheral
|
||||
- Peripheral changes:
|
||||
- gpio: Drop GPIO Pin generics (API break)
|
||||
- pdm: Fix gain register value derivation
|
||||
- pwm:
|
||||
- Expose `duty` method
|
||||
- Expose `pwm::PWM_CLK_HZ` and add `is_enabled` method
|
||||
- Allow specifying OutputDrive for PWM channels
|
||||
- Fix infinite loop
|
||||
- spim:
|
||||
- Reduce trace-level messages ("Copying SPIM tx buffer..")
|
||||
- Support configuring bit order for bus
|
||||
- Allow specifying OutputDrive for SPI pins
|
||||
- Add bounds checks for EasyDMA buffer size
|
||||
- Implement chunked DMA transfers
|
||||
- uart:
|
||||
- Add support for rx- or tx-only BufferedUart
|
||||
- Implement splitting Rx/Tx
|
||||
- Add support for handling RX errors
|
||||
- Miscellaneous changes:
|
||||
- Add `collapse_debuginfo` to fmt.rs macros.
|
||||
- Drop `sealed` mod
|
||||
- nrf52840: Add dcdc voltage parameter to configure REG0 regulator
|
||||
|
||||
## 0.1.0 - 2024-01-12
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "embassy-nrf"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers"
|
||||
@ -40,6 +40,7 @@ rt = [
|
||||
"nrf5340-app-pac?/rt",
|
||||
"nrf5340-net-pac?/rt",
|
||||
"nrf9160-pac?/rt",
|
||||
"nrf9120-pac?/rt",
|
||||
]
|
||||
|
||||
## Enable features requiring `embassy-time`
|
||||
@ -96,9 +97,18 @@ nrf5340-app-ns = ["_nrf5340-app", "_ns"]
|
||||
## nRF5340 network core
|
||||
nrf5340-net = ["_nrf5340-net"]
|
||||
## nRF9160 in Secure mode
|
||||
nrf9160-s = ["_nrf9160", "_s"]
|
||||
nrf9160-s = ["_nrf9160", "_s", "_nrf91"]
|
||||
## nRF9160 in Non-Secure mode
|
||||
nrf9160-ns = ["_nrf9160", "_ns"]
|
||||
nrf9160-ns = ["_nrf9160", "_ns", "_nrf91"]
|
||||
## The nRF9120 is the internal part number for the nRF9161 and nRF9151.
|
||||
## nRF9120 in Secure mode
|
||||
nrf9120-s = ["_nrf9120", "_s", "_nrf91"]
|
||||
nrf9151-s = ["_nrf9120", "_s", "_nrf91"]
|
||||
nrf9161-s = ["_nrf9120", "_s", "_nrf91"]
|
||||
## nRF9120 in Non-Secure mode
|
||||
nrf9120-ns = ["_nrf9120", "_ns", "_nrf91"]
|
||||
nrf9151-ns = ["_nrf9120", "_ns", "_nrf91"]
|
||||
nrf9161-ns = ["_nrf9120", "_ns", "_nrf91"]
|
||||
|
||||
# Features starting with `_` are for internal use only. They're not intended
|
||||
# to be enabled by other crates, and are not covered by semver guarantees.
|
||||
@ -107,8 +117,10 @@ _nrf5340-app = ["_nrf5340", "nrf5340-app-pac"]
|
||||
_nrf5340-net = ["_nrf5340", "nrf5340-net-pac"]
|
||||
_nrf5340 = ["_gpio-p1", "_dppi"]
|
||||
_nrf9160 = ["nrf9160-pac", "_dppi"]
|
||||
_nrf9120 = ["nrf9120-pac", "_dppi"]
|
||||
_nrf52 = ["_ppi"]
|
||||
_nrf51 = ["_ppi"]
|
||||
_nrf91 = []
|
||||
|
||||
_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768"]
|
||||
|
||||
@ -125,10 +137,10 @@ _nrf52832_anomaly_109 = []
|
||||
|
||||
[dependencies]
|
||||
embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true }
|
||||
embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true }
|
||||
embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true }
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
|
||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
|
||||
embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" }
|
||||
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" }
|
||||
|
||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
||||
@ -161,3 +173,4 @@ nrf52840-pac = { version = "0.12.0", optional = true }
|
||||
nrf5340-app-pac = { version = "0.12.0", optional = true }
|
||||
nrf5340-net-pac = { version = "0.12.0", optional = true }
|
||||
nrf9160-pac = { version = "0.12.0", optional = true }
|
||||
nrf9120-pac = { version = "0.12.0", optional = true }
|
||||
|
@ -766,6 +766,12 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
|
||||
rx.pop_done(amt);
|
||||
U::regs().intenset.write(|w| w.rxstarted().set());
|
||||
}
|
||||
|
||||
/// we are ready to read if there is data in the buffer
|
||||
fn read_ready() -> Result<bool, Error> {
|
||||
let state = U::buffered_state();
|
||||
Ok(!state.rx_buf.is_empty())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarteRx<'a, U, T> {
|
||||
@ -827,6 +833,18 @@ mod _embedded_io {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, U: UarteInstance, T: TimerInstance + 'd> embedded_io_async::ReadReady for BufferedUarte<'d, U, T> {
|
||||
fn read_ready(&mut self) -> Result<bool, Self::Error> {
|
||||
BufferedUarteRx::<'d, U, T>::read_ready()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, U: UarteInstance, T: TimerInstance + 'd> embedded_io_async::ReadReady for BufferedUarteRx<'d, U, T> {
|
||||
fn read_ready(&mut self) -> Result<bool, Self::Error> {
|
||||
Self::read_ready()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarte<'d, U, T> {
|
||||
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
|
||||
self.fill_buf().await
|
||||
|
430
embassy-nrf/src/chips/nrf9120.rs
Normal file
430
embassy-nrf/src/chips/nrf9120.rs
Normal file
@ -0,0 +1,430 @@
|
||||
/// Peripheral Access Crate
|
||||
#[allow(unused_imports)]
|
||||
#[rustfmt::skip]
|
||||
pub mod pac {
|
||||
// The nRF9120 has a secure and non-secure (NS) mode.
|
||||
// To avoid cfg spam, we remove _ns or _s suffixes here.
|
||||
|
||||
pub use nrf9120_pac::NVIC_PRIO_BITS;
|
||||
|
||||
#[cfg(feature="rt")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9120_pac::interrupt;
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9120_pac::{
|
||||
Interrupt,
|
||||
|
||||
cc_host_rgf_s as cc_host_rgf,
|
||||
clock_ns as clock,
|
||||
cryptocell_s as cryptocell,
|
||||
ctrl_ap_peri_s as ctrl_ap_peri,
|
||||
dppic_ns as dppic,
|
||||
egu0_ns as egu0,
|
||||
ficr_s as ficr,
|
||||
fpu_ns as fpu,
|
||||
gpiote0_s as gpiote,
|
||||
i2s_ns as i2s,
|
||||
ipc_ns as ipc,
|
||||
kmu_ns as kmu,
|
||||
nvmc_ns as nvmc,
|
||||
p0_ns as p0,
|
||||
pdm_ns as pdm,
|
||||
power_ns as power,
|
||||
pwm0_ns as pwm0,
|
||||
regulators_ns as regulators,
|
||||
rtc0_ns as rtc0,
|
||||
saadc_ns as saadc,
|
||||
spim0_ns as spim0,
|
||||
spis0_ns as spis0,
|
||||
spu_s as spu,
|
||||
tad_s as tad,
|
||||
timer0_ns as timer0,
|
||||
twim0_ns as twim0,
|
||||
twis0_ns as twis0,
|
||||
uarte0_ns as uarte0,
|
||||
uicr_s as uicr,
|
||||
vmc_ns as vmc,
|
||||
wdt_ns as wdt,
|
||||
};
|
||||
|
||||
/// Non-Secure mode (NS) peripherals
|
||||
pub mod ns {
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9120_pac::{
|
||||
CLOCK_NS as CLOCK,
|
||||
DPPIC_NS as DPPIC,
|
||||
EGU0_NS as EGU0,
|
||||
EGU1_NS as EGU1,
|
||||
EGU2_NS as EGU2,
|
||||
EGU3_NS as EGU3,
|
||||
EGU4_NS as EGU4,
|
||||
EGU5_NS as EGU5,
|
||||
FPU_NS as FPU,
|
||||
GPIOTE1_NS as GPIOTE1,
|
||||
I2S_NS as I2S,
|
||||
IPC_NS as IPC,
|
||||
KMU_NS as KMU,
|
||||
NVMC_NS as NVMC,
|
||||
P0_NS as P0,
|
||||
PDM_NS as PDM,
|
||||
POWER_NS as POWER,
|
||||
PWM0_NS as PWM0,
|
||||
PWM1_NS as PWM1,
|
||||
PWM2_NS as PWM2,
|
||||
PWM3_NS as PWM3,
|
||||
REGULATORS_NS as REGULATORS,
|
||||
RTC0_NS as RTC0,
|
||||
RTC1_NS as RTC1,
|
||||
SAADC_NS as SAADC,
|
||||
SPIM0_NS as SPIM0,
|
||||
SPIM1_NS as SPIM1,
|
||||
SPIM2_NS as SPIM2,
|
||||
SPIM3_NS as SPIM3,
|
||||
SPIS0_NS as SPIS0,
|
||||
SPIS1_NS as SPIS1,
|
||||
SPIS2_NS as SPIS2,
|
||||
SPIS3_NS as SPIS3,
|
||||
TIMER0_NS as TIMER0,
|
||||
TIMER1_NS as TIMER1,
|
||||
TIMER2_NS as TIMER2,
|
||||
TWIM0_NS as TWIM0,
|
||||
TWIM1_NS as TWIM1,
|
||||
TWIM2_NS as TWIM2,
|
||||
TWIM3_NS as TWIM3,
|
||||
TWIS0_NS as TWIS0,
|
||||
TWIS1_NS as TWIS1,
|
||||
TWIS2_NS as TWIS2,
|
||||
TWIS3_NS as TWIS3,
|
||||
UARTE0_NS as UARTE0,
|
||||
UARTE1_NS as UARTE1,
|
||||
UARTE2_NS as UARTE2,
|
||||
UARTE3_NS as UARTE3,
|
||||
VMC_NS as VMC,
|
||||
WDT_NS as WDT,
|
||||
};
|
||||
}
|
||||
|
||||
/// Secure mode (S) peripherals
|
||||
pub mod s {
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9120_pac::{
|
||||
CC_HOST_RGF_S as CC_HOST_RGF,
|
||||
CLOCK_S as CLOCK,
|
||||
CRYPTOCELL_S as CRYPTOCELL,
|
||||
CTRL_AP_PERI_S as CTRL_AP_PERI,
|
||||
DPPIC_S as DPPIC,
|
||||
EGU0_S as EGU0,
|
||||
EGU1_S as EGU1,
|
||||
EGU2_S as EGU2,
|
||||
EGU3_S as EGU3,
|
||||
EGU4_S as EGU4,
|
||||
EGU5_S as EGU5,
|
||||
FICR_S as FICR,
|
||||
FPU as FPU,
|
||||
GPIOTE0_S as GPIOTE0,
|
||||
I2S_S as I2S,
|
||||
IPC_S as IPC,
|
||||
KMU_S as KMU,
|
||||
NVMC_S as NVMC,
|
||||
P0_S as P0,
|
||||
PDM_S as PDM,
|
||||
POWER_S as POWER,
|
||||
PWM0_S as PWM0,
|
||||
PWM1_S as PWM1,
|
||||
PWM2_S as PWM2,
|
||||
PWM3_S as PWM3,
|
||||
REGULATORS_S as REGULATORS,
|
||||
RTC0_S as RTC0,
|
||||
RTC1_S as RTC1,
|
||||
SAADC_S as SAADC,
|
||||
SPIM0_S as SPIM0,
|
||||
SPIM1_S as SPIM1,
|
||||
SPIM2_S as SPIM2,
|
||||
SPIM3_S as SPIM3,
|
||||
SPIS0_S as SPIS0,
|
||||
SPIS1_S as SPIS1,
|
||||
SPIS2_S as SPIS2,
|
||||
SPIS3_S as SPIS3,
|
||||
SPU_S as SPU,
|
||||
TAD_S as TAD,
|
||||
TIMER0_S as TIMER0,
|
||||
TIMER1_S as TIMER1,
|
||||
TIMER2_S as TIMER2,
|
||||
TWIM0_S as TWIM0,
|
||||
TWIM1_S as TWIM1,
|
||||
TWIM2_S as TWIM2,
|
||||
TWIM3_S as TWIM3,
|
||||
TWIS0_S as TWIS0,
|
||||
TWIS1_S as TWIS1,
|
||||
TWIS2_S as TWIS2,
|
||||
TWIS3_S as TWIS3,
|
||||
UARTE0_S as UARTE0,
|
||||
UARTE1_S as UARTE1,
|
||||
UARTE2_S as UARTE2,
|
||||
UARTE3_S as UARTE3,
|
||||
UICR_S as UICR,
|
||||
VMC_S as VMC,
|
||||
WDT_S as WDT,
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "_ns")]
|
||||
pub use ns::*;
|
||||
#[cfg(feature = "_s")]
|
||||
pub use s::*;
|
||||
}
|
||||
|
||||
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||
pub const EASY_DMA_SIZE: usize = (1 << 13) - 1;
|
||||
pub const FORCE_COPY_BUFFER_SIZE: usize = 1024;
|
||||
|
||||
pub const FLASH_SIZE: usize = 1024 * 1024;
|
||||
|
||||
embassy_hal_internal::peripherals! {
|
||||
// RTC
|
||||
RTC0,
|
||||
RTC1,
|
||||
|
||||
// WDT
|
||||
WDT,
|
||||
|
||||
// NVMC
|
||||
NVMC,
|
||||
|
||||
// UARTE, TWI & SPI
|
||||
SERIAL0,
|
||||
SERIAL1,
|
||||
SERIAL2,
|
||||
SERIAL3,
|
||||
|
||||
// SAADC
|
||||
SAADC,
|
||||
|
||||
// PWM
|
||||
PWM0,
|
||||
PWM1,
|
||||
PWM2,
|
||||
PWM3,
|
||||
|
||||
// TIMER
|
||||
TIMER0,
|
||||
TIMER1,
|
||||
TIMER2,
|
||||
|
||||
// GPIOTE
|
||||
GPIOTE_CH0,
|
||||
GPIOTE_CH1,
|
||||
GPIOTE_CH2,
|
||||
GPIOTE_CH3,
|
||||
GPIOTE_CH4,
|
||||
GPIOTE_CH5,
|
||||
GPIOTE_CH6,
|
||||
GPIOTE_CH7,
|
||||
|
||||
// PPI
|
||||
PPI_CH0,
|
||||
PPI_CH1,
|
||||
PPI_CH2,
|
||||
PPI_CH3,
|
||||
PPI_CH4,
|
||||
PPI_CH5,
|
||||
PPI_CH6,
|
||||
PPI_CH7,
|
||||
PPI_CH8,
|
||||
PPI_CH9,
|
||||
PPI_CH10,
|
||||
PPI_CH11,
|
||||
PPI_CH12,
|
||||
PPI_CH13,
|
||||
PPI_CH14,
|
||||
PPI_CH15,
|
||||
|
||||
PPI_GROUP0,
|
||||
PPI_GROUP1,
|
||||
PPI_GROUP2,
|
||||
PPI_GROUP3,
|
||||
PPI_GROUP4,
|
||||
PPI_GROUP5,
|
||||
|
||||
// GPIO port 0
|
||||
P0_00,
|
||||
P0_01,
|
||||
P0_02,
|
||||
P0_03,
|
||||
P0_04,
|
||||
P0_05,
|
||||
P0_06,
|
||||
P0_07,
|
||||
P0_08,
|
||||
P0_09,
|
||||
P0_10,
|
||||
P0_11,
|
||||
P0_12,
|
||||
P0_13,
|
||||
P0_14,
|
||||
P0_15,
|
||||
P0_16,
|
||||
P0_17,
|
||||
P0_18,
|
||||
P0_19,
|
||||
P0_20,
|
||||
P0_21,
|
||||
P0_22,
|
||||
P0_23,
|
||||
P0_24,
|
||||
P0_25,
|
||||
P0_26,
|
||||
P0_27,
|
||||
P0_28,
|
||||
P0_29,
|
||||
P0_30,
|
||||
P0_31,
|
||||
|
||||
// PDM
|
||||
PDM,
|
||||
|
||||
// EGU
|
||||
EGU0,
|
||||
EGU1,
|
||||
EGU2,
|
||||
EGU3,
|
||||
EGU4,
|
||||
EGU5,
|
||||
}
|
||||
|
||||
impl_uarte!(SERIAL0, UARTE0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0);
|
||||
impl_uarte!(SERIAL1, UARTE1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1);
|
||||
impl_uarte!(SERIAL2, UARTE2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2);
|
||||
impl_uarte!(SERIAL3, UARTE3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3);
|
||||
|
||||
impl_spim!(SERIAL0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0);
|
||||
impl_spim!(SERIAL1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1);
|
||||
impl_spim!(SERIAL2, SPIM2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2);
|
||||
impl_spim!(SERIAL3, SPIM3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3);
|
||||
|
||||
impl_spis!(SERIAL0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0);
|
||||
impl_spis!(SERIAL1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1);
|
||||
impl_spis!(SERIAL2, SPIS2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2);
|
||||
impl_spis!(SERIAL3, SPIS3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3);
|
||||
|
||||
impl_twim!(SERIAL0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0);
|
||||
impl_twim!(SERIAL1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1);
|
||||
impl_twim!(SERIAL2, TWIM2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2);
|
||||
impl_twim!(SERIAL3, TWIM3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3);
|
||||
|
||||
impl_twis!(SERIAL0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0);
|
||||
impl_twis!(SERIAL1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1);
|
||||
impl_twis!(SERIAL2, TWIS2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2);
|
||||
impl_twis!(SERIAL3, TWIS3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3);
|
||||
|
||||
impl_pwm!(PWM0, PWM0, PWM0);
|
||||
impl_pwm!(PWM1, PWM1, PWM1);
|
||||
impl_pwm!(PWM2, PWM2, PWM2);
|
||||
impl_pwm!(PWM3, PWM3, PWM3);
|
||||
|
||||
impl_pdm!(PDM, PDM, PDM);
|
||||
|
||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
impl_pin!(P0_01, 0, 1);
|
||||
impl_pin!(P0_02, 0, 2);
|
||||
impl_pin!(P0_03, 0, 3);
|
||||
impl_pin!(P0_04, 0, 4);
|
||||
impl_pin!(P0_05, 0, 5);
|
||||
impl_pin!(P0_06, 0, 6);
|
||||
impl_pin!(P0_07, 0, 7);
|
||||
impl_pin!(P0_08, 0, 8);
|
||||
impl_pin!(P0_09, 0, 9);
|
||||
impl_pin!(P0_10, 0, 10);
|
||||
impl_pin!(P0_11, 0, 11);
|
||||
impl_pin!(P0_12, 0, 12);
|
||||
impl_pin!(P0_13, 0, 13);
|
||||
impl_pin!(P0_14, 0, 14);
|
||||
impl_pin!(P0_15, 0, 15);
|
||||
impl_pin!(P0_16, 0, 16);
|
||||
impl_pin!(P0_17, 0, 17);
|
||||
impl_pin!(P0_18, 0, 18);
|
||||
impl_pin!(P0_19, 0, 19);
|
||||
impl_pin!(P0_20, 0, 20);
|
||||
impl_pin!(P0_21, 0, 21);
|
||||
impl_pin!(P0_22, 0, 22);
|
||||
impl_pin!(P0_23, 0, 23);
|
||||
impl_pin!(P0_24, 0, 24);
|
||||
impl_pin!(P0_25, 0, 25);
|
||||
impl_pin!(P0_26, 0, 26);
|
||||
impl_pin!(P0_27, 0, 27);
|
||||
impl_pin!(P0_28, 0, 28);
|
||||
impl_pin!(P0_29, 0, 29);
|
||||
impl_pin!(P0_30, 0, 30);
|
||||
impl_pin!(P0_31, 0, 31);
|
||||
|
||||
impl_ppi_channel!(PPI_CH0, 0 => configurable);
|
||||
impl_ppi_channel!(PPI_CH1, 1 => configurable);
|
||||
impl_ppi_channel!(PPI_CH2, 2 => configurable);
|
||||
impl_ppi_channel!(PPI_CH3, 3 => configurable);
|
||||
impl_ppi_channel!(PPI_CH4, 4 => configurable);
|
||||
impl_ppi_channel!(PPI_CH5, 5 => configurable);
|
||||
impl_ppi_channel!(PPI_CH6, 6 => configurable);
|
||||
impl_ppi_channel!(PPI_CH7, 7 => configurable);
|
||||
impl_ppi_channel!(PPI_CH8, 8 => configurable);
|
||||
impl_ppi_channel!(PPI_CH9, 9 => configurable);
|
||||
impl_ppi_channel!(PPI_CH10, 10 => configurable);
|
||||
impl_ppi_channel!(PPI_CH11, 11 => configurable);
|
||||
impl_ppi_channel!(PPI_CH12, 12 => configurable);
|
||||
impl_ppi_channel!(PPI_CH13, 13 => configurable);
|
||||
impl_ppi_channel!(PPI_CH14, 14 => configurable);
|
||||
impl_ppi_channel!(PPI_CH15, 15 => configurable);
|
||||
|
||||
impl_saadc_input!(P0_13, ANALOG_INPUT0);
|
||||
impl_saadc_input!(P0_14, ANALOG_INPUT1);
|
||||
impl_saadc_input!(P0_15, ANALOG_INPUT2);
|
||||
impl_saadc_input!(P0_16, ANALOG_INPUT3);
|
||||
impl_saadc_input!(P0_17, ANALOG_INPUT4);
|
||||
impl_saadc_input!(P0_18, ANALOG_INPUT5);
|
||||
impl_saadc_input!(P0_19, ANALOG_INPUT6);
|
||||
impl_saadc_input!(P0_20, ANALOG_INPUT7);
|
||||
|
||||
impl_egu!(EGU0, EGU0, EGU0);
|
||||
impl_egu!(EGU1, EGU1, EGU1);
|
||||
impl_egu!(EGU2, EGU2, EGU2);
|
||||
impl_egu!(EGU3, EGU3, EGU3);
|
||||
impl_egu!(EGU4, EGU4, EGU4);
|
||||
impl_egu!(EGU5, EGU5, EGU5);
|
||||
|
||||
embassy_hal_internal::interrupt_mod!(
|
||||
SPU,
|
||||
CLOCK_POWER,
|
||||
SPIM0_SPIS0_TWIM0_TWIS0_UARTE0,
|
||||
SPIM1_SPIS1_TWIM1_TWIS1_UARTE1,
|
||||
SPIM2_SPIS2_TWIM2_TWIS2_UARTE2,
|
||||
SPIM3_SPIS3_TWIM3_TWIS3_UARTE3,
|
||||
GPIOTE0,
|
||||
SAADC,
|
||||
TIMER0,
|
||||
TIMER1,
|
||||
TIMER2,
|
||||
RTC0,
|
||||
RTC1,
|
||||
WDT,
|
||||
EGU0,
|
||||
EGU1,
|
||||
EGU2,
|
||||
EGU3,
|
||||
EGU4,
|
||||
EGU5,
|
||||
PWM0,
|
||||
PWM1,
|
||||
PWM2,
|
||||
PDM,
|
||||
PWM3,
|
||||
I2S,
|
||||
IPC,
|
||||
FPU,
|
||||
GPIOTE1,
|
||||
KMU,
|
||||
CRYPTOCELL,
|
||||
);
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -53,9 +53,9 @@ pub enum OutputChannelPolarity {
|
||||
|
||||
fn regs() -> &'static pac::gpiote::RegisterBlock {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s"))] {
|
||||
if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s", feature="nrf9120-s"))] {
|
||||
unsafe { &*pac::GPIOTE0::ptr() }
|
||||
} else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns"))] {
|
||||
} else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns", feature="nrf9120-ns"))] {
|
||||
unsafe { &*pac::GPIOTE1::ptr() }
|
||||
} else {
|
||||
unsafe { &*pac::GPIOTE::ptr() }
|
||||
@ -81,9 +81,9 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
|
||||
}
|
||||
|
||||
// Enable interrupts
|
||||
#[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))]
|
||||
#[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))]
|
||||
let irq = interrupt::GPIOTE0;
|
||||
#[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))]
|
||||
#[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns", feature = "nrf9120-ns"))]
|
||||
let irq = interrupt::GPIOTE1;
|
||||
#[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))]
|
||||
let irq = interrupt::GPIOTE;
|
||||
@ -96,14 +96,14 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
|
||||
g.intenset.write(|w| w.port().set());
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))]
|
||||
#[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))]
|
||||
#[cfg(feature = "rt")]
|
||||
#[interrupt]
|
||||
fn GPIOTE0() {
|
||||
unsafe { handle_gpiote_interrupt() };
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))]
|
||||
#[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns", feature = "nrf9120-ns"))]
|
||||
#[cfg(feature = "rt")]
|
||||
#[interrupt]
|
||||
fn GPIOTE1() {
|
||||
|
@ -24,8 +24,36 @@
|
||||
feature = "nrf5340-net",
|
||||
feature = "nrf9160-s",
|
||||
feature = "nrf9160-ns",
|
||||
feature = "nrf9120-s",
|
||||
feature = "nrf9120-ns",
|
||||
feature = "nrf9151-s",
|
||||
feature = "nrf9151-ns",
|
||||
feature = "nrf9161-s",
|
||||
feature = "nrf9161-ns",
|
||||
)))]
|
||||
compile_error!("No chip feature activated. You must activate exactly one of the following features: nrf52810, nrf52811, nrf52832, nrf52833, nrf52840");
|
||||
compile_error!(
|
||||
"No chip feature activated. You must activate exactly one of the following features:
|
||||
nrf51,
|
||||
nrf52805,
|
||||
nrf52810,
|
||||
nrf52811,
|
||||
nrf52820,
|
||||
nrf52832,
|
||||
nrf52833,
|
||||
nrf52840,
|
||||
nrf5340-app-s,
|
||||
nrf5340-app-ns,
|
||||
nrf5340-net,
|
||||
nrf9160-s,
|
||||
nrf9160-ns,
|
||||
nrf9120-s,
|
||||
nrf9120-ns,
|
||||
nrf9151-s,
|
||||
nrf9151-ns,
|
||||
nrf9161-s,
|
||||
nrf9161-ns,
|
||||
"
|
||||
);
|
||||
|
||||
#[cfg(all(feature = "reset-pin-as-gpio", not(feature = "_nrf52")))]
|
||||
compile_error!("feature `reset-pin-as-gpio` is only valid for nRF52 series chips.");
|
||||
@ -47,7 +75,7 @@ pub mod gpio;
|
||||
pub mod gpiote;
|
||||
|
||||
// TODO: tested on other chips
|
||||
#[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340-app")))]
|
||||
#[cfg(not(any(feature = "_nrf91", feature = "_nrf5340-app")))]
|
||||
pub mod radio;
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
@ -62,7 +90,7 @@ pub mod nvmc;
|
||||
feature = "nrf52833",
|
||||
feature = "nrf52840",
|
||||
feature = "_nrf5340-app",
|
||||
feature = "_nrf9160"
|
||||
feature = "_nrf91",
|
||||
))]
|
||||
pub mod pdm;
|
||||
pub mod ppi;
|
||||
@ -73,11 +101,11 @@ pub mod ppi;
|
||||
feature = "_nrf5340-net"
|
||||
)))]
|
||||
pub mod pwm;
|
||||
#[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340-net")))]
|
||||
#[cfg(not(any(feature = "nrf51", feature = "_nrf91", feature = "_nrf5340-net")))]
|
||||
pub mod qdec;
|
||||
#[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))]
|
||||
pub mod qspi;
|
||||
#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf9160")))]
|
||||
#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))]
|
||||
pub mod rng;
|
||||
#[cfg(not(any(feature = "nrf51", feature = "nrf52820", feature = "_nrf5340-net")))]
|
||||
pub mod saadc;
|
||||
@ -85,7 +113,7 @@ pub mod saadc;
|
||||
pub mod spim;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
pub mod spis;
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
|
||||
pub mod temp;
|
||||
pub mod timer;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
@ -116,6 +144,7 @@ pub mod wdt;
|
||||
#[cfg_attr(feature = "_nrf5340-app", path = "chips/nrf5340_app.rs")]
|
||||
#[cfg_attr(feature = "_nrf5340-net", path = "chips/nrf5340_net.rs")]
|
||||
#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")]
|
||||
#[cfg_attr(feature = "_nrf9120", path = "chips/nrf9120.rs")]
|
||||
mod chip;
|
||||
|
||||
/// Macro to bind interrupts to handlers.
|
||||
@ -196,15 +225,15 @@ pub mod config {
|
||||
/// Internal RC oscillator
|
||||
InternalRC,
|
||||
/// Synthesized from the high frequency clock source.
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
|
||||
Synthesized,
|
||||
/// External source from xtal.
|
||||
ExternalXtal,
|
||||
/// External source from xtal with low swing applied.
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
|
||||
ExternalLowSwing,
|
||||
/// External source from xtal with full swing applied.
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
|
||||
ExternalFullSwing,
|
||||
}
|
||||
|
||||
@ -222,7 +251,7 @@ pub mod config {
|
||||
}
|
||||
|
||||
/// Settings for enabling the built in DCDC converters.
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
|
||||
pub struct DcdcConfig {
|
||||
/// Config for the first stage DCDC (VDDH -> VDD), if disabled LDO will be used.
|
||||
#[cfg(feature = "nrf52840")]
|
||||
@ -264,7 +293,7 @@ pub mod config {
|
||||
}
|
||||
|
||||
/// Settings for enabling the built in DCDC converter.
|
||||
#[cfg(feature = "_nrf9160")]
|
||||
#[cfg(feature = "_nrf91")]
|
||||
pub struct DcdcConfig {
|
||||
/// Config for the main rail, if disabled LDO will be used.
|
||||
pub regmain: bool,
|
||||
@ -298,7 +327,7 @@ pub mod config {
|
||||
// xtals if they know they have them.
|
||||
hfclk_source: HfclkSource::Internal,
|
||||
lfclk_source: LfclkSource::InternalRC,
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
|
||||
dcdc: DcdcConfig {
|
||||
#[cfg(feature = "nrf52840")]
|
||||
reg0: false,
|
||||
@ -312,7 +341,7 @@ pub mod config {
|
||||
regmain: false,
|
||||
regradio: false,
|
||||
},
|
||||
#[cfg(feature = "_nrf9160")]
|
||||
#[cfg(feature = "_nrf91")]
|
||||
dcdc: DcdcConfig { regmain: false },
|
||||
#[cfg(feature = "gpiote")]
|
||||
gpiote_interrupt_priority: crate::interrupt::Priority::P0,
|
||||
@ -329,7 +358,7 @@ pub mod config {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "_nrf9160")]
|
||||
#[cfg(feature = "_nrf91")]
|
||||
#[allow(unused)]
|
||||
mod consts {
|
||||
pub const UICR_APPROTECT: *mut u32 = 0x00FF8000 as *mut u32;
|
||||
@ -468,7 +497,7 @@ pub fn init(config: config::Config) -> Peripherals {
|
||||
// UICR.APPROTECT = Enabled
|
||||
let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_ENABLED);
|
||||
needs_reset |= res == WriteResult::Written;
|
||||
#[cfg(any(feature = "_nrf5340-app", feature = "_nrf9160"))]
|
||||
#[cfg(any(feature = "_nrf5340-app", feature = "_nrf91"))]
|
||||
{
|
||||
let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_ENABLED);
|
||||
needs_reset |= res == WriteResult::Written;
|
||||
@ -552,7 +581,7 @@ pub fn init(config: config::Config) -> Peripherals {
|
||||
}
|
||||
|
||||
// Configure LFCLK.
|
||||
#[cfg(not(any(feature = "nrf51", feature = "_nrf5340", feature = "_nrf9160")))]
|
||||
#[cfg(not(any(feature = "nrf51", feature = "_nrf5340", feature = "_nrf91")))]
|
||||
match config.lfclk_source {
|
||||
config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()),
|
||||
config::LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()),
|
||||
@ -572,7 +601,7 @@ pub fn init(config: config::Config) -> Peripherals {
|
||||
w
|
||||
}),
|
||||
}
|
||||
#[cfg(feature = "_nrf9160")]
|
||||
#[cfg(feature = "_nrf91")]
|
||||
match config.lfclk_source {
|
||||
config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().lfrc()),
|
||||
config::LfclkSource::ExternalXtal => r.lfclksrc.write(|w| w.src().lfxo()),
|
||||
@ -585,7 +614,7 @@ pub fn init(config: config::Config) -> Peripherals {
|
||||
r.tasks_lfclkstart.write(|w| unsafe { w.bits(1) });
|
||||
while r.events_lfclkstarted.read().bits() == 0 {}
|
||||
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
|
||||
{
|
||||
// Setup DCDCs.
|
||||
let pwr = unsafe { &*pac::POWER::ptr() };
|
||||
@ -597,7 +626,7 @@ pub fn init(config: config::Config) -> Peripherals {
|
||||
pwr.dcdcen.write(|w| w.dcdcen().set_bit());
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "_nrf9160")]
|
||||
#[cfg(feature = "_nrf91")]
|
||||
{
|
||||
// Setup DCDC.
|
||||
let reg = unsafe { &*pac::REGULATORS::ptr() };
|
||||
@ -629,7 +658,7 @@ pub fn init(config: config::Config) -> Peripherals {
|
||||
time_driver::init(config.time_interrupt_priority);
|
||||
|
||||
// Disable UARTE (enabled by default for some reason)
|
||||
#[cfg(feature = "_nrf9160")]
|
||||
#[cfg(feature = "_nrf91")]
|
||||
unsafe {
|
||||
(*pac::UARTE0::ptr()).enable.write(|w| w.enable().disabled());
|
||||
(*pac::UARTE1::ptr()).enable.write(|w| w.enable().disabled());
|
||||
|
@ -60,23 +60,23 @@ impl<'d> Nvmc<'d> {
|
||||
while p.ready.read().ready().is_busy() {}
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340")))]
|
||||
#[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))]
|
||||
fn wait_ready_write(&mut self) {
|
||||
self.wait_ready();
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "_nrf9160", feature = "_nrf5340"))]
|
||||
#[cfg(any(feature = "_nrf91", feature = "_nrf5340"))]
|
||||
fn wait_ready_write(&mut self) {
|
||||
let p = Self::regs();
|
||||
while p.readynext.read().readynext().is_busy() {}
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340")))]
|
||||
#[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))]
|
||||
fn erase_page(&mut self, page_addr: u32) {
|
||||
Self::regs().erasepage().write(|w| unsafe { w.bits(page_addr) });
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "_nrf9160", feature = "_nrf5340"))]
|
||||
#[cfg(any(feature = "_nrf91", feature = "_nrf5340"))]
|
||||
fn erase_page(&mut self, page_addr: u32) {
|
||||
let first_page_word = page_addr as *mut u32;
|
||||
unsafe {
|
||||
|
@ -21,7 +21,7 @@ pub use crate::pac::pdm::pdmclkctrl::FREQ_A as Frequency;
|
||||
feature = "nrf52840",
|
||||
feature = "nrf52833",
|
||||
feature = "_nrf5340-app",
|
||||
feature = "_nrf9160",
|
||||
feature = "_nrf91",
|
||||
))]
|
||||
pub use crate::pac::pdm::ratio::RATIO_A as Ratio;
|
||||
use crate::{interrupt, Peripheral};
|
||||
@ -121,7 +121,7 @@ impl<'d, T: Instance> Pdm<'d, T> {
|
||||
feature = "nrf52840",
|
||||
feature = "nrf52833",
|
||||
feature = "_nrf5340-app",
|
||||
feature = "_nrf9160",
|
||||
feature = "_nrf91",
|
||||
))]
|
||||
r.ratio.write(|w| w.ratio().variant(config.ratio));
|
||||
r.mode.write(|w| {
|
||||
@ -374,7 +374,7 @@ pub struct Config {
|
||||
feature = "nrf52840",
|
||||
feature = "nrf52833",
|
||||
feature = "_nrf5340-app",
|
||||
feature = "_nrf9160",
|
||||
feature = "_nrf91",
|
||||
))]
|
||||
pub ratio: Ratio,
|
||||
/// Gain left in dB
|
||||
@ -393,7 +393,7 @@ impl Default for Config {
|
||||
feature = "nrf52840",
|
||||
feature = "nrf52833",
|
||||
feature = "_nrf5340-app",
|
||||
feature = "_nrf9160",
|
||||
feature = "_nrf91",
|
||||
))]
|
||||
ratio: Ratio::RATIO80,
|
||||
gain_left: I7F1::ZERO,
|
||||
|
@ -722,9 +722,9 @@ macro_rules! impl_saadc_input {
|
||||
pub struct VddInput;
|
||||
|
||||
impl_peripheral!(VddInput);
|
||||
#[cfg(not(feature = "_nrf9160"))]
|
||||
#[cfg(not(feature = "_nrf91"))]
|
||||
impl_saadc_input!(@local, VddInput, VDD);
|
||||
#[cfg(feature = "_nrf9160")]
|
||||
#[cfg(feature = "_nrf91")]
|
||||
impl_saadc_input!(@local, VddInput, VDDGPIO);
|
||||
|
||||
/// A dummy `Input` pin implementation for SAADC peripheral sampling from the
|
||||
|
@ -30,9 +30,9 @@ impl Config {
|
||||
pub fn try_new(_wdt: &peripherals::WDT) -> Option<Self> {
|
||||
let r = unsafe { &*WDT::ptr() };
|
||||
|
||||
#[cfg(not(feature = "_nrf9160"))]
|
||||
#[cfg(not(feature = "_nrf91"))]
|
||||
let runstatus = r.runstatus.read().runstatus().bit();
|
||||
#[cfg(feature = "_nrf9160")]
|
||||
#[cfg(feature = "_nrf91")]
|
||||
let runstatus = r.runstatus.read().runstatuswdt().bit();
|
||||
|
||||
if runstatus {
|
||||
@ -83,9 +83,9 @@ impl Watchdog {
|
||||
let crv = config.timeout_ticks.max(MIN_TICKS);
|
||||
let rren = (1u32 << N) - 1;
|
||||
|
||||
#[cfg(not(feature = "_nrf9160"))]
|
||||
#[cfg(not(feature = "_nrf91"))]
|
||||
let runstatus = r.runstatus.read().runstatus().bit();
|
||||
#[cfg(feature = "_nrf9160")]
|
||||
#[cfg(feature = "_nrf91")]
|
||||
let runstatus = r.runstatus.read().runstatuswdt().bit();
|
||||
|
||||
if runstatus {
|
||||
|
32
embassy-rp/CHANGELOG.md
Normal file
32
embassy-rp/CHANGELOG.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Changelog for embassy-rp
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 0.2.0 - 2024-08-05
|
||||
|
||||
- Add read_to_break_with_count
|
||||
- add option to provide your own boot2
|
||||
- Add multichannel ADC
|
||||
- Add collapse_debuginfo to fmt.rs macros.
|
||||
- Use raw slices .len() method instead of unsafe hacks.
|
||||
- Add missing word "pin" in rp pwm documentation
|
||||
- Add Clone and Copy to Error types
|
||||
- fix spinlocks staying locked after reset.
|
||||
- wait until read matches for PSM accesses.
|
||||
- Remove generics
|
||||
- fix drop implementation of BufferedUartRx and BufferedUartTx
|
||||
- implement `embedded_storage_async::nor_flash::MultiwriteNorFlash`
|
||||
- rp usb: wake ep-wakers after stalling
|
||||
- rp usb: add stall implementation
|
||||
- Add parameter for enabling pull-up and pull-down in RP PWM input mode
|
||||
- rp: remove mod sealed.
|
||||
- rename pins data type and the macro
|
||||
- rename pwm channels to pwm slices, including in documentation
|
||||
- rename the Channel trait to Slice and the PwmPin to PwmChannel
|
||||
- i2c: Fix race condition that appears on fast repeated transfers.
|
||||
- Add a basic "read to break" function
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "embassy-rp"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "Embassy Hardware Abstraction Layer (HAL) for the Raspberry Pi RP2040 microcontroller"
|
||||
@ -91,10 +91,10 @@ boot2-none = []
|
||||
[dependencies]
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||
embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true }
|
||||
embassy-time = { version = "0.3.1", path = "../embassy-time" }
|
||||
embassy-time = { version = "0.3.2", path = "../embassy-time" }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
|
||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
|
||||
embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" }
|
||||
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" }
|
||||
atomic-polyfill = "1.0.1"
|
||||
defmt = { version = "0.3", optional = true }
|
||||
@ -125,5 +125,5 @@ rp2040-boot2 = "0.3"
|
||||
document-features = "0.2.7"
|
||||
|
||||
[dev-dependencies]
|
||||
embassy-executor = { version = "0.5.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] }
|
||||
embassy-executor = { version = "0.6.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] }
|
||||
static_cell = { version = "2" }
|
||||
|
@ -23,5 +23,5 @@ The `embassy-rp` HAL implements the traits from [embedded-hal](https://crates.io
|
||||
|
||||
This crate can run on any executor.
|
||||
|
||||
Optionally, some features requiring [`embassy-time`](https://crates.io/crates/embassy-time) can be activated with the `time` feature. If you enable it,
|
||||
Optionally, some features requiring [`embassy-time`](https://crates.io/crates/embassy-time) can be activated with the `time-driver` feature. If you enable it,
|
||||
you must link an `embassy-time` driver in your project.
|
||||
|
@ -57,9 +57,9 @@ mod ram_helpers {
|
||||
"str {val}, [{cs_gpio}, $GPIO_CTRL]",
|
||||
|
||||
// ...then wait for the state to settle...
|
||||
"1:", // ~4000 cycle delay loop
|
||||
"2:", // ~4000 cycle delay loop
|
||||
"subs {val}, #8",
|
||||
"bne 1b",
|
||||
"bne 2b",
|
||||
|
||||
// ...we can read the current state of bootsel
|
||||
"ldr {val}, [{cs_gpio}, $GPIO_STATUS]",
|
||||
|
@ -625,18 +625,18 @@ mod ram_helpers {
|
||||
"movs r3, #0", // r3 = 0
|
||||
"ldr r4, [{ptrs}, #8]",
|
||||
"cmp r4, #0",
|
||||
"beq 1f",
|
||||
"beq 2f",
|
||||
"blx r4", // flash_range_erase(addr, len, 1 << 31, 0)
|
||||
"1:",
|
||||
"2:",
|
||||
|
||||
"mov r0, r8", // r0 = addr
|
||||
"mov r1, r9", // r0 = data
|
||||
"mov r2, r10", // r2 = len
|
||||
"ldr r4, [{ptrs}, #12]",
|
||||
"cmp r4, #0",
|
||||
"beq 1f",
|
||||
"beq 2f",
|
||||
"blx r4", // flash_range_program(addr, data, len);
|
||||
"1:",
|
||||
"2:",
|
||||
|
||||
"ldr r4, [{ptrs}, #16]",
|
||||
"blx r4", // flash_flush_cache();
|
||||
@ -802,12 +802,12 @@ mod ram_helpers {
|
||||
"adds r2, 0x60", // &DR
|
||||
"ldr r0, [r3, #0]", // cmd_addr
|
||||
"ldr r1, [r3, #4]", // cmd_addr_len
|
||||
"10:",
|
||||
"3:",
|
||||
"ldrb r3, [r0]",
|
||||
"strb r3, [r2]", // DR
|
||||
"adds r0, #1",
|
||||
"subs r1, #1",
|
||||
"bne 10b",
|
||||
"bne 3b",
|
||||
|
||||
// Skip any dummy cycles
|
||||
"mov r3, r10", // cmd
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -312,13 +312,13 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Read from address into buffer using DMA.
|
||||
/// Read from address into buffer asynchronously.
|
||||
pub async fn read_async(&mut self, addr: impl Into<u16>, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
Self::setup(addr.into())?;
|
||||
self.read_async_internal(buffer, true, true).await
|
||||
}
|
||||
|
||||
/// Write to address from buffer using DMA.
|
||||
/// Write to address from buffer asynchronously.
|
||||
pub async fn write_async(
|
||||
&mut self,
|
||||
addr: impl Into<u16>,
|
||||
@ -328,7 +328,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
|
||||
self.write_async_internal(bytes, true).await
|
||||
}
|
||||
|
||||
/// Write to address from bytes and read from address into buffer using DMA.
|
||||
/// Write to address from bytes and read from address into buffer asynchronously.
|
||||
pub async fn write_read_async(
|
||||
&mut self,
|
||||
addr: impl Into<u16>,
|
||||
@ -779,9 +779,6 @@ pub fn i2c_reserved_addr(addr: u16) -> bool {
|
||||
}
|
||||
|
||||
pub(crate) trait SealedInstance {
|
||||
const TX_DREQ: u8;
|
||||
const RX_DREQ: u8;
|
||||
|
||||
fn regs() -> crate::pac::i2c::I2c;
|
||||
fn reset() -> crate::pac::resets::regs::Peripherals;
|
||||
fn waker() -> &'static AtomicWaker;
|
||||
@ -816,11 +813,8 @@ pub trait Instance: SealedInstance {
|
||||
}
|
||||
|
||||
macro_rules! impl_instance {
|
||||
($type:ident, $irq:ident, $reset:ident, $tx_dreq:expr, $rx_dreq:expr) => {
|
||||
($type:ident, $irq:ident, $reset:ident) => {
|
||||
impl SealedInstance for peripherals::$type {
|
||||
const TX_DREQ: u8 = $tx_dreq;
|
||||
const RX_DREQ: u8 = $rx_dreq;
|
||||
|
||||
#[inline]
|
||||
fn regs() -> pac::i2c::I2c {
|
||||
pac::$type
|
||||
@ -846,8 +840,8 @@ macro_rules! impl_instance {
|
||||
};
|
||||
}
|
||||
|
||||
impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33);
|
||||
impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35);
|
||||
impl_instance!(I2C0, I2C0_IRQ, set_i2c0);
|
||||
impl_instance!(I2C1, I2C1_IRQ, set_i2c1);
|
||||
|
||||
/// SDA pin.
|
||||
pub trait SdaPin<T: Instance>: crate::gpio::Pin {}
|
||||
|
@ -163,9 +163,21 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
|
||||
self.tx.send_break(bits).await
|
||||
}
|
||||
|
||||
/// sets baudrate on runtime
|
||||
pub fn set_baudrate(&mut self, baudrate: u32) {
|
||||
super::Uart::<'d, T, Async>::set_baudrate_inner(baudrate);
|
||||
}
|
||||
|
||||
/// Split into separate RX and TX handles.
|
||||
pub fn split(self) -> (BufferedUartRx<'d, T>, BufferedUartTx<'d, T>) {
|
||||
(self.rx, self.tx)
|
||||
pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) {
|
||||
(self.tx, self.rx)
|
||||
}
|
||||
|
||||
/// Split the Uart into a transmitter and receiver by mutable reference,
|
||||
/// which is particularly useful when having two tasks correlating to
|
||||
/// transmitting and receiving.
|
||||
pub fn split_ref(&mut self) -> (&mut BufferedUartTx<'d, T>, &mut BufferedUartRx<'d, T>) {
|
||||
(&mut self.tx, &mut self.rx)
|
||||
}
|
||||
}
|
||||
|
||||
@ -315,6 +327,12 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
||||
w.set_rtim(true);
|
||||
});
|
||||
}
|
||||
|
||||
/// we are ready to read if there is data in the buffer
|
||||
fn read_ready() -> Result<bool, Error> {
|
||||
let state = T::buffered_state();
|
||||
Ok(!state.rx_buf.is_empty())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
||||
@ -621,6 +639,18 @@ impl<'d, T: Instance + 'd> embedded_io_async::Read for BufferedUartRx<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io_async::ReadReady for BufferedUart<'d, T> {
|
||||
fn read_ready(&mut self) -> Result<bool, Self::Error> {
|
||||
BufferedUartRx::<'d, T>::read_ready()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io_async::ReadReady for BufferedUartRx<'d, T> {
|
||||
fn read_ready(&mut self) -> Result<bool, Self::Error> {
|
||||
Self::read_ready()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd> embedded_io_async::BufRead for BufferedUart<'d, T> {
|
||||
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
|
||||
BufferedUartRx::<'d, T>::fill_buf().await
|
||||
|
@ -7,7 +7,7 @@ use atomic_polyfill::{AtomicU16, Ordering};
|
||||
use embassy_futures::select::{select, Either};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use embassy_time::Timer;
|
||||
use embassy_time::{Delay, Timer};
|
||||
use pac::uart::regs::Uartris;
|
||||
|
||||
use crate::clocks::clk_peri_freq;
|
||||
@ -490,6 +490,36 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
||||
/// * The first call to `read_to_break()` will return `Ok(20)`.
|
||||
/// * The next call to `read_to_break()` will work as expected
|
||||
pub async fn read_to_break(&mut self, buffer: &mut [u8]) -> Result<usize, ReadToBreakError> {
|
||||
self.read_to_break_with_count(buffer, 0).await
|
||||
}
|
||||
|
||||
/// Read from the UART, waiting for a line break as soon as at least `min_count` bytes have been read.
|
||||
///
|
||||
/// We read until one of the following occurs:
|
||||
///
|
||||
/// * We read `buffer.len()` bytes without a line break
|
||||
/// * returns `Err(ReadToBreakError::MissingBreak(buffer.len()))`
|
||||
/// * We read `n > min_count` bytes then a line break occurs
|
||||
/// * returns `Ok(n)`
|
||||
/// * We encounter some error OTHER than a line break
|
||||
/// * returns `Err(ReadToBreakError::Other(error))`
|
||||
///
|
||||
/// If a line break occurs before `min_count` bytes have been read, the break will be ignored and the read will continue
|
||||
///
|
||||
/// **NOTE**: you MUST provide a buffer one byte larger than your largest expected
|
||||
/// message to reliably detect the framing on one single call to `read_to_break()`.
|
||||
///
|
||||
/// * If you expect a message of 20 bytes + line break, and provide a 20-byte buffer:
|
||||
/// * The first call to `read_to_break()` will return `Err(ReadToBreakError::MissingBreak(20))`
|
||||
/// * The next call to `read_to_break()` will immediately return `Ok(0)`, from the "stale" line break
|
||||
/// * If you expect a message of 20 bytes + line break, and provide a 21-byte buffer:
|
||||
/// * The first call to `read_to_break()` will return `Ok(20)`.
|
||||
/// * The next call to `read_to_break()` will work as expected
|
||||
pub async fn read_to_break_with_count(
|
||||
&mut self,
|
||||
buffer: &mut [u8],
|
||||
min_count: usize,
|
||||
) -> Result<usize, ReadToBreakError> {
|
||||
// clear error flags before we drain the fifo. errors that have accumulated
|
||||
// in the flags will also be present in the fifo.
|
||||
T::dma_state().rx_errs.store(0, Ordering::Relaxed);
|
||||
@ -502,7 +532,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
||||
|
||||
// then drain the fifo. we need to read at most 32 bytes. errors that apply
|
||||
// to fifo bytes will be reported directly.
|
||||
let sbuffer = match {
|
||||
let mut sbuffer = match {
|
||||
let limit = buffer.len().min(32);
|
||||
self.drain_fifo(&mut buffer[0..limit])
|
||||
} {
|
||||
@ -511,7 +541,13 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
||||
// Drained (some/all of the fifo), no room left
|
||||
Ok(len) => return Err(ReadToBreakError::MissingBreak(len)),
|
||||
// We got a break WHILE draining the FIFO, return what we did get before the break
|
||||
Err((i, Error::Break)) => return Ok(i),
|
||||
Err((len, Error::Break)) => {
|
||||
if len < min_count && len < buffer.len() {
|
||||
&mut buffer[len..]
|
||||
} else {
|
||||
return Ok(len);
|
||||
}
|
||||
}
|
||||
// Some other error, just return the error
|
||||
Err((_i, e)) => return Err(ReadToBreakError::Other(e)),
|
||||
};
|
||||
@ -530,110 +566,118 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
||||
reg.set_rxdmae(true);
|
||||
reg.set_dmaonerr(true);
|
||||
});
|
||||
let transfer = unsafe {
|
||||
// If we don't assign future to a variable, the data register pointer
|
||||
// is held across an await and makes the future non-Send.
|
||||
crate::dma::read(&mut ch, T::regs().uartdr().as_ptr() as *const _, sbuffer, T::RX_DREQ)
|
||||
};
|
||||
|
||||
// wait for either the transfer to complete or an error to happen.
|
||||
let transfer_result = select(
|
||||
transfer,
|
||||
poll_fn(|cx| {
|
||||
T::dma_state().rx_err_waker.register(cx.waker());
|
||||
match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) {
|
||||
0 => Poll::Pending,
|
||||
e => Poll::Ready(Uartris(e as u32)),
|
||||
loop {
|
||||
let transfer = unsafe {
|
||||
// If we don't assign future to a variable, the data register pointer
|
||||
// is held across an await and makes the future non-Send.
|
||||
crate::dma::read(&mut ch, T::regs().uartdr().as_ptr() as *const _, sbuffer, T::RX_DREQ)
|
||||
};
|
||||
|
||||
// wait for either the transfer to complete or an error to happen.
|
||||
let transfer_result = select(
|
||||
transfer,
|
||||
poll_fn(|cx| {
|
||||
T::dma_state().rx_err_waker.register(cx.waker());
|
||||
match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) {
|
||||
0 => Poll::Pending,
|
||||
e => Poll::Ready(Uartris(e as u32)),
|
||||
}
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
// Figure out our error state
|
||||
let errors = match transfer_result {
|
||||
Either::First(()) => {
|
||||
// We're here because the DMA finished, BUT if an error occurred on the LAST
|
||||
// byte, then we may still need to grab the error state!
|
||||
Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32)
|
||||
}
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
// Figure out our error state
|
||||
let errors = match transfer_result {
|
||||
Either::First(()) => {
|
||||
// We're here because the DMA finished, BUT if an error occurred on the LAST
|
||||
// byte, then we may still need to grab the error state!
|
||||
Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32)
|
||||
}
|
||||
Either::Second(e) => {
|
||||
// We're here because we errored, which means this is the error that
|
||||
// was problematic.
|
||||
e
|
||||
}
|
||||
};
|
||||
|
||||
if errors.0 == 0 {
|
||||
// No errors? That means we filled the buffer without a line break.
|
||||
// For THIS function, that's a problem.
|
||||
return Err(ReadToBreakError::MissingBreak(buffer.len()));
|
||||
} else if errors.beris() {
|
||||
// We got a Line Break! By this point, we've finished/aborted the DMA
|
||||
// transaction, which means that we need to figure out where it left off
|
||||
// by looking at the write_addr.
|
||||
//
|
||||
// First, we do a sanity check to make sure the write value is within the
|
||||
// range of DMA we just did.
|
||||
let sval = buffer.as_ptr() as usize;
|
||||
let eval = sval + buffer.len();
|
||||
|
||||
// This is the address where the DMA would write to next
|
||||
let next_addr = ch.regs().write_addr().read() as usize;
|
||||
|
||||
// If we DON'T end up inside the range, something has gone really wrong.
|
||||
// Note that it's okay that `eval` is one past the end of the slice, as
|
||||
// this is where the write pointer will end up at the end of a full
|
||||
// transfer.
|
||||
if (next_addr < sval) || (next_addr > eval) {
|
||||
unreachable!("UART DMA reported invalid `write_addr`");
|
||||
}
|
||||
|
||||
let regs = T::regs();
|
||||
let all_full = next_addr == eval;
|
||||
|
||||
// NOTE: This is off label usage of RSR! See the issue below for
|
||||
// why I am not checking if there is an "extra" FIFO byte, and why
|
||||
// I am checking RSR directly (it seems to report the status of the LAST
|
||||
// POPPED value, rather than the NEXT TO POP value like the datasheet
|
||||
// suggests!)
|
||||
//
|
||||
// issue: https://github.com/raspberrypi/pico-feedback/issues/367
|
||||
let last_was_break = regs.uartrsr().read().be();
|
||||
|
||||
return match (all_full, last_was_break) {
|
||||
(true, true) | (false, _) => {
|
||||
// We got less than the full amount + a break, or the full amount
|
||||
// and the last byte was a break. Subtract the break off by adding one to sval.
|
||||
Ok(next_addr.saturating_sub(1 + sval))
|
||||
}
|
||||
(true, false) => {
|
||||
// We finished the whole DMA, and the last DMA'd byte was NOT a break
|
||||
// character. This is an error.
|
||||
//
|
||||
// NOTE: we COULD potentially return Ok(buffer.len()) here, since we
|
||||
// know a line break occured at SOME POINT after the DMA completed.
|
||||
//
|
||||
// However, we have no way of knowing if there was extra data BEFORE
|
||||
// that line break, so instead return an Err to signal to the caller
|
||||
// that there are "leftovers", and they'll catch the actual line break
|
||||
// on the next call.
|
||||
//
|
||||
// Doing it like this also avoids racyness: now whether you finished
|
||||
// the full read BEFORE the line break occurred or AFTER the line break
|
||||
// occurs, you still get `MissingBreak(buffer.len())` instead of sometimes
|
||||
// getting `Ok(buffer.len())` if you were "late enough" to observe the
|
||||
// line break.
|
||||
Err(ReadToBreakError::MissingBreak(buffer.len()))
|
||||
Either::Second(e) => {
|
||||
// We're here because we errored, which means this is the error that
|
||||
// was problematic.
|
||||
e
|
||||
}
|
||||
};
|
||||
} else if errors.oeris() {
|
||||
return Err(ReadToBreakError::Other(Error::Overrun));
|
||||
} else if errors.peris() {
|
||||
return Err(ReadToBreakError::Other(Error::Parity));
|
||||
} else if errors.feris() {
|
||||
return Err(ReadToBreakError::Other(Error::Framing));
|
||||
|
||||
if errors.0 == 0 {
|
||||
// No errors? That means we filled the buffer without a line break.
|
||||
// For THIS function, that's a problem.
|
||||
return Err(ReadToBreakError::MissingBreak(buffer.len()));
|
||||
} else if errors.beris() {
|
||||
// We got a Line Break! By this point, we've finished/aborted the DMA
|
||||
// transaction, which means that we need to figure out where it left off
|
||||
// by looking at the write_addr.
|
||||
//
|
||||
// First, we do a sanity check to make sure the write value is within the
|
||||
// range of DMA we just did.
|
||||
let sval = buffer.as_ptr() as usize;
|
||||
let eval = sval + buffer.len();
|
||||
|
||||
// This is the address where the DMA would write to next
|
||||
let next_addr = ch.regs().write_addr().read() as usize;
|
||||
|
||||
// If we DON'T end up inside the range, something has gone really wrong.
|
||||
// Note that it's okay that `eval` is one past the end of the slice, as
|
||||
// this is where the write pointer will end up at the end of a full
|
||||
// transfer.
|
||||
if (next_addr < sval) || (next_addr > eval) {
|
||||
unreachable!("UART DMA reported invalid `write_addr`");
|
||||
}
|
||||
|
||||
if (next_addr - sval) < min_count {
|
||||
sbuffer = &mut buffer[(next_addr - sval)..];
|
||||
continue;
|
||||
}
|
||||
|
||||
let regs = T::regs();
|
||||
let all_full = next_addr == eval;
|
||||
|
||||
// NOTE: This is off label usage of RSR! See the issue below for
|
||||
// why I am not checking if there is an "extra" FIFO byte, and why
|
||||
// I am checking RSR directly (it seems to report the status of the LAST
|
||||
// POPPED value, rather than the NEXT TO POP value like the datasheet
|
||||
// suggests!)
|
||||
//
|
||||
// issue: https://github.com/raspberrypi/pico-feedback/issues/367
|
||||
let last_was_break = regs.uartrsr().read().be();
|
||||
|
||||
return match (all_full, last_was_break) {
|
||||
(true, true) | (false, _) => {
|
||||
// We got less than the full amount + a break, or the full amount
|
||||
// and the last byte was a break. Subtract the break off by adding one to sval.
|
||||
Ok(next_addr.saturating_sub(1 + sval))
|
||||
}
|
||||
(true, false) => {
|
||||
// We finished the whole DMA, and the last DMA'd byte was NOT a break
|
||||
// character. This is an error.
|
||||
//
|
||||
// NOTE: we COULD potentially return Ok(buffer.len()) here, since we
|
||||
// know a line break occured at SOME POINT after the DMA completed.
|
||||
//
|
||||
// However, we have no way of knowing if there was extra data BEFORE
|
||||
// that line break, so instead return an Err to signal to the caller
|
||||
// that there are "leftovers", and they'll catch the actual line break
|
||||
// on the next call.
|
||||
//
|
||||
// Doing it like this also avoids racyness: now whether you finished
|
||||
// the full read BEFORE the line break occurred or AFTER the line break
|
||||
// occurs, you still get `MissingBreak(buffer.len())` instead of sometimes
|
||||
// getting `Ok(buffer.len())` if you were "late enough" to observe the
|
||||
// line break.
|
||||
Err(ReadToBreakError::MissingBreak(buffer.len()))
|
||||
}
|
||||
};
|
||||
} else if errors.oeris() {
|
||||
return Err(ReadToBreakError::Other(Error::Overrun));
|
||||
} else if errors.peris() {
|
||||
return Err(ReadToBreakError::Other(Error::Parity));
|
||||
} else if errors.feris() {
|
||||
return Err(ReadToBreakError::Other(Error::Framing));
|
||||
}
|
||||
unreachable!("unrecognized rx error");
|
||||
}
|
||||
unreachable!("unrecognized rx error");
|
||||
}
|
||||
}
|
||||
|
||||
@ -860,6 +904,56 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
||||
});
|
||||
}
|
||||
|
||||
fn lcr_modify<R>(f: impl FnOnce(&mut rp_pac::uart::regs::UartlcrH) -> R) -> R {
|
||||
let r = T::regs();
|
||||
|
||||
// Notes from PL011 reference manual:
|
||||
//
|
||||
// - Before writing the LCR, if the UART is enabled it needs to be
|
||||
// disabled and any current TX + RX activity has to be completed
|
||||
//
|
||||
// - There is a BUSY flag which waits for the current TX char, but this is
|
||||
// OR'd with TX FIFO !FULL, so not usable when FIFOs are enabled and
|
||||
// potentially nonempty
|
||||
//
|
||||
// - FIFOs can't be set to disabled whilst a character is in progress
|
||||
// (else "FIFO integrity is not guaranteed")
|
||||
//
|
||||
// Combination of these means there is no general way to halt and poll for
|
||||
// end of TX character, if FIFOs may be enabled. Either way, there is no
|
||||
// way to poll for end of RX character.
|
||||
//
|
||||
// So, insert a 15 Baud period delay before changing the settings.
|
||||
// 15 Baud is comfortably higher than start + max data + parity + stop.
|
||||
// Anything else would require API changes to permit a non-enabled UART
|
||||
// state after init() where settings can be changed safely.
|
||||
let clk_base = crate::clocks::clk_peri_freq();
|
||||
|
||||
let cr = r.uartcr().read();
|
||||
if cr.uarten() {
|
||||
r.uartcr().modify(|w| {
|
||||
w.set_uarten(false);
|
||||
w.set_txe(false);
|
||||
w.set_rxe(false);
|
||||
});
|
||||
|
||||
// Note: Maximise precision here. Show working, the compiler will mop this up.
|
||||
// Create a 16.6 fixed-point fractional division ratio; then scale to 32-bits.
|
||||
let mut brdiv_ratio = 64 * r.uartibrd().read().0 + r.uartfbrd().read().0;
|
||||
brdiv_ratio <<= 10;
|
||||
// 3662 is ~(15 * 244.14) where 244.14 is 16e6 / 2^16
|
||||
let scaled_freq = clk_base / 3662;
|
||||
let wait_time_us = brdiv_ratio / scaled_freq;
|
||||
embedded_hal_1::delay::DelayNs::delay_us(&mut Delay, wait_time_us);
|
||||
}
|
||||
|
||||
let res = r.uartlcr_h().modify(f);
|
||||
|
||||
r.uartcr().write_value(cr);
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
/// sets baudrate on runtime
|
||||
pub fn set_baudrate(&mut self, baudrate: u32) {
|
||||
Self::set_baudrate_inner(baudrate);
|
||||
@ -886,9 +980,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
||||
r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
|
||||
r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
|
||||
|
||||
// PL011 needs a (dummy) line control register write to latch in the
|
||||
// divisors. We don't want to actually change LCR contents here.
|
||||
r.uartlcr_h().modify(|_| {});
|
||||
Self::lcr_modify(|_| {});
|
||||
}
|
||||
}
|
||||
|
||||
@ -923,6 +1015,13 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
|
||||
pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) {
|
||||
(self.tx, self.rx)
|
||||
}
|
||||
|
||||
/// Split the Uart into a transmitter and receiver by mutable reference,
|
||||
/// which is particularly useful when having two tasks correlating to
|
||||
/// transmitting and receiving.
|
||||
pub fn split_ref(&mut self) -> (&mut UartTx<'d, T, M>, &mut UartRx<'d, T, M>) {
|
||||
(&mut self.tx, &mut self.rx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Uart<'d, T, Async> {
|
||||
@ -942,6 +1041,17 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
|
||||
pub async fn read_to_break<'a>(&mut self, buf: &'a mut [u8]) -> Result<usize, ReadToBreakError> {
|
||||
self.rx.read_to_break(buf).await
|
||||
}
|
||||
|
||||
/// Read until the buffer is full or a line break occurs after at least `min_count` bytes have been read.
|
||||
///
|
||||
/// See [`UartRx::read_to_break_with_count()`] for more details
|
||||
pub async fn read_to_break_with_count<'a>(
|
||||
&mut self,
|
||||
buf: &'a mut [u8],
|
||||
min_count: usize,
|
||||
) -> Result<usize, ReadToBreakError> {
|
||||
self.rx.read_to_break_with_count(buf, min_count).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> {
|
||||
|
@ -21,10 +21,10 @@ features = ["stm32wb55rg"]
|
||||
[dependencies]
|
||||
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" }
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||
embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true }
|
||||
embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" }
|
||||
embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal" }
|
||||
embassy-embedded-hal = { version = "0.2.0", path = "../embassy-embedded-hal" }
|
||||
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true }
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -43,15 +43,15 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[dependencies]
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||
embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true }
|
||||
embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true }
|
||||
embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] }
|
||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] }
|
||||
embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" }
|
||||
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
||||
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" }
|
||||
embassy-usb-synopsys-otg = {version = "0.1.0", path = "../embassy-usb-synopsys-otg" }
|
||||
embassy-executor = { version = "0.5.0", path = "../embassy-executor", optional = true }
|
||||
embassy-executor = { version = "0.6.0", path = "../embassy-executor", optional = true }
|
||||
|
||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
||||
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
|
||||
|
@ -8,8 +8,6 @@
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::process::Command;
|
||||
|
||||
/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
|
||||
/// them (`cargo:rust-check-cfg=cfg(X)`).
|
||||
@ -17,7 +15,6 @@ use std::process::Command;
|
||||
pub struct CfgSet {
|
||||
enabled: HashSet<String>,
|
||||
declared: HashSet<String>,
|
||||
emit_declared: bool,
|
||||
}
|
||||
|
||||
impl CfgSet {
|
||||
@ -25,7 +22,6 @@ impl CfgSet {
|
||||
Self {
|
||||
enabled: HashSet::new(),
|
||||
declared: HashSet::new(),
|
||||
emit_declared: is_rustc_nightly(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +45,7 @@ impl CfgSet {
|
||||
///
|
||||
/// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
|
||||
pub fn declare(&mut self, cfg: impl AsRef<str>) {
|
||||
if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared {
|
||||
if self.declared.insert(cfg.as_ref().to_owned()) {
|
||||
println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
|
||||
}
|
||||
}
|
||||
@ -69,21 +65,6 @@ impl CfgSet {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_rustc_nightly() -> bool {
|
||||
if env::var_os("EMBASSY_FORCE_CHECK_CFG").is_some() {
|
||||
return true;
|
||||
}
|
||||
|
||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
|
||||
|
||||
let output = Command::new(rustc)
|
||||
.arg("--version")
|
||||
.output()
|
||||
.expect("failed to run `rustc --version`");
|
||||
|
||||
String::from_utf8_lossy(&output.stdout).contains("nightly")
|
||||
}
|
||||
|
||||
/// Sets configs that describe the target platform.
|
||||
pub fn set_target_cfgs(cfgs: &mut CfgSet) {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#![macro_use]
|
||||
#![allow(missing_docs)] // TODO
|
||||
#![cfg_attr(adc_f3_v2, allow(unused))]
|
||||
|
||||
#[cfg(not(adc_f3_v2))]
|
||||
#[cfg_attr(adc_f1, path = "f1.rs")]
|
||||
|
@ -42,9 +42,11 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
|
||||
|
||||
// prevents parallelism errors
|
||||
fence(Ordering::SeqCst);
|
||||
|
||||
wait_ready_blocking()?;
|
||||
}
|
||||
|
||||
wait_ready_blocking()
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
|
||||
|
@ -160,6 +160,26 @@ impl<'d, T: Instance> Fmc<'d, T> {
|
||||
]
|
||||
));
|
||||
|
||||
fmc_sdram_constructor!(sdram_a13bits_d32bits_4banks_bank1: (
|
||||
bank: stm32_fmc::SdramTargetBank::Bank1,
|
||||
addr: [
|
||||
(a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin), (a12: A12Pin)
|
||||
],
|
||||
ba: [(ba0: BA0Pin), (ba1: BA1Pin)],
|
||||
d: [
|
||||
(d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin),
|
||||
(d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin),
|
||||
(d16: D16Pin), (d17: D17Pin), (d18: D18Pin), (d19: D19Pin), (d20: D20Pin), (d21: D21Pin), (d22: D22Pin), (d23: D23Pin),
|
||||
(d24: D24Pin), (d25: D25Pin), (d26: D26Pin), (d27: D27Pin), (d28: D28Pin), (d29: D29Pin), (d30: D30Pin), (d31: D31Pin)
|
||||
],
|
||||
nbl: [
|
||||
(nbl0: NBL0Pin), (nbl1: NBL1Pin), (nbl2: NBL2Pin), (nbl3: NBL3Pin)
|
||||
],
|
||||
ctrl: [
|
||||
(sdcke: SDCKE0Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE0Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
|
||||
]
|
||||
));
|
||||
|
||||
fmc_sdram_constructor!(sdram_a12bits_d16bits_4banks_bank2: (
|
||||
bank: stm32_fmc::SdramTargetBank::Bank2,
|
||||
addr: [
|
||||
@ -197,6 +217,26 @@ impl<'d, T: Instance> Fmc<'d, T> {
|
||||
(sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
|
||||
]
|
||||
));
|
||||
|
||||
fmc_sdram_constructor!(sdram_a13bits_d32bits_4banks_bank2: (
|
||||
bank: stm32_fmc::SdramTargetBank::Bank2,
|
||||
addr: [
|
||||
(a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin), (a12: A12Pin)
|
||||
],
|
||||
ba: [(ba0: BA0Pin), (ba1: BA1Pin)],
|
||||
d: [
|
||||
(d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin),
|
||||
(d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin),
|
||||
(d16: D16Pin), (d17: D17Pin), (d18: D18Pin), (d19: D19Pin), (d20: D20Pin), (d21: D21Pin), (d22: D22Pin), (d23: D23Pin),
|
||||
(d24: D24Pin), (d25: D25Pin), (d26: D26Pin), (d27: D27Pin), (d28: D28Pin), (d29: D29Pin), (d30: D30Pin), (d31: D31Pin)
|
||||
],
|
||||
nbl: [
|
||||
(nbl0: NBL0Pin), (nbl1: NBL1Pin), (nbl2: NBL2Pin), (nbl3: NBL3Pin)
|
||||
],
|
||||
ctrl: [
|
||||
(sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
|
||||
]
|
||||
));
|
||||
}
|
||||
|
||||
trait SealedInstance: crate::rcc::RccPeripheral {
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -158,6 +158,11 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> {
|
||||
.modify(|w| w.set_ise(sem_x, enable));
|
||||
}
|
||||
|
||||
/// Gets the interrupt flag for the semaphore.
|
||||
pub fn is_interrupt_active(&mut self, core_id: CoreId, sem_x: usize) -> bool {
|
||||
T::regs().isr(core_id_to_index(core_id)).read().isf(sem_x)
|
||||
}
|
||||
|
||||
/// Clears the interrupt flag for the semaphore.
|
||||
pub fn clear_interrupt(&mut self, core_id: CoreId, sem_x: usize) {
|
||||
T::regs()
|
||||
|
@ -45,6 +45,7 @@ pub struct OpAmpOutput<'d, T: Instance> {
|
||||
/// OpAmp internal outputs, wired directly to ADC inputs.
|
||||
///
|
||||
/// This struct can be used as an ADC input.
|
||||
#[cfg(opamp_g4)]
|
||||
pub struct OpAmpInternalOutput<'d, T: Instance> {
|
||||
_inner: &'d OpAmp<'d, T>,
|
||||
}
|
||||
@ -80,11 +81,11 @@ impl<'d, T: Instance> OpAmp<'d, T> {
|
||||
/// directly used as an ADC input. The opamp will be disabled when the
|
||||
/// [`OpAmpOutput`] is dropped.
|
||||
pub fn buffer_ext(
|
||||
&'d mut self,
|
||||
&mut self,
|
||||
in_pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::Pin>,
|
||||
out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin> + 'd,
|
||||
out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin>,
|
||||
gain: OpAmpGain,
|
||||
) -> OpAmpOutput<'d, T> {
|
||||
) -> OpAmpOutput<'_, T> {
|
||||
into_ref!(in_pin);
|
||||
into_ref!(out_pin);
|
||||
in_pin.set_as_analog();
|
||||
@ -119,9 +120,9 @@ impl<'d, T: Instance> OpAmp<'d, T> {
|
||||
/// [`OpAmpOutput`] is dropped.
|
||||
#[cfg(opamp_g4)]
|
||||
pub fn buffer_dac(
|
||||
&'d mut self,
|
||||
out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin> + 'd,
|
||||
) -> OpAmpOutput<'d, T> {
|
||||
&mut self,
|
||||
out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin>,
|
||||
) -> OpAmpOutput<'_, T> {
|
||||
into_ref!(out_pin);
|
||||
out_pin.set_as_analog();
|
||||
|
||||
@ -147,10 +148,10 @@ impl<'d, T: Instance> OpAmp<'d, T> {
|
||||
/// The opamp output will be disabled when it is dropped.
|
||||
#[cfg(opamp_g4)]
|
||||
pub fn buffer_int(
|
||||
&'d mut self,
|
||||
&mut self,
|
||||
pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::Pin>,
|
||||
gain: OpAmpGain,
|
||||
) -> OpAmpInternalOutput<'d, T> {
|
||||
) -> OpAmpInternalOutput<'_, T> {
|
||||
into_ref!(pin);
|
||||
pin.set_as_analog();
|
||||
|
||||
@ -184,6 +185,7 @@ impl<'d, T: Instance> Drop for OpAmpOutput<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(opamp_g4)]
|
||||
impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> {
|
||||
fn drop(&mut self) {
|
||||
T::regs().csr().modify(|w| {
|
||||
|
@ -1060,10 +1060,6 @@ pub(crate) trait SealedInstance {
|
||||
const REGS: Regs;
|
||||
}
|
||||
|
||||
trait SealedWord {
|
||||
const CONFIG: u8;
|
||||
}
|
||||
|
||||
/// OSPI instance trait.
|
||||
#[allow(private_bounds)]
|
||||
pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {}
|
||||
@ -1110,17 +1106,14 @@ impl<'d, T: Instance, M: PeriMode> GetConfig for Ospi<'d, T, M> {
|
||||
|
||||
/// Word sizes usable for OSPI.
|
||||
#[allow(private_bounds)]
|
||||
pub trait Word: word::Word + SealedWord {}
|
||||
pub trait Word: word::Word {}
|
||||
|
||||
macro_rules! impl_word {
|
||||
($T:ty, $config:expr) => {
|
||||
impl SealedWord for $T {
|
||||
const CONFIG: u8 = $config;
|
||||
}
|
||||
($T:ty) => {
|
||||
impl Word for $T {}
|
||||
};
|
||||
}
|
||||
|
||||
impl_word!(u8, 8);
|
||||
impl_word!(u16, 16);
|
||||
impl_word!(u32, 32);
|
||||
impl_word!(u8);
|
||||
impl_word!(u16);
|
||||
impl_word!(u32);
|
||||
|
@ -94,6 +94,34 @@ impl DerefMut for DataBlock {
|
||||
}
|
||||
}
|
||||
|
||||
/// Command Block buffer for SDMMC command transfers.
|
||||
///
|
||||
/// This is a 16-word array, exposed so that DMA commpatible memory can be used if required.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct CmdBlock(pub [u32; 16]);
|
||||
|
||||
impl CmdBlock {
|
||||
/// Creates a new instance of CmdBlock
|
||||
pub const fn new() -> Self {
|
||||
Self([0u32; 16])
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for CmdBlock {
|
||||
type Target = [u32; 16];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for CmdBlock {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
@ -292,6 +320,10 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> {
|
||||
signalling: Signalling,
|
||||
/// Card
|
||||
card: Option<Card>,
|
||||
|
||||
/// An optional buffer to be used for commands
|
||||
/// This should be used if there are special memory location requirements for dma
|
||||
cmd_block: Option<&'d mut CmdBlock>,
|
||||
}
|
||||
|
||||
const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh);
|
||||
@ -495,6 +527,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
clock: SD_INIT_FREQ,
|
||||
signalling: Default::default(),
|
||||
card: None,
|
||||
cmd_block: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -531,8 +564,10 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
/// # Safety
|
||||
///
|
||||
/// `buffer` must be valid for the whole transfer and word aligned
|
||||
#[allow(unused_variables)]
|
||||
fn prepare_datapath_read<'a>(
|
||||
&'a mut self,
|
||||
config: &Config,
|
||||
dma: &'a mut PeripheralRef<'d, Dma>,
|
||||
buffer: &'a mut [u32],
|
||||
length_bytes: u32,
|
||||
block_size: u8,
|
||||
@ -544,15 +579,14 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
Self::wait_idle();
|
||||
Self::clear_interrupt_flags();
|
||||
|
||||
regs.dtimer()
|
||||
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
|
||||
regs.dtimer().write(|w| w.set_datatime(config.data_transfer_timeout));
|
||||
regs.dlenr().write(|w| w.set_datalength(length_bytes));
|
||||
|
||||
#[cfg(sdmmc_v1)]
|
||||
let transfer = unsafe {
|
||||
let request = self.dma.request();
|
||||
let request = dma.request();
|
||||
Transfer::new_read(
|
||||
&mut self.dma,
|
||||
dma,
|
||||
request,
|
||||
regs.fifor().as_ptr() as *mut u32,
|
||||
buffer,
|
||||
@ -692,13 +726,16 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
Signalling::SDR12 => 0xFF_FF00,
|
||||
};
|
||||
|
||||
let mut status = [0u32; 16];
|
||||
let status = match self.cmd_block.as_deref_mut() {
|
||||
Some(x) => x,
|
||||
None => &mut CmdBlock::new(),
|
||||
};
|
||||
|
||||
// Arm `OnDrop` after the buffer, so it will be dropped first
|
||||
let regs = T::regs();
|
||||
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||
|
||||
let transfer = self.prepare_datapath_read(&mut status, 64, 6);
|
||||
let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6);
|
||||
InterruptHandler::<T>::data_interrupts(true);
|
||||
Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6
|
||||
|
||||
@ -770,16 +807,21 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
let card = self.card.as_mut().ok_or(Error::NoCard)?;
|
||||
let rca = card.rca;
|
||||
|
||||
let cmd_block = match self.cmd_block.as_deref_mut() {
|
||||
Some(x) => x,
|
||||
None => &mut CmdBlock::new(),
|
||||
};
|
||||
|
||||
Self::cmd(Cmd::set_block_length(64), false)?; // CMD16
|
||||
Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP
|
||||
|
||||
let mut status = [0u32; 16];
|
||||
let status = cmd_block;
|
||||
|
||||
// Arm `OnDrop` after the buffer, so it will be dropped first
|
||||
let regs = T::regs();
|
||||
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||
|
||||
let transfer = self.prepare_datapath_read(&mut status, 64, 6);
|
||||
let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6);
|
||||
InterruptHandler::<T>::data_interrupts(true);
|
||||
Self::cmd(Cmd::card_status(0), true)?;
|
||||
|
||||
@ -813,7 +855,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
for byte in status.iter_mut() {
|
||||
*byte = u32::from_be(*byte);
|
||||
}
|
||||
self.card.as_mut().unwrap().status = status.into();
|
||||
self.card.as_mut().unwrap().status = status.0.into();
|
||||
}
|
||||
res
|
||||
}
|
||||
@ -872,13 +914,17 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
Self::cmd(Cmd::set_block_length(8), false)?; // CMD16
|
||||
Self::cmd(Cmd::app_cmd(card.rca << 16), false)?;
|
||||
|
||||
let mut scr = [0u32; 2];
|
||||
let cmd_block = match self.cmd_block.as_deref_mut() {
|
||||
Some(x) => x,
|
||||
None => &mut CmdBlock::new(),
|
||||
};
|
||||
let scr = &mut cmd_block.0[..2];
|
||||
|
||||
// Arm `OnDrop` after the buffer, so it will be dropped first
|
||||
let regs = T::regs();
|
||||
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||
|
||||
let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3);
|
||||
let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, scr, 8, 3);
|
||||
InterruptHandler::<T>::data_interrupts(true);
|
||||
Self::cmd(Cmd::cmd51(), true)?;
|
||||
|
||||
@ -910,7 +956,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
drop(transfer);
|
||||
|
||||
unsafe {
|
||||
let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]);
|
||||
let scr_bytes = &*(&scr as *const _ as *const [u8; 8]);
|
||||
card.scr = SCR(u64::from_be_bytes(*scr_bytes));
|
||||
}
|
||||
}
|
||||
@ -1002,8 +1048,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
Self::stop_datapath();
|
||||
}
|
||||
|
||||
/// Initializes card (if present) and sets the bus at the
|
||||
/// specified frequency.
|
||||
/// Initializes card (if present) and sets the bus at the specified frequency.
|
||||
pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> {
|
||||
let regs = T::regs();
|
||||
let ker_ck = T::frequency();
|
||||
@ -1143,6 +1188,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read status after signalling change
|
||||
self.read_sd_status().await?;
|
||||
|
||||
@ -1168,7 +1214,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
let regs = T::regs();
|
||||
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||
|
||||
let transfer = self.prepare_datapath_read(buffer, 512, 9);
|
||||
let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, buffer, 512, 9);
|
||||
InterruptHandler::<T>::data_interrupts(true);
|
||||
Self::cmd(Cmd::read_single_block(address), true)?;
|
||||
|
||||
@ -1291,6 +1337,14 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
pub fn clock(&self) -> Hertz {
|
||||
self.clock
|
||||
}
|
||||
|
||||
/// Set a specific cmd buffer rather than using the default stack allocated one.
|
||||
/// This is required if stack RAM cannot be used with DMA and usually manifests
|
||||
/// itself as an indefinite wait on a dma transfer because the dma peripheral
|
||||
/// cannot access the memory.
|
||||
pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) {
|
||||
self.cmd_block = Some(cmd_block)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> {
|
||||
|
@ -1282,6 +1282,7 @@ pub(crate) struct Info {
|
||||
struct State {}
|
||||
|
||||
impl State {
|
||||
#[allow(unused)]
|
||||
const fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@
|
||||
//! g7.set_io2(context.PE3, PinType::Sample);
|
||||
//! g7.set_io3(context.PE4, PinType::Channel);
|
||||
//!
|
||||
//! let mut touch_controller = tsc::Tsc::new(
|
||||
//! let mut touch_controller = tsc::Tsc::new_blocking(
|
||||
//! context.TSC,
|
||||
//! Some(g1),
|
||||
//! Some(g2),
|
||||
@ -188,7 +188,7 @@ pub struct Config {
|
||||
pub spread_spectrum_prescaler: bool,
|
||||
/// Selects AHB clock divider used to generate pulse generator clk
|
||||
pub pulse_generator_prescaler: PGPrescalerDivider,
|
||||
/// Maximum number of charge tranfer pulses that can be generated before error
|
||||
/// Maximum number of charge transfer pulses that can be generated before error
|
||||
pub max_count_value: MaxCount,
|
||||
/// Defines config of all IOs when no ongoing acquisition
|
||||
pub io_default_mode: bool,
|
||||
|
@ -436,6 +436,12 @@ impl<'d> BufferedUartRx<'d> {
|
||||
}
|
||||
}
|
||||
|
||||
/// we are ready to read if there is data in the buffer
|
||||
fn read_ready(&mut self) -> Result<bool, Error> {
|
||||
let state = self.state;
|
||||
Ok(!state.rx_buf.is_empty())
|
||||
}
|
||||
|
||||
/// Reconfigure the driver
|
||||
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
reconfigure(self.info, self.kernel_clock, config)?;
|
||||
@ -610,6 +616,18 @@ impl<'d> embedded_io_async::Read for BufferedUartRx<'d> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> embedded_io_async::ReadReady for BufferedUart<'d> {
|
||||
fn read_ready(&mut self) -> Result<bool, Self::Error> {
|
||||
BufferedUartRx::<'d>::read_ready(&mut self.rx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> embedded_io_async::ReadReady for BufferedUartRx<'d> {
|
||||
fn read_ready(&mut self) -> Result<bool, Self::Error> {
|
||||
Self::read_ready(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> embedded_io_async::BufRead for BufferedUart<'d> {
|
||||
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
|
||||
self.rx.fill_buf().await
|
||||
|
@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## Unreleased
|
||||
|
||||
- Add LazyLock sync primitive.
|
||||
|
||||
## 0.6.0 - 2024-05-29
|
||||
|
||||
- Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `Channel`.
|
||||
|
@ -13,6 +13,7 @@ Synchronization primitives and data structures with async support:
|
||||
- [`WakerRegistration`](waitqueue::WakerRegistration) - Utility to register and wake a `Waker`.
|
||||
- [`AtomicWaker`](waitqueue::AtomicWaker) - A variant of `WakerRegistration` accessible using a non-mut API.
|
||||
- [`MultiWakerRegistration`](waitqueue::MultiWakerRegistration) - Utility registering and waking multiple `Waker`'s.
|
||||
- [`LazyLock`](lazy_lock::LazyLock) - A value which is initialized on the first access
|
||||
|
||||
## Interoperability
|
||||
|
||||
|
@ -8,8 +8,6 @@
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::process::Command;
|
||||
|
||||
/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
|
||||
/// them (`cargo:rust-check-cfg=cfg(X)`).
|
||||
@ -17,7 +15,6 @@ use std::process::Command;
|
||||
pub struct CfgSet {
|
||||
enabled: HashSet<String>,
|
||||
declared: HashSet<String>,
|
||||
emit_declared: bool,
|
||||
}
|
||||
|
||||
impl CfgSet {
|
||||
@ -25,7 +22,6 @@ impl CfgSet {
|
||||
Self {
|
||||
enabled: HashSet::new(),
|
||||
declared: HashSet::new(),
|
||||
emit_declared: is_rustc_nightly(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +45,7 @@ impl CfgSet {
|
||||
///
|
||||
/// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
|
||||
pub fn declare(&mut self, cfg: impl AsRef<str>) {
|
||||
if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared {
|
||||
if self.declared.insert(cfg.as_ref().to_owned()) {
|
||||
println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
|
||||
}
|
||||
}
|
||||
@ -69,21 +65,6 @@ impl CfgSet {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_rustc_nightly() -> bool {
|
||||
if env::var_os("EMBASSY_FORCE_CHECK_CFG").is_some() {
|
||||
return true;
|
||||
}
|
||||
|
||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
|
||||
|
||||
let output = Command::new(rustc)
|
||||
.arg("--version")
|
||||
.output()
|
||||
.expect("failed to run `rustc --version`");
|
||||
|
||||
String::from_utf8_lossy(&output.stdout).contains("nightly")
|
||||
}
|
||||
|
||||
/// Sets configs that describe the target platform.
|
||||
pub fn set_target_cfgs(cfgs: &mut CfgSet) {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
@ -90,19 +90,15 @@ macro_rules! todo {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::core::unreachable!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unreachable!($($x)*)
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
152
embassy-sync/src/lazy_lock.rs
Normal file
152
embassy-sync/src/lazy_lock.rs
Normal file
@ -0,0 +1,152 @@
|
||||
//! Synchronization primitive for initializing a value once, allowing others to get a reference to the value.
|
||||
|
||||
use core::cell::UnsafeCell;
|
||||
use core::mem::ManuallyDrop;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
/// The `LazyLock` is a synchronization primitive that allows for
|
||||
/// initializing a value once, and allowing others to obtain a
|
||||
/// reference to the value. This is useful for lazy initialization of
|
||||
/// a static value.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use futures_executor::block_on;
|
||||
/// use embassy_sync::lazy_lock::LazyLock;
|
||||
///
|
||||
/// // Define a static value that will be lazily initialized
|
||||
/// // at runtime at the first access.
|
||||
/// static VALUE: LazyLock<u32> = LazyLock::new(|| 20);
|
||||
///
|
||||
/// let reference = VALUE.get();
|
||||
/// assert_eq!(reference, &20);
|
||||
/// ```
|
||||
pub struct LazyLock<T, F = fn() -> T> {
|
||||
init: AtomicBool,
|
||||
data: UnsafeCell<Data<T, F>>,
|
||||
}
|
||||
|
||||
union Data<T, F> {
|
||||
value: ManuallyDrop<T>,
|
||||
f: ManuallyDrop<F>,
|
||||
}
|
||||
|
||||
unsafe impl<T, F> Sync for LazyLock<T, F> {}
|
||||
|
||||
impl<T, F: FnOnce() -> T> LazyLock<T, F> {
|
||||
/// Create a new uninitialized `StaticLock`.
|
||||
pub const fn new(init_fn: F) -> Self {
|
||||
Self {
|
||||
init: AtomicBool::new(false),
|
||||
data: UnsafeCell::new(Data {
|
||||
f: ManuallyDrop::new(init_fn),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a reference to the underlying value, initializing it if it
|
||||
/// has not been done already.
|
||||
#[inline]
|
||||
pub fn get(&self) -> &T {
|
||||
self.ensure_init_fast();
|
||||
unsafe { &(*self.data.get()).value }
|
||||
}
|
||||
|
||||
/// Consume the `LazyLock`, returning the underlying value. The
|
||||
/// initialization function will be called if it has not been
|
||||
/// already.
|
||||
#[inline]
|
||||
pub fn into_inner(self) -> T {
|
||||
self.ensure_init_fast();
|
||||
let this = ManuallyDrop::new(self);
|
||||
let data = unsafe { core::ptr::read(&this.data) }.into_inner();
|
||||
|
||||
ManuallyDrop::into_inner(unsafe { data.value })
|
||||
}
|
||||
|
||||
/// Initialize the `LazyLock` if it has not been initialized yet.
|
||||
/// This function is a fast track to [`Self::ensure_init`]
|
||||
/// which does not require a critical section in most cases when
|
||||
/// the value has been initialized already.
|
||||
/// When this function returns, `self.data` is guaranteed to be
|
||||
/// initialized and visible on the current core.
|
||||
#[inline]
|
||||
fn ensure_init_fast(&self) {
|
||||
if !self.init.load(Ordering::Acquire) {
|
||||
self.ensure_init();
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize the `LazyLock` if it has not been initialized yet.
|
||||
/// When this function returns, `self.data` is guaranteed to be
|
||||
/// initialized and visible on the current core.
|
||||
fn ensure_init(&self) {
|
||||
critical_section::with(|_| {
|
||||
if !self.init.load(Ordering::Acquire) {
|
||||
let data = unsafe { &mut *self.data.get() };
|
||||
let f = unsafe { ManuallyDrop::take(&mut data.f) };
|
||||
let value = f();
|
||||
data.value = ManuallyDrop::new(value);
|
||||
|
||||
self.init.store(true, Ordering::Release);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F> Drop for LazyLock<T, F> {
|
||||
fn drop(&mut self) {
|
||||
if self.init.load(Ordering::Acquire) {
|
||||
unsafe { ManuallyDrop::drop(&mut self.data.get_mut().value) };
|
||||
} else {
|
||||
unsafe { ManuallyDrop::drop(&mut self.data.get_mut().f) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_lazy_lock() {
|
||||
static VALUE: LazyLock<u32> = LazyLock::new(|| 20);
|
||||
let reference = VALUE.get();
|
||||
assert_eq!(reference, &20);
|
||||
}
|
||||
#[test]
|
||||
fn test_lazy_lock_into_inner() {
|
||||
let lazy: LazyLock<u32> = LazyLock::new(|| 20);
|
||||
let value = lazy.into_inner();
|
||||
assert_eq!(value, 20);
|
||||
}
|
||||
|
||||
static DROP_CHECKER: AtomicU32 = AtomicU32::new(0);
|
||||
struct DropCheck;
|
||||
|
||||
impl Drop for DropCheck {
|
||||
fn drop(&mut self) {
|
||||
DROP_CHECKER.fetch_add(1, Ordering::Acquire);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lazy_drop() {
|
||||
let lazy: LazyLock<DropCheck> = LazyLock::new(|| DropCheck);
|
||||
assert_eq!(DROP_CHECKER.load(Ordering::Acquire), 0);
|
||||
lazy.get();
|
||||
drop(lazy);
|
||||
assert_eq!(DROP_CHECKER.load(Ordering::Acquire), 1);
|
||||
|
||||
let dropper = DropCheck;
|
||||
let lazy_fn: LazyLock<u32, _> = LazyLock::new(move || {
|
||||
let _a = dropper;
|
||||
20
|
||||
});
|
||||
assert_eq!(DROP_CHECKER.load(Ordering::Acquire), 1);
|
||||
drop(lazy_fn);
|
||||
assert_eq!(DROP_CHECKER.load(Ordering::Acquire), 2);
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ mod ring_buffer;
|
||||
|
||||
pub mod blocking_mutex;
|
||||
pub mod channel;
|
||||
pub mod lazy_lock;
|
||||
pub mod mutex;
|
||||
pub mod once_lock;
|
||||
pub mod pipe;
|
||||
|
@ -7,7 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 0.4.0 - 2024-01-11
|
||||
## 0.3.2 - 2024-08-05
|
||||
|
||||
- Implement with_timeout()/with_deadline() method style call on Future
|
||||
- Add collapse_debuginfo to fmt.rs macros.
|
||||
|
||||
## 0.3.1 - 2024-01-11
|
||||
|
||||
- Add with\_deadline convenience function and example
|
||||
- Implement Clone for Delay
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "embassy-time"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
edition = "2021"
|
||||
description = "Instant and Duration for embedded no-std systems, with async timer support"
|
||||
repository = "https://github.com/embassy-rs/embassy"
|
||||
@ -431,4 +431,4 @@ wasm-timer = { version = "0.2.5", optional = true }
|
||||
[dev-dependencies]
|
||||
serial_test = "0.9"
|
||||
critical-section = { version = "1.1", features = ["std"] }
|
||||
embassy-executor = { version = "0.5.0", path = "../embassy-executor" }
|
||||
embassy-executor = { version = "0.6.0", path = "../embassy-executor" }
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user