Merge branch 'master' into stm-dualcore

This commit is contained in:
Dion Dokter 2024-08-05 11:21:21 +02:00
commit ab4d378dda
186 changed files with 4143 additions and 784 deletions

17
ci.sh
View File

@ -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 \

View File

@ -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"

View File

@ -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 }

View File

@ -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.

View File

@ -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)*);
}
};
}

View File

@ -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;

View File

@ -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"

View File

@ -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"

View File

@ -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 youre 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 were working on. Follow the instructions commented in that file to get rust-analyzer working correctly.

View File

@ -353,7 +353,12 @@ 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.
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]

View File

@ -1,6 +1,6 @@
= Starting a new project
Once youve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project.
Once youve successfully xref:#_getting_started[run some example projects], the next step is to make a standalone Embassy project.
== Tools for generating Embassy projects

View File

@ -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

View File

@ -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?

View File

@ -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].

View File

@ -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

View File

@ -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};

View File

@ -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"

View File

@ -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)*);
}
};
}

View File

@ -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" }

View File

@ -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)*);
}
};
}

View File

@ -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"

View File

@ -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)*);
}
};
}

View File

@ -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" }

View File

@ -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

View File

@ -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)*);
}
};
}

View 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

View File

@ -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",
] }

View File

@ -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 {

View File

@ -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 {

View File

@ -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"

View File

@ -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(())

View File

@ -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.

View File

@ -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"

View File

@ -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();

View File

@ -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)*);
}
};
}

View File

@ -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)*);
}
};
}

View File

@ -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."

View File

@ -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();

View File

@ -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)*);
}
};
}

View File

@ -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"

View File

@ -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.

View File

@ -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)])
}

View File

@ -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)*);
}
};
}

View File

@ -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

View File

@ -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."

View File

@ -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)*);
}
};
}

View File

@ -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 }

View File

@ -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)*);
}
};
}

View File

@ -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" }

View File

@ -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)*);
}
};
}

View File

@ -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" }

View File

@ -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)*);
}
};
}

View File

@ -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 }

View File

@ -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" }

View File

@ -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)*);
}
};
}

View File

@ -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();
}

View File

@ -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)

View File

@ -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

View File

@ -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 }

View File

@ -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

View 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,
);

View File

@ -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)*);
}
};
}

View File

@ -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() {

View File

@ -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());

View File

@ -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 {

View File

@ -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,

View File

@ -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

View File

@ -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
View 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

View File

@ -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" }

View File

@ -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.

View File

@ -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]",

View File

@ -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

View File

@ -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)*);
}
};
}

View File

@ -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 {}

View File

@ -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

View File

@ -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> {

View File

@ -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 }

View File

@ -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)*);
}
};
}

View File

@ -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" }

View File

@ -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();

View File

@ -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")]

View File

@ -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> {

View File

@ -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 {

View File

@ -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)*);
}
};
}

View File

@ -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()

View File

@ -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| {

View File

@ -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);

View File

@ -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> {

View File

@ -1282,6 +1282,7 @@ pub(crate) struct Info {
struct State {}
impl State {
#[allow(unused)]
const fn new() -> Self {
Self {}
}

View File

@ -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,

View File

@ -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

View File

@ -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`.

View File

@ -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

View File

@ -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();

View File

@ -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)*);
}
};
}

View 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);
}
}

View File

@ -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;

View File

@ -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

View File

@ -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