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