Merge branch 'master' of https://github.com/embassy-rs/embassy into rtos-trace

This commit is contained in:
Quentin Smith 2022-08-19 00:53:06 -04:00
commit 71e468681b
315 changed files with 2533 additions and 1344 deletions

View file

@ -1,9 +1,7 @@
{
"editor.formatOnSave": true,
"rust-analyzer.checkOnSave.allFeatures": false,
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.checkOnSave.noDefaultFeatures": true,
"rust-analyzer.cargo.allFeatures": false,
"rust-analyzer.cargo.noDefaultFeatures": true,
"rust-analyzer.procMacro.enable": true,
"rust-analyzer.cargo.target": "thumbv7em-none-eabi",

View file

@ -16,7 +16,7 @@ Rust's <a href="https://rust-lang.github.io/async-book/">async/await</a> allows
- <a href="https://docs.embassy.dev/embassy-nrf/">embassy-nrf</a>, for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
- **Time that Just Works** -
No more messing with hardware timers. <a href="https://docs.embassy.dev/embassy/git/thumbv7em-none-eabihf/time/index.html">embassy_executor::time</a> provides Instant, Duration and Timer types that are globally available and never overflow.
No more messing with hardware timers. <a href="https://docs.embassy.dev/embassy-time">embassy_time</a> provides Instant, Duration and Timer types that are globally available and never overflow.
- **Real-time ready** -
Tasks on the same async executor run cooperatively, but you can create multiple executors with different priorities, so that higher priority tasks preempt lower priority ones. See the <a href="https://github.com/embassy-rs/embassy/blob/master/examples/nrf/src/bin/multiprio.rs">example</a>.
@ -44,8 +44,8 @@ The <a href="https://github.com/embassy-rs/nrf-softdevice">nrf-softdevice</a> cr
```rust,ignore
use defmt::info;
use embassy_executor::executor::Spawner;
use embassy_executor::time::{Duration, Timer};
use embassy_executor::Spawner;
use embassy_time::{Duration, Timer};
use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull};
use embassy_nrf::Peripherals;
@ -65,7 +65,9 @@ async fn blink(pin: AnyPin) {
// Main is itself an async task as well.
#[embassy_executor::main]
async fn main(spawner: Spawner, p: Peripherals) {
async fn main(spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
// Spawned tasks run in the background, concurrently.
spawner.spawn(blink(p.P0_13.degrade())).unwrap();

38
ci.sh
View file

@ -54,25 +54,25 @@ cargo batch \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,log \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32wl54jc-cm0p,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wle5ub,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f107vc,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f103re,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f100c4,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32wl54jc-cm0p,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wle5ub,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f107vc,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f103re,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f100c4,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
--- build --release --manifest-path embassy-boot/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
--- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \

View file

@ -30,38 +30,38 @@ cargo batch \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features unstable-traits,defmt \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features unstable-traits,log \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g473cc,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585zi,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55vy,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55uc-cm4,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r9zi,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303vc,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,embassy-executor/time-tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,embassy-executor/time-tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,embassy-executor/time-tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,embassy-executor/time-tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,embassy-executor/time-tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,embassy-executor/time-tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,embassy-executor/time-tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,embassy-executor/time-tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g473cc,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585zi,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55vy,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55uc-cm4,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r9zi,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303vc,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,embassy-time?/tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,embassy-time?/tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,embassy-time?/tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,embassy-time?/tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,embassy-time?/tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,embassy-time?/tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,embassy-time?/tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,embassy-time?/tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,embassy-time?/tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,embassy-time?/tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,embassy-time?/tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,embassy-time?/tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,embassy-time?/tick-32768hz \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,embassy-time?/tick-32768hz,unstable-traits \
--- build --release --manifest-path examples/nrf/Cargo.toml --target thumbv7em-none-eabi --no-default-features --out-dir out/examples/nrf --bin raw_spawn \
--- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --no-default-features --out-dir out/examples/stm32l0 --bin raw_spawn \

View file

@ -1,4 +1,4 @@
name: embassy
name: ROOT
title: Embassy
version: dev
nav:

View file

@ -6,6 +6,7 @@ version = "0.1.0"
[dependencies]
embassy-executor = { version = "0.1.0", path = "../../../../../embassy-executor", features = ["defmt", "nightly"] }
embassy-time = { version = "0.1.0", path = "../../../../../embassy-time", features = ["defmt", "nightly"] }
embassy-nrf = { version = "0.1.0", path = "../../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "nightly"] }
defmt = "0.3"

View file

@ -3,11 +3,10 @@
#![feature(type_alias_impl_trait)]
use defmt::*;
use embassy_executor::executor::Spawner;
use embassy_executor::time::{Duration, Timer};
use embassy_executor::Spawner;
use embassy_nrf::gpio::{Level, Output, OutputDrive};
use embassy_nrf::peripherals::P0_13;
use embassy_nrf::Peripherals;
use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _}; // global logger
#[embassy_executor::task]
@ -21,7 +20,9 @@ async fn blinker(mut led: Output<'static, P0_13>, interval: Duration) {
}
#[embassy_executor::main]
async fn main(spawner: Spawner, p: Peripherals) {
async fn main(spawner: Spawner) {
let p = embassy_nrf::init(Default::default());
let led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
unwrap!(spawner.spawn(blinker(led, Duration::from_millis(300))));
}

View file

@ -2,14 +2,14 @@
#![no_main]
#![feature(type_alias_impl_trait)]
use embassy_executor::executor::Spawner;
use embassy_executor::Spawner;
use embassy_stm32::exti::ExtiInput;
use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
use embassy_stm32::Peripherals;
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]
async fn main(_s: Spawner, p: Peripherals) {
async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
let mut led = Output::new(p.PB14, Level::Low, Speed::VeryHigh);
let mut button = ExtiInput::new(Input::new(p.PC13, Pull::Up), p.EXTI13);

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View file

@ -1,10 +1,10 @@
* xref:runtime.adoc[Runtime]
* xref:traits.adoc[APIs]
* xref:hal.adoc[Hardware Abstraction Layer]
** xref:nrf.adoc[nRF]
** xref:stm32.adoc[STM32]
* xref:bootloader.adoc[Bootloader]
* xref:getting_started.adoc[Getting started]
** xref:basic_application.adoc[Basic application]
** xref:layer_by_layer.adoc[Layer by Layer]
* xref:runtime.adoc[Executor]
* xref:hal.adoc[HAL]
** xref:nrf.adoc[nRF]
** xref:stm32.adoc[STM32]
* xref:bootloader.adoc[Bootloader]
* xref:examples.adoc[Examples]

View file

@ -21,7 +21,7 @@ Then, what follows are some declarations on how to deal with panics and faults.
[source,rust]
----
include::example$basic/src/main.rs[lines="5..6"]
include::example$basic/src/main.rs[lines="11..12"]
----
=== Task declaration
@ -30,7 +30,7 @@ After a bit of import declaration, the tasks run by the application should be de
[source,rust]
----
include::example$basic/src/main.rs[lines="18..27"]
include::example$basic/src/main.rs[lines="13..22"]
----
An embassy task must be declared `async`, and may NOT take generic arguments. In this case, we are handed the LED that should be blinked and the interval of the blinking.
@ -39,32 +39,32 @@ NOTE: Notice that there is no busy waiting going on in this task. It is using th
=== Main
The main entry point of an Embassy application is defined using the `#[embassy::main]` macro. The entry point is also required to take a `Spawner` and a `Peripherals` argument.
The main entry point of an Embassy application is defined using the `#[embassy_executor::main]` macro. The entry point is also required to take a `Spawner` and a `Peripherals` argument.
The `Spawner` is the way the main application spawns other tasks. The `Peripherals` type holds all peripherals that the application may use. In this case, we want to configure one of the pins as a GPIO output driving the LED:
The `Spawner` is the way the main application spawns other tasks. The `Peripherals` type comes from the HAL and holds all peripherals that the application may use. In this case, we want to configure one of the pins as a GPIO output driving the LED:
[source,rust]
----
include::example$basic/src/main.rs[lines="28..-1"]
include::example$basic/src/main.rs[lines="23..-1"]
----
`#[embassy::main]` takes an optional `config` paramter specifying a function that returns an instance of HAL's `Config` struct. For example:
`#[embassy_executor::main]` takes an optional `config` parameter specifying a function that returns an instance of HAL's `Config` struct. For example:
```rust
fn embassy_config() -> embassy_nrf::config::Config {
embassy_nrf::config::Config::default()
}
#[embassy::main(config = "embassy_config()")]
async fn main(_spawner: embassy::executor::Spawner, p: embassy_nrf::Peripherals) {
#[embassy_executor::main(config = "embassy_config()")]
async fn main(_spawner: Spawner, p: embassy_nrf::Peripherals) {
// ...
}
```
What happens when the `blinker` task have been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy::main]` macro. The macro does the following:
. Creates an Embassy Executor instance
. Initializes the microcontroller to get the `Peripherals`
. Creates an Embassy Executor
. Initializes the microcontroller HAL to get the `Peripherals`
. Defines a main task for the entry point
. Runs the executor spawning the main task

View file

@ -20,7 +20,10 @@ In general, the bootloader works on any platform that implements the `embedded-s
== Design
The bootloader divides the storage into 4 main partitions, configured by a linker script:
image::bootloader_flash.png[Bootloader flash layout]
The bootloader divides the storage into 4 main partitions, configurable when creating the bootloader
instance or via linker scripts:
* BOOTLOADER - Where the bootloader is placed. The bootloader itself consumes about 8kB of flash.
* ACTIVE - Where the main application is placed. The bootloader will attempt to load the application at the start of this partition. This partition is only written to by the bootloader.

View file

@ -46,15 +46,13 @@ You can run an example by opening a terminal and entering the following commands
[source, bash]
----
cd examples/nrf
DEFMT_LOG=info cargo run --bin blinky --release
cargo run --bin blinky --release
----
IMPORTANT: The DEFMT_LOG environment variable controls the example log verbosity. If you do not specify it, you will not see anything logged to the console.
== Whats next?
Congratulations, you have your first Embassy application running! Here are some alternatives on where to go from here:
* Read more about the xref:runtime.adoc[runtime].
* Read more about the xref:runtime.adoc[executor].
* Read more about the xref:hal.adoc[HAL].
* Start xref:basic_application.adoc[writing your application].

View file

@ -1,9 +1,10 @@
= Hardware Abstraction Layer (HAL)
Embassy provides HAL's for several microcontroller families:
Embassy provides HALs for several microcontroller families:
* `embassy-nrf` for the nRF microcontrollers from Nordic Semiconductor
* `embassy-stm32` for STM32 microcontrollers from ST Microelectronics
* `embassy-rp` for the Raspberry Pi RP2040 microcontrollers
These HALs implement async/await functionality for most peripherals while also implementing the async traits in Embassy.
These HALs implement async/await functionality for most peripherals while also implementing the
async traits in `embedded-hal-async`. You can also use these HALs with another executor.

View file

@ -15,6 +15,20 @@ In Rust, non-blocking operations can be implemented using async-await. Async-awa
== What is Embassy?
Embassy is an executor and a Hardware Access Layer (HAL). The executor is a scheduler that generally executes a fixed number of tasks, allocated at startup, though more can be added later. The HAL is an API that you can use to access peripherals, such as USART, UART, I2C, SPI, CAN, and USB. Embassy provides implementations of both async and blocking APIs where it makes sense. DMA (Direct Memory Access) is an example where async is a good fit, whereas GPIO states are a better fit for a blocking API.
The Embassy project consists of several crates that you can use together or independently:
Embassy may also provide a system timer that you can use for both async and blocking delays. For less than one microsecond, blocking delays should be used because the cost of context-switching is too high and the executor will be unable to provide accurate timing.
* **Executor** - The link:https://docs.embassy.dev/embassy-executor/[embassy-executor] is an async/await executor that generally executes a fixed number of tasks, allocated at startup, though more can be added later. The HAL is an API that you can use to access peripherals, such as USART, UART, I2C, SPI, CAN, and USB. Embassy provides implementations of both async and blocking APIs where it makes sense. DMA (Direct Memory Access) is an example where async is a good fit, whereas GPIO states are a better fit for a blocking API. The executor may also provide a system timer that you can use for both async and blocking delays. For less than one microsecond, blocking delays should be used because the cost of context-switching is too high and the executor will be unable to provide accurate timing.
* **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy.
** link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families.
** link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
* **Networking** - The link:https://docs.embassy.dev/embassy-net/[embassy-net] network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently.
* **Bluetooth** - The link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers.
* **LoRa** - link:https://docs.embassy.dev/embassy-lora/[embassy-lora] supports LoRa networking on STM32WL wireless microcontrollers and Semtech SX127x transceivers.
* **USB** - link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
* **Bootloader and DFU** - link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.

View file

@ -1,6 +1,6 @@
= Embassy runtime
= Embassy executor
The Embassy runtime is an async/await executor designed for embedded usage along with support functionality for interrupts and timers.
The Embassy executor is an async/await executor designed for embedded usage along with support functionality for interrupts and timers.
== Features

View file

@ -1,8 +0,0 @@
= Embassy Traits
Embassy provides a set of traits and types specifically designed for `async` usage. Many of these futures will be upstreamed to the `embedded-hal` crate at some point in the future, probably when the required GAT (Generic Associated Types) feature is stabilized in Rust.
* `embassy::io`: `AsyncBufRead`, `AsyncWrite`. Traits for byte-stream IO, essentially `no_std` compatible versions of `futures::io`. The primary reason for re-defining these traits is that the `futures::io` variant requires `std::io::Error`, which does not work in the `no_std` environment.
* `embassy::time`: Time `Driver` trait that is implemented for different platforms. Time in Embassy is represented using the `Duration` and `Instant` types.
These traits are implemented by the platform-specific crates, such as `embassy-nrf` or `embassy-stm32`.

View file

@ -4,6 +4,11 @@ name = "embassy-boot"
version = "0.1.0"
description = "Bootloader using Embassy"
[package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-v$VERSION/embassy-boot/boot/src/"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot/boot/src/"
target = "thumbv7em-none-eabi"
[lib]
[dependencies]

View file

@ -4,6 +4,12 @@ name = "embassy-boot-nrf"
version = "0.1.0"
description = "Bootloader lib for nRF chips"
[package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-nrf-v$VERSION/embassy-boot/nrf/src/"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot/nrf/src/"
features = ["embassy-nrf/nrf52840"]
target = "thumbv7em-none-eabi"
[lib]
[dependencies]
@ -12,7 +18,7 @@ defmt = { version = "0.3", optional = true }
embassy-util = { path = "../../embassy-util" }
embassy-nrf = { path = "../../embassy-nrf", default-features = false, features = ["nightly"] }
embassy-boot = { path = "../boot", default-features = false }
cortex-m = { version = "0.7" }
cortex-m = { version = "0.7.6" }
cortex-m-rt = { version = "0.7" }
embedded-storage = "0.3.0"
embedded-storage-async = "0.3.0"

View file

@ -4,6 +4,12 @@ name = "embassy-boot-stm32"
version = "0.1.0"
description = "Bootloader lib for STM32 chips"
[package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-nrf-v$VERSION/embassy-boot/stm32/src/"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot/stm32/src/"
features = ["embassy-stm32/stm32f429zi"]
target = "thumbv7em-none-eabi"
[lib]
[dependencies]
@ -14,7 +20,7 @@ log = { version = "0.4", optional = true }
embassy-util = { path = "../../embassy-util" }
embassy-stm32 = { path = "../../embassy-stm32", default-features = false, features = ["nightly"] }
embassy-boot = { path = "../boot", default-features = false }
cortex-m = { version = "0.7" }
cortex-m = { version = "0.7.6" }
cortex-m-rt = { version = "0.7" }
embedded-storage = "0.3.0"
embedded-storage-async = "0.3.0"

View file

@ -39,8 +39,8 @@ embassy-util = { version = "0.1.0", path = "../embassy-util" }
embassy-executor = { version = "0.1.0", path = "../embassy-executor"}
embassy-macros = { version = "0.1.0", path = "../embassy-macros"}
embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common"}
atomic-polyfill = "0.1.5"
critical-section = "0.2.5"
atomic-polyfill = "1.0.1"
critical-section = "1.1"
cfg-if = "1.0.0"
cortex-m = "0.7.3"
cortex-m = "0.7.6"

View file

@ -1,7 +1,7 @@
//! Executor specific to cortex-m devices.
use core::marker::PhantomData;
pub use embassy_executor::executor::*;
pub use embassy_executor::*;
use crate::interrupt::{Interrupt, InterruptExt};
@ -60,11 +60,11 @@ impl<I: Interrupt> InterruptExecutor<I> {
/// The executor keeps running in the background through the interrupt.
///
/// This returns a [`SendSpawner`] you can use to spawn tasks on it. A [`SendSpawner`]
/// is returned instead of a [`Spawner`](embassy_executor::executor::Spawner) because the executor effectively runs in a
/// is returned instead of a [`Spawner`](embassy_executor::Spawner) because the executor effectively runs in a
/// different "thread" (the interrupt), so spawning tasks on it is effectively
/// sending them.
///
/// To obtain a [`Spawner`](embassy_executor::executor::Spawner) for this executor, use [`Spawner::for_current_executor()`](embassy_executor::executor::Spawner::for_current_executor()) from
/// To obtain a [`Spawner`](embassy_executor::Spawner) for this executor, use [`Spawner::for_current_executor()`](embassy_executor::Spawner::for_current_executor()) from
/// a task running in it.
///
/// This function requires `&'static mut self`. This means you have to store the

View file

@ -6,6 +6,13 @@ use cortex_m::peripheral::NVIC;
use embassy_hal_common::Peripheral;
pub use embassy_macros::cortex_m_interrupt_take as take;
/// Do not use. Used for macros and HALs only. Not covered by semver guarantees.
#[doc(hidden)]
pub mod _export {
pub use atomic_polyfill as atomic;
pub use embassy_macros::{cortex_m_interrupt as interrupt, cortex_m_interrupt_declare as declare};
}
/// Implementation detail, do not use outside embassy crates.
#[doc(hidden)]
pub struct Handler {

View file

@ -3,6 +3,13 @@ name = "embassy-embedded-hal"
version = "0.1.0"
edition = "2021"
[package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-embedded-hal-v$VERSION/embassy-embedded-hal/src/"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-embedded-hal/src/"
features = ["nightly", "std"]
target = "thumbv7em-none-eabi"
[features]
std = []
# Enable nightly-only features

View file

@ -7,7 +7,7 @@ edition = "2021"
[package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/"
features = ["nightly", "defmt", "unstable-traits", "time", "time-tick-1mhz"]
features = ["nightly", "defmt", "unstable-traits"]
flavors = [
{ name = "std", target = "x86_64-unknown-linux-gnu", features = ["std"] },
{ name = "wasm", target = "wasm32-unknown-unknown", features = ["wasm"] },
@ -22,33 +22,13 @@ flavors = [
[features]
default = []
std = ["time", "time-tick-1mhz", "embassy-macros/std"]
wasm = ["wasm-bindgen", "js-sys", "embassy-macros/wasm", "wasm-timer", "time", "time-tick-1mhz"]
std = ["embassy-macros/std"]
wasm = ["dep:wasm-bindgen", "dep:js-sys", "embassy-macros/wasm"]
# Enable nightly-only features
nightly = ["embedded-hal-async"]
nightly = []
# Implement embedded-hal 1.0 alpha and embedded-hal-async traits.
# Implement embedded-hal-async traits if `nightly` is set as well.
unstable-traits = ["embedded-hal-1"]
# Display a timestamp of the number of seconds since startup next to defmt log messages
# To use this you must have a time driver provided.
defmt-timestamp-uptime = ["defmt"]
# Enable `embassy_executor::time` module.
# NOTE: This feature is only intended to be enabled by crates providing the time driver implementation.
# Enabling it directly without supplying a time driver will fail to link.
time = []
# Set the `embassy_executor::time` tick rate.
# NOTE: This feature is only intended to be enabled by crates providing the time driver implementation.
# If you're not writing your own driver, check the driver documentation to customize the tick rate.
# If you're writing a driver and your tick rate is not listed here, please add it and send a PR!
time-tick-32768hz = ["time"]
time-tick-1000hz = ["time"]
time-tick-1mhz = ["time"]
time-tick-16mhz = ["time"]
integrated-timers = ["dep:embassy-time"]
# Trace interrupt invocations with rtos-trace.
rtos-trace-interrupt = ["rtos-trace"]
@ -58,17 +38,13 @@ defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
rtos-trace = { version = "0.1.2", optional = true }
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" }
embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true}
embedded-hal-async = { version = "0.1.0-alpha.1", optional = true}
futures-util = { version = "0.3.17", default-features = false }
embassy-macros = { version = "0.1.0", path = "../embassy-macros"}
atomic-polyfill = "0.1.5"
critical-section = "0.2.5"
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true}
atomic-polyfill = "1.0.1"
critical-section = "1.1"
cfg-if = "1.0.0"
# WASM dependencies
wasm-bindgen = { version = "0.2.76", features = ["nightly"], optional = true }
js-sys = { version = "0.3", optional = true }
wasm-timer = { version = "0.2.5", optional = true }
js-sys = { version = "0.3", optional = true }

View file

@ -0,0 +1,11 @@
# embassy-executor
An async/await executor designed for embedded usage.
- No `alloc`, no heap needed. Task futures are statically allocated.
- No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning.
- Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`.
- No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`.
- Efficient polling: a wake will only poll the woken task, not all of them.
- Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time.
- Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks.

View file

@ -1,44 +0,0 @@
//! Async task executor.
//!
//! This module provides an async/await executor designed for embedded usage.
//!
//! - No `alloc`, no heap needed. Task futures are statically allocated.
//! - No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning.
//! - Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`.
//! - No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`.
//! - Efficient polling: a wake will only poll the woken task, not all of them.
//! - Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time.
//! - Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks.
cfg_if::cfg_if! {
if #[cfg(cortex_m)] {
#[path="arch/cortex_m.rs"]
mod arch;
pub use arch::*;
}
else if #[cfg(target_arch="riscv32")] {
#[path="arch/riscv32.rs"]
mod arch;
pub use arch::*;
}
else if #[cfg(all(target_arch="xtensa", feature = "nightly"))] {
#[path="arch/xtensa.rs"]
mod arch;
pub use arch::*;
}
else if #[cfg(feature="wasm")] {
#[path="arch/wasm.rs"]
mod arch;
pub use arch::*;
}
else if #[cfg(feature="std")] {
#[path="arch/std.rs"]
mod arch;
pub use arch::*;
}
}
pub mod raw;
mod spawner;
pub use spawner::*;

View file

@ -195,9 +195,6 @@ macro_rules! unwrap {
}
}
#[cfg(feature = "defmt-timestamp-uptime")]
defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct NoneError;

View file

@ -1,24 +1,46 @@
#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)]
#![cfg_attr(feature = "nightly", feature(generic_associated_types, type_alias_impl_trait))]
#![cfg_attr(all(feature = "nightly", target_arch = "xtensa"), feature(asm_experimental_arch))]
#![allow(clippy::new_without_default)]
#![doc = include_str!("../../README.md")]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
// This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt;
pub mod executor;
#[cfg(feature = "time")]
pub mod time;
#[cfg(feature = "nightly")]
pub use embassy_macros::{main, task};
cfg_if::cfg_if! {
if #[cfg(cortex_m)] {
#[path="arch/cortex_m.rs"]
mod arch;
pub use arch::*;
}
else if #[cfg(target_arch="riscv32")] {
#[path="arch/riscv32.rs"]
mod arch;
pub use arch::*;
}
else if #[cfg(all(target_arch="xtensa", feature = "nightly"))] {
#[path="arch/xtensa.rs"]
mod arch;
pub use arch::*;
}
else if #[cfg(feature="wasm")] {
#[path="arch/wasm.rs"]
mod arch;
pub use arch::*;
}
else if #[cfg(feature="std")] {
#[path="arch/std.rs"]
mod arch;
pub use arch::*;
}
}
#[doc(hidden)]
/// Implementation details for embassy macros. DO NOT USE.
pub mod export {
pub use atomic_polyfill as atomic;
#[cfg(feature = "rtos-trace")]
pub use rtos_trace::trace;
@ -40,3 +62,8 @@ pub mod export {
($($tt:tt)*) => {};
}
}
pub mod raw;
mod spawner;
pub use spawner::*;

View file

@ -8,7 +8,7 @@
//! executor wrappers in [`executor`](crate::executor) and the [`embassy_executor::task`](embassy_macros::task) macro, which are fully safe.
mod run_queue;
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
mod timer_queue;
pub(crate) mod util;
mod waker;
@ -22,6 +22,10 @@ use core::{mem, ptr};
use atomic_polyfill::{AtomicU32, Ordering};
use critical_section::CriticalSection;
#[cfg(feature = "integrated-timers")]
use embassy_time::driver::{self, AlarmHandle};
#[cfg(feature = "integrated-timers")]
use embassy_time::Instant;
#[cfg(feature = "rtos-trace")]
use rtos_trace::trace;
@ -29,17 +33,13 @@ use self::run_queue::{RunQueue, RunQueueItem};
use self::util::UninitCell;
pub use self::waker::task_from_waker;
use super::SpawnToken;
#[cfg(feature = "time")]
use crate::time::driver::{self, AlarmHandle};
#[cfg(feature = "time")]
use crate::time::Instant;
/// Task is spawned (has a future)
pub(crate) const STATE_SPAWNED: u32 = 1 << 0;
/// Task is in the executor run queue
pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1;
/// Task is in the executor timer queue
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2;
/// Raw task header for use in task pointers.
@ -52,9 +52,9 @@ pub struct TaskHeader {
pub(crate) executor: Cell<*const Executor>, // Valid if state != 0
pub(crate) poll_fn: UninitCell<unsafe fn(NonNull<TaskHeader>)>, // Valid if STATE_SPAWNED
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
pub(crate) expires_at: Cell<Instant>,
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
pub(crate) timer_queue_item: timer_queue::TimerQueueItem,
}
@ -66,9 +66,9 @@ impl TaskHeader {
executor: Cell::new(ptr::null()),
poll_fn: UninitCell::uninit(),
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
expires_at: Cell::new(Instant::from_ticks(0)),
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
timer_queue_item: timer_queue::TimerQueueItem::new(),
}
}
@ -269,9 +269,9 @@ pub struct Executor {
signal_fn: fn(*mut ()),
signal_ctx: *mut (),
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
pub(crate) timer_queue: timer_queue::TimerQueue,
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
alarm: AlarmHandle,
}
@ -283,9 +283,9 @@ impl Executor {
///
/// See [`Executor`] docs for details on `signal_fn`.
pub fn new(signal_fn: fn(*mut ()), signal_ctx: *mut ()) -> Self {
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
let alarm = unsafe { unwrap!(driver::allocate_alarm()) };
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
driver::set_alarm_callback(alarm, signal_fn, signal_ctx);
Self {
@ -293,9 +293,9 @@ impl Executor {
signal_fn,
signal_ctx,
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
timer_queue: timer_queue::TimerQueue::new(),
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
alarm,
}
}
@ -354,13 +354,13 @@ impl Executor {
/// somehow schedule for `poll()` to be called later, at a time you know for sure there's
/// no `poll()` already running.
pub unsafe fn poll(&'static self) {
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
self.timer_queue.dequeue_expired(Instant::now(), |task| wake_task(task));
self.run_queue.dequeue_all(|p| {
let task = p.as_ref();
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
task.expires_at.set(Instant::MAX);
let state = task.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel);
@ -383,11 +383,11 @@ impl Executor {
trace::task_exec_end();
// Enqueue or update into timer_queue
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
self.timer_queue.update(p);
});
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
{
// If this is already in the past, set_alarm will immediately trigger the alarm.
// This will cause `signal_fn` to be called, which will cause `poll()` to be called again,
@ -435,8 +435,9 @@ pub unsafe fn wake_task(task: NonNull<TaskHeader>) {
})
}
#[cfg(feature = "time")]
pub(crate) unsafe fn register_timer(at: Instant, waker: &core::task::Waker) {
#[cfg(feature = "integrated-timers")]
#[no_mangle]
unsafe fn _embassy_time_schedule_wake(at: Instant, waker: &core::task::Waker) {
let task = waker::task_from_waker(waker);
let task = task.as_ref();
let expires_at = task.expires_at.get();
@ -448,11 +449,11 @@ impl rtos_trace::RtosTraceOSCallbacks for Executor {
fn task_list() {
// We don't know what tasks exist, so we can't send them.
}
#[cfg(feature = "time")]
#[cfg(feature = "integrated-timers")]
fn time() -> u64 {
Instant::now().as_micros()
}
#[cfg(not(feature = "time"))]
#[cfg(not(feature = "integrated-timers"))]
fn time() -> u64 {
0
}

View file

@ -4,9 +4,9 @@ use core::ptr;
use core::ptr::NonNull;
use atomic_polyfill::Ordering;
use embassy_time::Instant;
use super::{TaskHeader, STATE_TIMER_QUEUED};
use crate::time::Instant;
pub(crate) struct TimerQueueItem {
next: Cell<*mut TaskHeader>,

View file

@ -40,7 +40,7 @@ pub fn task_from_waker(waker: &Waker) -> NonNull<TaskHeader> {
// TODO use waker_getters when stable. https://github.com/rust-lang/rust/issues/96992
let hack: &WakerHack = unsafe { mem::transmute(waker) };
if hack.vtable != &VTABLE {
panic!("Found waker not created by the Embassy executor. `embassy_executor::time::Timer` only works with the Embassy executor.")
panic!("Found waker not created by the Embassy executor. `embassy_time::Timer` only works with the Embassy executor.")
}
// safety: we never create a waker with a null data pointer.

View file

@ -9,5 +9,4 @@ edition = "2021"
defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
embassy-util = { version = "0.1.0", path = "../embassy-util" }
num-traits = { version = "0.2.14", default-features = false }

View file

@ -8,8 +8,8 @@ src_base = "https://github.com/embassy-rs/embassy/blob/embassy-lora-v$VERSION/em
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-lora/src/"
features = ["time", "defmt"]
flavors = [
{ name = "sx127x", target = "thumbv7em-none-eabihf", features = ["sx127x", "embassy-stm32/stm32wl55jc-cm4", "embassy-stm32/time-driver-any", "embassy-executor/time-tick-32768hz"] },
{ name = "stm32wl", target = "thumbv7em-none-eabihf", features = ["stm32wl", "embassy-stm32/stm32wl55jc-cm4", "embassy-stm32/time-driver-any", "embassy-executor/time-tick-32768hz"] },
{ name = "sx127x", target = "thumbv7em-none-eabihf", features = ["sx127x", "embassy-stm32/stm32wl55jc-cm4", "embassy-stm32/time-driver-any", "embassy-time/tick-32768hz"] },
{ name = "stm32wl", target = "thumbv7em-none-eabihf", features = ["stm32wl", "embassy-stm32/stm32wl55jc-cm4", "embassy-stm32/time-driver-any", "embassy-time/tick-32768hz"] },
]
[lib]
@ -24,7 +24,7 @@ time = []
defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
embassy-executor = { version = "0.1.0", path = "../embassy-executor" }
embassy-time = { version = "0.1.0", path = "../embassy-time" }
embassy-util = { version = "0.1.0", path = "../embassy-util" }
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true }
embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" }

View file

@ -18,6 +18,6 @@ pub struct LoraTimer;
impl lorawan_device::async_device::radio::Timer for LoraTimer {
type DelayFuture<'m> = impl core::future::Future<Output = ()> + 'm;
fn delay_ms<'m>(&'m mut self, millis: u64) -> Self::DelayFuture<'m> {
embassy_executor::time::Timer::after(embassy_executor::time::Duration::from_millis(millis))
embassy_time::Timer::after(embassy_time::Duration::from_millis(millis))
}
}

View file

@ -6,7 +6,7 @@
#![allow(dead_code)]
use bit_field::BitField;
use embassy_executor::time::{Duration, Timer};
use embassy_time::{Duration, Timer};
use embedded_hal::digital::v2::OutputPin;
use embedded_hal_async::spi::SpiBus;

View file

@ -13,8 +13,5 @@ proc-macro2 = "1.0.29"
proc-macro = true
[features]
nrf = []
stm32 = []
rp = []
std = []
wasm = []

View file

@ -16,8 +16,8 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
static HANDLER: interrupt::Handler;
}
let func = HANDLER.func.load(::embassy_executor::export::atomic::Ordering::Relaxed);
let ctx = HANDLER.ctx.load(::embassy_executor::export::atomic::Ordering::Relaxed);
let func = HANDLER.func.load(interrupt::_export::atomic::Ordering::Relaxed);
let ctx = HANDLER.ctx.load(interrupt::_export::atomic::Ordering::Relaxed);
let func: fn(*mut ()) = ::core::mem::transmute(func);
::embassy_executor::rtos_trace_interrupt! {
::embassy_executor::export::trace::isr_enter();
@ -28,9 +28,9 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
}
}
static TAKEN: ::embassy_executor::export::atomic::AtomicBool = ::embassy_executor::export::atomic::AtomicBool::new(false);
static TAKEN: interrupt::_export::atomic::AtomicBool = interrupt::_export::atomic::AtomicBool::new(false);
if TAKEN.compare_exchange(false, true, ::embassy_executor::export::atomic::Ordering::AcqRel, ::embassy_executor::export::atomic::Ordering::Acquire).is_err() {
if TAKEN.compare_exchange(false, true, interrupt::_export::atomic::Ordering::AcqRel, interrupt::_export::atomic::Ordering::Acquire).is_err() {
core::panic!("IRQ Already taken");
}

View file

@ -3,28 +3,12 @@ use proc_macro2::TokenStream;
use quote::quote;
use crate::util::ctxt::Ctxt;
use crate::util::path::ModulePrefix;
#[cfg(feature = "stm32")]
const HAL: Option<&str> = Some("embassy_stm32");
#[cfg(feature = "nrf")]
const HAL: Option<&str> = Some("embassy_nrf");
#[cfg(feature = "rp")]
const HAL: Option<&str> = Some("embassy_rp");
#[cfg(not(any(feature = "stm32", feature = "nrf", feature = "rp")))]
const HAL: Option<&str> = None;
#[derive(Debug, FromMeta)]
struct Args {
#[darling(default)]
embassy_prefix: ModulePrefix,
#[allow(unused)]
#[darling(default)]
config: Option<syn::LitStr>,
}
struct Args {}
pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, TokenStream> {
#[allow(unused_variables)]
let args = Args::from_list(&args).map_err(|e| e.write_errors())?;
let fargs = f.sig.inputs.clone();
@ -32,32 +16,26 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke
let ctxt = Ctxt::new();
if f.sig.asyncness.is_none() {
ctxt.error_spanned_by(&f.sig, "task functions must be async");
ctxt.error_spanned_by(&f.sig, "main function must be async");
}
if !f.sig.generics.params.is_empty() {
ctxt.error_spanned_by(&f.sig, "task functions must not be generic");
ctxt.error_spanned_by(&f.sig, "main function must not be generic");
}
if HAL.is_some() && fargs.len() != 2 {
ctxt.error_spanned_by(&f.sig, "main function must have 2 arguments");
}
if HAL.is_none() && fargs.len() != 1 {
ctxt.error_spanned_by(&f.sig, "main function must have 1 argument");
if fargs.len() != 1 {
ctxt.error_spanned_by(&f.sig, "main function must have 1 argument: the spawner.");
}
ctxt.check()?;
let embassy_prefix = args.embassy_prefix;
let embassy_prefix_lit = embassy_prefix.literal();
let embassy_path = embassy_prefix.append("embassy_executor").path();
let f_body = f.block;
#[cfg(feature = "wasm")]
let main = quote! {
#[wasm_bindgen::prelude::wasm_bindgen(start)]
pub fn main() -> Result<(), wasm_bindgen::JsValue> {
static EXECUTOR: ::embassy_util::Forever<#embassy_path::executor::Executor> = ::embassy_util::Forever::new();
let executor = EXECUTOR.put(#embassy_path::executor::Executor::new());
static EXECUTOR: ::embassy_util::Forever<::embassy_executor::Executor> = ::embassy_util::Forever::new();
let executor = EXECUTOR.put(::embassy_executor::Executor::new());
executor.start(|spawner| {
spawner.spawn(__embassy_main(spawner)).unwrap();
@ -70,7 +48,7 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke
#[cfg(all(feature = "std", not(feature = "wasm")))]
let main = quote! {
fn main() -> ! {
let mut executor = #embassy_path::executor::Executor::new();
let mut executor = ::embassy_executor::Executor::new();
let executor = unsafe { __make_static(&mut executor) };
executor.run(|spawner| {
@ -80,43 +58,20 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke
};
#[cfg(all(not(feature = "std"), not(feature = "wasm")))]
let main = {
let config = args.config.map(|s| s.parse::<syn::Expr>().unwrap()).unwrap_or_else(|| {
syn::Expr::Verbatim(quote! {
Default::default()
let main = quote! {
#[cortex_m_rt::entry]
fn main() -> ! {
let mut executor = ::embassy_executor::Executor::new();
let executor = unsafe { __make_static(&mut executor) };
executor.run(|spawner| {
spawner.must_spawn(__embassy_main(spawner));
})
});
let (hal_setup, peris_arg) = match HAL {
Some(hal) => {
let embassy_hal_path = embassy_prefix.append(hal).path();
(
quote!(
let p = #embassy_hal_path::init(#config);
),
quote!(p),
)
}
None => (quote!(), quote!()),
};
quote! {
#[cortex_m_rt::entry]
fn main() -> ! {
#hal_setup
let mut executor = #embassy_path::executor::Executor::new();
let executor = unsafe { __make_static(&mut executor) };
executor.run(|spawner| {
spawner.must_spawn(__embassy_main(spawner, #peris_arg));
})
}
}
};
let result = quote! {
#[#embassy_path::task(embassy_prefix = #embassy_prefix_lit)]
#[::embassy_executor::task()]
async fn __embassy_main(#fargs) {
#f_body
}

View file

@ -3,22 +3,16 @@ use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use crate::util::ctxt::Ctxt;
use crate::util::path::ModulePrefix;
#[derive(Debug, FromMeta)]
struct Args {
#[darling(default)]
pool_size: Option<usize>,
#[darling(default)]
embassy_prefix: ModulePrefix,
}
pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, TokenStream> {
let args = Args::from_list(&args).map_err(|e| e.write_errors())?;
let embassy_prefix = args.embassy_prefix.append("embassy_executor");
let embassy_path = embassy_prefix.path();
let pool_size: usize = args.pool_size.unwrap_or(1);
let ctxt = Ctxt::new();
@ -70,9 +64,9 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke
// in the user's code.
#task_inner
#visibility fn #task_ident(#fargs) -> #embassy_path::executor::SpawnToken<impl Sized> {
#visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> {
type Fut = impl ::core::future::Future + 'static;
static POOL: #embassy_path::executor::raw::TaskPool<Fut, #pool_size> = #embassy_path::executor::raw::TaskPool::new();
static POOL: ::embassy_executor::raw::TaskPool<Fut, #pool_size> = ::embassy_executor::raw::TaskPool::new();
unsafe { POOL._spawn_async_fn(move || #task_inner_ident(#(#arg_names,)*)) }
}
};

View file

@ -1,2 +1 @@
pub mod ctxt;
pub mod path;

View file

@ -1,41 +0,0 @@
use darling::{FromMeta, Result};
use proc_macro2::Span;
use syn::{LitStr, Path};
#[derive(Debug)]
pub struct ModulePrefix {
literal: LitStr,
}
impl ModulePrefix {
pub fn new(path: &str) -> Self {
let literal = LitStr::new(path, Span::call_site());
Self { literal }
}
pub fn append(&self, component: &str) -> ModulePrefix {
let mut lit = self.literal().value();
lit.push_str(component);
Self::new(lit.as_str())
}
pub fn path(&self) -> Path {
self.literal.parse().unwrap()
}
pub fn literal(&self) -> &LitStr {
&self.literal
}
}
impl FromMeta for ModulePrefix {
fn from_string(value: &str) -> Result<Self> {
Ok(ModulePrefix::new(value))
}
}
impl Default for ModulePrefix {
fn default() -> ModulePrefix {
ModulePrefix::new("::")
}
}

View file

@ -7,10 +7,8 @@ edition = "2021"
[package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/"
features = [ "pool-4", "defmt", "tcp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "embassy-executor/time", "embassy-executor/time-tick-1mhz"]
flavors = [
{ name = "default", target = "thumbv7em-none-eabihf" },
]
features = [ "pool-4", "defmt", "tcp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "embassy-time/tick-1mhz"]
target = "thumbv7em-none-eabi"
[features]
default = []
@ -18,6 +16,7 @@ std = []
defmt = ["dep:defmt", "smoltcp/defmt"]
udp = ["smoltcp/socket-udp"]
tcp = ["smoltcp/socket-tcp"]
dns = ["smoltcp/socket-dns"]
dhcpv4 = ["medium-ethernet", "smoltcp/socket-dhcpv4"]
@ -31,23 +30,26 @@ pool-16 = []
pool-32 = []
pool-64 = []
pool-128 = []
unstable-traits = []
[dependencies]
defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
embassy-executor = { version = "0.1.0", path = "../embassy-executor" }
embassy-util = { version = "0.1.0", path = "../embassy-util" }
embedded-io = { version = "0.3.0", features = [ "async" ] }
embassy-time = { version = "0.1.0", path = "../embassy-time" }
embassy-util = { version = "0.1.0", path = "../embassy-util" }
embedded-io = { version = "0.3.0", features = [ "async" ] }
managed = { version = "0.8.0", default-features = false, features = [ "map" ] }
heapless = { version = "0.7.5", default-features = false }
as-slice = "0.2.1"
generic-array = { version = "0.14.4", default-features = false }
stable_deref_trait = { version = "1.2.0", default-features = false }
futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
atomic-pool = "0.2.1"
managed = { version = "0.8.0", default-features = false, features = [ "map" ] }
heapless = { version = "0.7.5", default-features = false }
as-slice = "0.2.1"
generic-array = { version = "0.14.4", default-features = false }
stable_deref_trait = { version = "1.2.0", default-features = false }
futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
atomic-pool = "1.0"
atomic-polyfill = "1.0.1"
embedded-nal-async = "0.2.0"
[dependencies.smoltcp]
version = "0.8.0"

View file

@ -16,6 +16,9 @@ pub use stack::{Config, ConfigStrategy, Stack, StackResources};
#[cfg(feature = "tcp")]
pub mod tcp;
#[cfg(feature = "udp")]
pub mod udp;
// smoltcp reexports
pub use smoltcp::phy::{DeviceCapabilities, Medium};
pub use smoltcp::time::{Duration as SmolDuration, Instant as SmolInstant};
@ -24,3 +27,5 @@ pub use smoltcp::wire::{EthernetAddress, HardwareAddress};
pub use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Cidr};
#[cfg(feature = "proto-ipv6")]
pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr};
#[cfg(feature = "udp")]
pub use smoltcp::{socket::udp::PacketMetadata, wire::IpListenEndpoint};

View file

@ -2,7 +2,7 @@ use core::cell::UnsafeCell;
use core::future::Future;
use core::task::{Context, Poll};
use embassy_executor::time::{Instant, Timer};
use embassy_time::{Instant, Timer};
use embassy_util::waitqueue::WakerRegistration;
use futures::future::poll_fn;
use futures::pin_mut;

View file

@ -181,7 +181,7 @@ impl<'a> Drop for TcpSocket<'a> {
// =======================
#[derive(Copy, Clone)]
pub struct TcpIo<'a> {
struct TcpIo<'a> {
stack: &'a UnsafeCell<SocketStack>,
handle: SocketHandle,
}
@ -328,3 +328,172 @@ impl<'d> embedded_io::asynch::Write for TcpWriter<'d> {
self.io.flush()
}
}
#[cfg(feature = "unstable-traits")]
pub mod client {
use core::mem::MaybeUninit;
use core::ptr::NonNull;
use atomic_polyfill::{AtomicBool, Ordering};
use embedded_nal_async::IpAddr;
use super::*;
/// TCP client capable of creating up to N multiple connections with tx and rx buffers according to TX_SZ and RX_SZ.
pub struct TcpClient<'d, D: Device, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> {
stack: &'d Stack<D>,
state: &'d TcpClientState<N, TX_SZ, RX_SZ>,
}
impl<'d, D: Device, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClient<'d, D, N, TX_SZ, RX_SZ> {
/// Create a new TcpClient
pub fn new(stack: &'d Stack<D>, state: &'d TcpClientState<N, TX_SZ, RX_SZ>) -> Self {
Self { stack, state }
}
}
impl<'d, D: Device, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_nal_async::TcpConnect
for TcpClient<'d, D, N, TX_SZ, RX_SZ>
{
type Error = Error;
type Connection<'m> = TcpConnection<'m, N, TX_SZ, RX_SZ> where Self: 'm;
type ConnectFuture<'m> = impl Future<Output = Result<Self::Connection<'m>, Self::Error>> + 'm
where
Self: 'm;
fn connect<'m>(&'m self, remote: embedded_nal_async::SocketAddr) -> Self::ConnectFuture<'m> {
async move {
let addr: crate::IpAddress = match remote.ip() {
IpAddr::V4(addr) => crate::IpAddress::Ipv4(crate::Ipv4Address::from_bytes(&addr.octets())),
#[cfg(feature = "proto-ipv6")]
IpAddr::V6(addr) => crate::IpAddress::Ipv6(crate::Ipv6Address::from_bytes(&addr.octets())),
#[cfg(not(feature = "proto-ipv6"))]
IpAddr::V6(_) => panic!("ipv6 support not enabled"),
};
let remote_endpoint = (addr, remote.port());
let mut socket = TcpConnection::new(&self.stack, self.state)?;
socket
.socket
.connect(remote_endpoint)
.await
.map_err(|_| Error::ConnectionReset)?;
Ok(socket)
}
}
}
pub struct TcpConnection<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> {
socket: TcpSocket<'d>,
state: &'d TcpClientState<N, TX_SZ, RX_SZ>,
bufs: NonNull<([u8; TX_SZ], [u8; RX_SZ])>,
}
impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpConnection<'d, N, TX_SZ, RX_SZ> {
fn new<D: Device>(stack: &'d Stack<D>, state: &'d TcpClientState<N, TX_SZ, RX_SZ>) -> Result<Self, Error> {
let mut bufs = state.pool.alloc().ok_or(Error::ConnectionReset)?;
Ok(Self {
socket: unsafe { TcpSocket::new(stack, &mut bufs.as_mut().0, &mut bufs.as_mut().1) },
state,
bufs,
})
}
}
impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> Drop for TcpConnection<'d, N, TX_SZ, RX_SZ> {
fn drop(&mut self) {
unsafe {
self.socket.close();
self.state.pool.free(self.bufs);
}
}
}
impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_io::Io
for TcpConnection<'d, N, TX_SZ, RX_SZ>
{
type Error = Error;
}
impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_io::asynch::Read
for TcpConnection<'d, N, TX_SZ, RX_SZ>
{
type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
where
Self: 'a;
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
self.socket.read(buf)
}
}
impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_io::asynch::Write
for TcpConnection<'d, N, TX_SZ, RX_SZ>
{
type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
where
Self: 'a;
fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
self.socket.write(buf)
}
type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
where
Self: 'a;
fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
self.socket.flush()
}
}
/// State for TcpClient
pub struct TcpClientState<const N: usize, const TX_SZ: usize, const RX_SZ: usize> {
pool: Pool<([u8; TX_SZ], [u8; RX_SZ]), N>,
}
impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClientState<N, TX_SZ, RX_SZ> {
pub const fn new() -> Self {
Self { pool: Pool::new() }
}
}
unsafe impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> Sync for TcpClientState<N, TX_SZ, RX_SZ> {}
struct Pool<T, const N: usize> {
used: [AtomicBool; N],
data: [UnsafeCell<MaybeUninit<T>>; N],
}
impl<T, const N: usize> Pool<T, N> {
const VALUE: AtomicBool = AtomicBool::new(false);
const UNINIT: UnsafeCell<MaybeUninit<T>> = UnsafeCell::new(MaybeUninit::uninit());
const fn new() -> Self {
Self {
used: [Self::VALUE; N],
data: [Self::UNINIT; N],
}
}
}
impl<T, const N: usize> Pool<T, N> {
fn alloc(&self) -> Option<NonNull<T>> {
for n in 0..N {
if self.used[n].swap(true, Ordering::SeqCst) == false {
let p = self.data[n].get() as *mut T;
return Some(unsafe { NonNull::new_unchecked(p) });
}
}
None
}
/// safety: p must be a pointer obtained from self.alloc that hasn't been freed yet.
unsafe fn free(&self, p: NonNull<T>) {
let origin = self.data.as_ptr() as *mut T;
let n = p.as_ptr().offset_from(origin);
assert!(n >= 0);
assert!((n as usize) < N);
self.used[n as usize].store(false, Ordering::SeqCst);
}
}
}

157
embassy-net/src/udp.rs Normal file
View file

@ -0,0 +1,157 @@
use core::cell::UnsafeCell;
use core::mem;
use core::task::Poll;
use futures::future::poll_fn;
use smoltcp::iface::{Interface, SocketHandle};
use smoltcp::socket::udp::{self, PacketMetadata};
use smoltcp::wire::{IpEndpoint, IpListenEndpoint};
use super::stack::SocketStack;
use crate::{Device, Stack};
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BindError {
/// The socket was already open.
InvalidState,
/// No route to host.
NoRoute,
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
/// No route to host.
NoRoute,
}
pub struct UdpSocket<'a> {
stack: &'a UnsafeCell<SocketStack>,
handle: SocketHandle,
}
impl<'a> UdpSocket<'a> {
pub fn new<D: Device>(
stack: &'a Stack<D>,
rx_meta: &'a mut [PacketMetadata],
rx_buffer: &'a mut [u8],
tx_meta: &'a mut [PacketMetadata],
tx_buffer: &'a mut [u8],
) -> Self {
// safety: not accessed reentrantly.
let s = unsafe { &mut *stack.socket.get() };
let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) };
let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) };
let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) };
let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) };
let handle = s.sockets.add(udp::Socket::new(
udp::PacketBuffer::new(rx_meta, rx_buffer),
udp::PacketBuffer::new(tx_meta, tx_buffer),
));
Self {
stack: &stack.socket,
handle,
}
}
pub fn bind<T>(&mut self, endpoint: T) -> Result<(), BindError>
where
T: Into<IpListenEndpoint>,
{
let mut endpoint = endpoint.into();
// safety: not accessed reentrantly.
if endpoint.port == 0 {
// If user didn't specify port allocate a dynamic port.
endpoint.port = unsafe { &mut *self.stack.get() }.get_local_port();
}
// safety: not accessed reentrantly.
match unsafe { self.with_mut(|s, _| s.bind(endpoint)) } {
Ok(()) => Ok(()),
Err(udp::BindError::InvalidState) => Err(BindError::InvalidState),
Err(udp::BindError::Unaddressable) => Err(BindError::NoRoute),
}
}
/// SAFETY: must not call reentrantly.
unsafe fn with<R>(&self, f: impl FnOnce(&udp::Socket, &Interface) -> R) -> R {
let s = &*self.stack.get();
let socket = s.sockets.get::<udp::Socket>(self.handle);
f(socket, &s.iface)
}
/// SAFETY: must not call reentrantly.
unsafe fn with_mut<R>(&self, f: impl FnOnce(&mut udp::Socket, &mut Interface) -> R) -> R {
let s = &mut *self.stack.get();
let socket = s.sockets.get_mut::<udp::Socket>(self.handle);
let res = f(socket, &mut s.iface);
s.waker.wake();
res
}
pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint), Error> {
poll_fn(move |cx| unsafe {
self.with_mut(|s, _| match s.recv_slice(buf) {
Ok(x) => Poll::Ready(Ok(x)),
// No data ready
Err(udp::RecvError::Exhausted) => {
//s.register_recv_waker(cx.waker());
cx.waker().wake_by_ref();
Poll::Pending
}
})
})
.await
}
pub async fn send_to<T>(&self, buf: &[u8], remote_endpoint: T) -> Result<(), Error>
where
T: Into<IpEndpoint>,
{
let remote_endpoint = remote_endpoint.into();
poll_fn(move |cx| unsafe {
self.with_mut(|s, _| match s.send_slice(buf, remote_endpoint) {
// Entire datagram has been sent
Ok(()) => Poll::Ready(Ok(())),
Err(udp::SendError::BufferFull) => {
s.register_send_waker(cx.waker());
Poll::Pending
}
Err(udp::SendError::Unaddressable) => Poll::Ready(Err(Error::NoRoute)),
})
})
.await
}
pub fn endpoint(&self) -> IpListenEndpoint {
unsafe { self.with(|s, _| s.endpoint()) }
}
pub fn is_open(&self) -> bool {
unsafe { self.with(|s, _| s.is_open()) }
}
pub fn close(&mut self) {
unsafe { self.with_mut(|s, _| s.close()) }
}
pub fn may_send(&self) -> bool {
unsafe { self.with(|s, _| s.can_send()) }
}
pub fn may_recv(&self) -> bool {
unsafe { self.with(|s, _| s.can_recv()) }
}
}
impl Drop for UdpSocket<'_> {
fn drop(&mut self) {
// safety: not accessed reentrantly.
let s = unsafe { &mut *self.stack.get() };
s.sockets.remove(self.handle);
}
}

View file

@ -16,7 +16,7 @@ flavors = [
[features]
time = ["embassy-executor/time"]
time = ["dep:embassy-time"]
defmt = ["dep:defmt", "embassy-executor/defmt", "embassy-util/defmt", "embassy-usb?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"]
@ -57,7 +57,7 @@ _nrf5340-net = ["_nrf5340", "nrf5340-net-pac"]
_nrf5340 = ["_gpio-p1", "_dppi"]
_nrf9160 = ["nrf9160-pac", "_dppi"]
_time-driver = ["embassy-executor/time-tick-32768hz", "time"]
_time-driver = ["dep:embassy-time", "embassy-time?/tick-32768hz"]
_ppi = []
_dppi = []
@ -65,9 +65,9 @@ _gpio-p1 = []
[dependencies]
embassy-executor = { version = "0.1.0", path = "../embassy-executor", optional = true }
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
embassy-util = { version = "0.1.0", path = "../embassy-util" }
embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-3"]}
embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["nrf"]}
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
embassy-usb = {version = "0.1.0", path = "../embassy-usb", optional=true }
@ -80,9 +80,9 @@ embedded-io = { version = "0.3.0", features = ["async"], optional = true }
defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
cortex-m-rt = ">=0.6.15,<0.8"
cortex-m = "0.7.3"
cortex-m = "0.7.6"
futures = { version = "0.3.17", default-features = false }
critical-section = "0.2.5"
critical-section = "1.1"
rand_core = "0.6.3"
fixed = "1.10.0"
embedded-storage = "0.3.0"

View file

@ -197,7 +197,7 @@ impl_saadc_input!(P0_04, ANALOGINPUT2);
impl_saadc_input!(P0_05, ANALOGINPUT3);
pub mod irqs {
use embassy_macros::cortex_m_interrupt_declare as declare;
use embassy_cortex_m::interrupt::_export::declare;
use crate::pac::Interrupt as InterruptEnum;

View file

@ -218,7 +218,7 @@ impl_saadc_input!(P0_30, ANALOGINPUT6);
impl_saadc_input!(P0_31, ANALOGINPUT7);
pub mod irqs {
use embassy_macros::cortex_m_interrupt_declare as declare;
use embassy_cortex_m::interrupt::_export::declare;
use crate::pac::Interrupt as InterruptEnum;

View file

@ -219,7 +219,7 @@ impl_saadc_input!(P0_30, ANALOGINPUT6);
impl_saadc_input!(P0_31, ANALOGINPUT7);
pub mod irqs {
use embassy_macros::cortex_m_interrupt_declare as declare;
use embassy_cortex_m::interrupt::_export::declare;
use crate::pac::Interrupt as InterruptEnum;

View file

@ -211,7 +211,7 @@ impl_ppi_channel!(PPI_CH30, 30 => static);
impl_ppi_channel!(PPI_CH31, 31 => static);
pub mod irqs {
use embassy_macros::cortex_m_interrupt_declare as declare;
use embassy_cortex_m::interrupt::_export::declare;
use crate::pac::Interrupt as InterruptEnum;

View file

@ -235,7 +235,7 @@ impl_saadc_input!(P0_30, ANALOGINPUT6);
impl_saadc_input!(P0_31, ANALOGINPUT7);
pub mod irqs {
use embassy_macros::cortex_m_interrupt_declare as declare;
use embassy_cortex_m::interrupt::_export::declare;
use crate::pac::Interrupt as InterruptEnum;

View file

@ -278,7 +278,7 @@ impl_saadc_input!(P0_30, ANALOGINPUT6);
impl_saadc_input!(P0_31, ANALOGINPUT7);
pub mod irqs {
use embassy_macros::cortex_m_interrupt_declare as declare;
use embassy_cortex_m::interrupt::_export::declare;
use crate::pac::Interrupt as InterruptEnum;

View file

@ -283,7 +283,7 @@ impl_saadc_input!(P0_30, ANALOGINPUT6);
impl_saadc_input!(P0_31, ANALOGINPUT7);
pub mod irqs {
use embassy_macros::cortex_m_interrupt_declare as declare;
use embassy_cortex_m::interrupt::_export::declare;
use crate::pac::Interrupt as InterruptEnum;

View file

@ -468,7 +468,7 @@ impl_saadc_input!(P0_19, ANALOGINPUT6);
impl_saadc_input!(P0_20, ANALOGINPUT7);
pub mod irqs {
use embassy_macros::cortex_m_interrupt_declare as declare;
use embassy_cortex_m::interrupt::_export::declare;
use crate::pac::Interrupt as InterruptEnum;

View file

@ -328,7 +328,7 @@ impl_ppi_channel!(PPI_CH30, 30 => configurable);
impl_ppi_channel!(PPI_CH31, 31 => configurable);
pub mod irqs {
use embassy_macros::cortex_m_interrupt_declare as declare;
use embassy_cortex_m::interrupt::_export::declare;
use crate::pac::Interrupt as InterruptEnum;

View file

@ -346,7 +346,7 @@ impl_saadc_input!(P0_19, ANALOGINPUT6);
impl_saadc_input!(P0_20, ANALOGINPUT7);
pub mod irqs {
use embassy_macros::cortex_m_interrupt_declare as declare;
use embassy_cortex_m::interrupt::_export::declare;
use crate::pac::Interrupt as InterruptEnum;

View file

@ -135,8 +135,8 @@ pub use chip::pac;
pub(crate) use chip::pac;
pub use chip::{peripherals, Peripherals};
pub use embassy_cortex_m::executor;
pub use embassy_cortex_m::interrupt::_export::interrupt;
pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
pub use embassy_macros::cortex_m_interrupt as interrupt;
pub mod config {
//! Configuration options used when initializing the HAL.

View file

@ -3,7 +3,7 @@ use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering};
use core::{mem, ptr};
use critical_section::CriticalSection;
use embassy_executor::time::driver::{AlarmHandle, Driver};
use embassy_time::driver::{AlarmHandle, Driver};
use embassy_util::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_util::blocking_mutex::CriticalSectionMutex as Mutex;
@ -119,7 +119,7 @@ struct RtcDriver {
}
const ALARM_STATE_NEW: AlarmState = AlarmState::new();
embassy_executor::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
embassy_time::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
period: AtomicU32::new(0),
alarm_count: AtomicU8::new(0),
alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]),

View file

@ -12,9 +12,9 @@ use core::sync::atomic::Ordering::SeqCst;
use core::task::Poll;
use embassy_embedded_hal::SetConfig;
#[cfg(feature = "time")]
use embassy_executor::time::{Duration, Instant};
use embassy_hal_common::{into_ref, PeripheralRef};
#[cfg(feature = "time")]
use embassy_time::{Duration, Instant};
use embassy_util::waitqueue::AtomicWaker;
use futures::future::poll_fn;

View file

@ -28,17 +28,19 @@ unstable-traits = ["embedded-hal-1"]
[dependencies]
embassy-util = { version = "0.1.0", path = "../embassy-util" }
embassy-executor = { version = "0.1.0", path = "../embassy-executor", features = [ "time-tick-1mhz" ] }
embassy-executor = { version = "0.1.0", path = "../embassy-executor" }
embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-1mhz" ] }
embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-3"]}
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["rp"]}
atomic-polyfill = "0.1.5"
atomic-polyfill = "1.0.1"
defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
nb = "1.0.0"
cfg-if = "1.0.0"
cortex-m-rt = ">=0.6.15,<0.8"
cortex-m = "0.7.3"
critical-section = "0.2.5"
cortex-m = "0.7.6"
critical-section = "1.1"
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="9ad7223a48a065e612bc7dc7be5bf5bd0b41cfc4", features = ["rt"] }

View file

@ -1,5 +1,7 @@
use core::sync::atomic::{compiler_fence, Ordering};
use embassy_hal_common::impl_peripheral;
use crate::pac::dma::vals;
use crate::{pac, peripherals};
@ -35,6 +37,10 @@ impl<T: Channel> Dma<T> {
}
}
pub struct NoDma;
impl_peripheral!(NoDma);
mod sealed {
use super::*;

View file

@ -4,8 +4,8 @@
//! nrf_softdevice::interrupt. Intended for switching between the two at compile-time.
// Re-exports
use embassy_cortex_m::interrupt::_export::declare;
pub use embassy_cortex_m::interrupt::*;
use embassy_macros::cortex_m_interrupt_declare as declare;
use crate::pac::Interrupt as InterruptEnum;
declare!(TIMER_IRQ_0);

View file

@ -17,8 +17,8 @@ mod reset;
// Reexports
pub use embassy_cortex_m::executor;
pub use embassy_cortex_m::interrupt::_export::interrupt;
pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
pub use embassy_macros::cortex_m_interrupt as interrupt;
#[cfg(feature = "unstable-pac")]
pub use rp2040_pac2 as pac;
#[cfg(not(feature = "unstable-pac"))]

View file

@ -2,7 +2,7 @@ use core::cell::Cell;
use atomic_polyfill::{AtomicU8, Ordering};
use critical_section::CriticalSection;
use embassy_executor::time::driver::{AlarmHandle, Driver};
use embassy_time::driver::{AlarmHandle, Driver};
use embassy_util::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_util::blocking_mutex::Mutex;
@ -26,7 +26,7 @@ struct TimerDriver {
next_alarm: AtomicU8,
}
embassy_executor::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
embassy_time::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [DUMMY_ALARM; ALARM_COUNT]),
next_alarm: AtomicU8::new(0),
});

View file

@ -1,42 +1,199 @@
use embassy_hal_common::{into_ref, PeripheralRef};
use gpio::Pin;
use core::marker::PhantomData;
use crate::{gpio, pac, peripherals, Peripheral};
use embassy_hal_common::{into_ref, PeripheralRef};
use crate::gpio::sealed::Pin;
use crate::gpio::AnyPin;
use crate::{pac, peripherals, Peripheral};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum DataBits {
DataBits5,
DataBits6,
DataBits7,
DataBits8,
}
impl DataBits {
fn bits(&self) -> u8 {
match self {
Self::DataBits5 => 0b00,
Self::DataBits6 => 0b01,
Self::DataBits7 => 0b10,
Self::DataBits8 => 0b11,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Parity {
ParityNone,
ParityEven,
ParityOdd,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum StopBits {
#[doc = "1 stop bit"]
STOP1,
#[doc = "2 stop bits"]
STOP2,
}
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Config {
pub baudrate: u32,
pub data_bits: u8,
pub stop_bits: u8,
pub data_bits: DataBits,
pub stop_bits: StopBits,
pub parity: Parity,
}
impl Default for Config {
fn default() -> Self {
Self {
baudrate: 115200,
data_bits: 8,
stop_bits: 1,
data_bits: DataBits::DataBits8,
stop_bits: StopBits::STOP1,
parity: Parity::ParityNone,
}
}
}
/// Serial error
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum Error {
/// Triggered when the FIFO (or shift-register) is overflowed.
Overrun,
/// Triggered when a break is received
Break,
/// Triggered when there is a parity mismatch between what's received and
/// our settings.
Parity,
/// Triggered when the received character didn't have a valid stop bit.
Framing,
}
pub struct Uart<'d, T: Instance> {
inner: PeripheralRef<'d, T>,
tx: UartTx<'d, T>,
rx: UartRx<'d, T>,
}
pub struct UartTx<'d, T: Instance> {
phantom: PhantomData<&'d mut T>,
}
pub struct UartRx<'d, T: Instance> {
phantom: PhantomData<&'d mut T>,
}
impl<'d, T: Instance> UartTx<'d, T> {
fn new() -> Self {
Self { phantom: PhantomData }
}
pub async fn write(&mut self, _buffer: &[u8]) -> Result<(), Error> {
todo!()
}
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let r = T::regs();
unsafe {
for &b in buffer {
while r.uartfr().read().txff() {}
r.uartdr().write(|w| w.set_data(b));
}
}
Ok(())
}
pub fn blocking_flush(&mut self) -> Result<(), Error> {
let r = T::regs();
unsafe { while r.uartfr().read().txff() {} }
Ok(())
}
}
impl<'d, T: Instance> UartRx<'d, T> {
fn new() -> Self {
Self { phantom: PhantomData }
}
pub async fn read(&mut self, _buffer: &mut [u8]) -> Result<(), Error> {
todo!();
}
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
let r = T::regs();
unsafe {
for b in buffer {
*b = loop {
let dr = r.uartdr().read();
if dr.oe() {
return Err(Error::Overrun);
} else if dr.be() {
return Err(Error::Break);
} else if dr.pe() {
return Err(Error::Parity);
} else if dr.fe() {
return Err(Error::Framing);
} else if dr.fe() {
break dr.data();
}
};
}
}
Ok(())
}
}
impl<'d, T: Instance> Uart<'d, T> {
/// Create a new UART without hardware flow control
pub fn new(
inner: impl Peripheral<P = T> + 'd,
uart: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
config: Config,
) -> Self {
into_ref!(tx, rx);
Self::new_inner(uart, rx.map_into(), tx.map_into(), None, None, config)
}
/// Create a new UART with hardware flow control (RTS/CTS)
pub fn new_with_rtscts(
uart: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
config: Config,
) -> Self {
into_ref!(inner, tx, rx, cts, rts);
into_ref!(tx, rx, cts, rts);
Self::new_inner(
uart,
rx.map_into(),
tx.map_into(),
Some(cts.map_into()),
Some(rts.map_into()),
config,
)
}
fn new_inner(
_uart: impl Peripheral<P = T> + 'd,
tx: PeripheralRef<'d, AnyPin>,
rx: PeripheralRef<'d, AnyPin>,
cts: Option<PeripheralRef<'d, AnyPin>>,
rts: Option<PeripheralRef<'d, AnyPin>>,
config: Config,
) -> Self {
into_ref!(_uart);
unsafe {
let p = inner.regs();
let r = T::regs();
let clk_base = crate::clocks::clk_peri_freq();
@ -53,49 +210,217 @@ impl<'d, T: Instance> Uart<'d, T> {
}
// Load PL011's baud divisor registers
p.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
p.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
p.uartlcr_h().write(|w| {
w.set_wlen(config.data_bits - 5);
w.set_stp2(config.stop_bits == 2);
w.set_pen(false);
w.set_eps(false);
let (pen, eps) = match config.parity {
Parity::ParityNone => (false, false),
Parity::ParityEven => (true, true),
Parity::ParityOdd => (true, false),
};
r.uartlcr_h().write(|w| {
w.set_wlen(config.data_bits.bits());
w.set_stp2(config.stop_bits == StopBits::STOP2);
w.set_pen(pen);
w.set_eps(eps);
w.set_fen(true);
});
p.uartcr().write(|w| {
r.uartcr().write(|w| {
w.set_uarten(true);
w.set_rxe(true);
w.set_txe(true);
w.set_ctsen(cts.is_some());
w.set_rtsen(rts.is_some());
});
tx.io().ctrl().write(|w| w.set_funcsel(2));
rx.io().ctrl().write(|w| w.set_funcsel(2));
cts.io().ctrl().write(|w| w.set_funcsel(2));
rts.io().ctrl().write(|w| w.set_funcsel(2));
if let Some(pin) = &cts {
pin.io().ctrl().write(|w| w.set_funcsel(2));
}
if let Some(pin) = &rts {
pin.io().ctrl().write(|w| w.set_funcsel(2));
}
}
Self {
tx: UartTx::new(),
rx: UartRx::new(),
}
Self { inner }
}
pub fn send(&mut self, data: &[u8]) {
unsafe {
let p = self.inner.regs();
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
self.tx.write(buffer).await
}
for &byte in data {
if !p.uartfr().read().txff() {
p.uartdr().write(|w| w.set_data(byte));
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
self.tx.blocking_write(buffer)
}
pub fn blocking_flush(&mut self) -> Result<(), Error> {
self.tx.blocking_flush()
}
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
self.rx.read(buffer).await
}
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
self.rx.blocking_read(buffer)
}
/// Split the Uart into a transmitter and receiver, which is
/// particuarly useful when having two tasks correlating to
/// transmitting and receiving.
pub fn split(self) -> (UartTx<'d, T>, UartRx<'d, T>) {
(self.tx, self.rx)
}
}
mod eh02 {
use super::*;
impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for UartRx<'d, T> {
type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
let r = T::regs();
unsafe {
let dr = r.uartdr().read();
if dr.oe() {
Err(nb::Error::Other(Error::Overrun))
} else if dr.be() {
Err(nb::Error::Other(Error::Break))
} else if dr.pe() {
Err(nb::Error::Other(Error::Parity))
} else if dr.fe() {
Err(nb::Error::Other(Error::Framing))
} else if dr.fe() {
Ok(dr.data())
} else {
Err(nb::Error::WouldBlock)
}
}
}
}
impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T> {
type Error = Error;
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(buffer)
}
fn bflush(&mut self) -> Result<(), Self::Error> {
self.blocking_flush()
}
}
impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for Uart<'d, T> {
type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
embedded_hal_02::serial::Read::read(&mut self.rx)
}
}
impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T> {
type Error = Error;
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(buffer)
}
fn bflush(&mut self) -> Result<(), Self::Error> {
self.blocking_flush()
}
}
}
#[cfg(feature = "unstable-traits")]
mod eh1 {
use super::*;
impl embedded_hal_1::serial::Error for Error {
fn kind(&self) -> embedded_hal_1::serial::ErrorKind {
match *self {
Self::Framing => embedded_hal_1::serial::ErrorKind::FrameFormat,
Self::Break => embedded_hal_1::serial::ErrorKind::Other,
Self::Overrun => embedded_hal_1::serial::ErrorKind::Overrun,
Self::Parity => embedded_hal_1::serial::ErrorKind::Parity,
}
}
}
impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for Uart<'d, T> {
type Error = Error;
}
impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UartTx<'d, T> {
type Error = Error;
}
impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UartRx<'d, T> {
type Error = Error;
}
}
cfg_if::cfg_if! {
if #[cfg(all(feature = "unstable-traits", feature = "nightly", feature = "_todo_embedded_hal_serial"))] {
use core::future::Future;
impl<'d, T: Instance> embedded_hal_async::serial::Write for UartTx<'d, T>
{
type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
self.write(buf)
}
type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
async move { Ok(()) }
}
}
impl<'d, T: Instance> embedded_hal_async::serial::Read for UartRx<'d, T>
{
type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
self.read(buf)
}
}
impl<'d, T: Instance> embedded_hal_async::serial::Write for Uart<'d, T>
{
type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
self.write(buf)
}
type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
async move { Ok(()) }
}
}
impl<'d, T: Instance> embedded_hal_async::serial::Read for Uart<'d, T>
{
type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
self.read(buf)
}
}
}
}
mod sealed {
use super::*;
pub trait Instance {
fn regs(&self) -> pac::uart::Uart;
fn regs() -> pac::uart::Uart;
}
pub trait TxPin<T: Instance> {}
pub trait RxPin<T: Instance> {}
@ -106,23 +431,23 @@ mod sealed {
pub trait Instance: sealed::Instance {}
macro_rules! impl_instance {
($type:ident, $irq:ident) => {
impl sealed::Instance for peripherals::$type {
fn regs(&self) -> pac::uart::Uart {
pac::$type
($inst:ident, $irq:ident) => {
impl sealed::Instance for peripherals::$inst {
fn regs() -> pac::uart::Uart {
pac::$inst
}
}
impl Instance for peripherals::$type {}
impl Instance for peripherals::$inst {}
};
}
impl_instance!(UART0, UART0);
impl_instance!(UART1, UART1);
pub trait TxPin<T: Instance>: sealed::TxPin<T> + Pin {}
pub trait RxPin<T: Instance>: sealed::RxPin<T> + Pin {}
pub trait CtsPin<T: Instance>: sealed::CtsPin<T> + Pin {}
pub trait RtsPin<T: Instance>: sealed::RtsPin<T> + Pin {}
pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {}
pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {}
pub trait CtsPin<T: Instance>: sealed::CtsPin<T> + crate::gpio::Pin {}
pub trait RtsPin<T: Instance>: sealed::RtsPin<T> + crate::gpio::Pin {}
macro_rules! impl_pin {
($pin:ident, $instance:ident, $function:ident) => {

View file

@ -10,7 +10,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32
# TODO: sdmmc
# TODO: net
# TODO: subghz
features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "embassy-executor/time-tick-32768hz"]
features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "exti", "time-driver-any", "embassy-time/tick-32768hz"]
flavors = [
{ regex_feature = "stm32f0.*", target = "thumbv6m-none-eabi" },
{ regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" },
@ -33,8 +33,8 @@ flavors = [
[dependencies]
embassy-util = { version = "0.1.0", path = "../embassy-util" }
embassy-executor = { version = "0.1.0", path = "../embassy-executor" }
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-4"]}
embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["stm32"] }
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
embassy-net = { version = "0.1.0", path = "../embassy-net", optional = true }
@ -50,14 +50,13 @@ embedded-storage-async = { version = "0.3.0", optional = true }
defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
cortex-m-rt = ">=0.6.15,<0.8"
cortex-m = "0.7.3"
cortex-m = "0.7.6"
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
rand_core = "0.6.3"
sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/thalesfragoso/embedded-sdmmc-rs", branch = "async", optional = true }
critical-section = "0.2.5"
bare-metal = "1.0.0"
atomic-polyfill = "0.1.5"
critical-section = "1.1"
atomic-polyfill = "1.0.1"
stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", features = ["rt"] }
vcell = "0.1.3"
bxcan = "0.7.0"
@ -82,7 +81,7 @@ exti = []
# 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.
_time-driver = ["embassy-executor/time"]
_time-driver = ["dep:embassy-time"]
time-driver-any = ["_time-driver"]
time-driver-tim2 = ["_time-driver"]
time-driver-tim3 = ["_time-driver"]

View file

@ -96,7 +96,7 @@ fn main() {
g.extend(quote! {
pub mod interrupt {
use crate::pac::Interrupt as InterruptEnum;
use embassy_macros::cortex_m_interrupt_declare as declare;
use embassy_cortex_m::interrupt::_export::declare;
#(
declare!(#irqs);
)*

View file

@ -213,7 +213,7 @@ impl<'d, T: Pin> Drop for Flex<'d, T> {
}
/// Pull setting for an input.
#[derive(Debug, Eq, PartialEq)]
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Pull {
None,
@ -235,7 +235,7 @@ impl From<Pull> for vals::Pupdr {
}
/// Speed settings
#[derive(Debug)]
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Speed {
Low,
@ -303,7 +303,7 @@ impl<'d, T: Pin> Input<'d, T> {
}
/// Digital input or output level.
#[derive(Debug, Eq, PartialEq)]
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Level {
Low,
@ -470,7 +470,7 @@ pub(crate) mod sealed {
use super::*;
/// Alternate function type settings
#[derive(Debug)]
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum AFType {
Input,

View file

@ -4,11 +4,28 @@ use embassy_embedded_hal::SetConfig;
use embassy_hal_common::into_ref;
use crate::gpio::sealed::AFType;
use crate::gpio::Pull;
use crate::i2c::{Error, Instance, SclPin, SdaPin};
use crate::pac::i2c;
use crate::time::Hertz;
use crate::Peripheral;
#[non_exhaustive]
#[derive(Copy, Clone)]
pub struct Config {
pub sda_pullup: bool,
pub scl_pullup: bool,
}
impl Default for Config {
fn default() -> Self {
Self {
sda_pullup: false,
scl_pullup: false,
}
}
}
pub struct State {}
impl State {
@ -27,6 +44,7 @@ impl<'d, T: Instance> I2c<'d, T> {
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
freq: Hertz,
config: Config,
) -> Self {
into_ref!(scl, sda);
@ -34,8 +52,22 @@ impl<'d, T: Instance> I2c<'d, T> {
T::reset();
unsafe {
scl.set_as_af(scl.af_num(), AFType::OutputOpenDrain);
sda.set_as_af(sda.af_num(), AFType::OutputOpenDrain);
scl.set_as_af_pull(
scl.af_num(),
AFType::OutputOpenDrain,
match config.scl_pullup {
true => Pull::Up,
false => Pull::None,
},
);
sda.set_as_af_pull(
sda.af_num(),
AFType::OutputOpenDrain,
match config.sda_pullup {
true => Pull::Up,
false => Pull::None,
},
);
}
unsafe {

View file

@ -10,12 +10,29 @@ use futures::future::poll_fn;
use crate::dma::NoDma;
use crate::gpio::sealed::AFType;
use crate::gpio::Pull;
use crate::i2c::{Error, Instance, SclPin, SdaPin};
use crate::interrupt::InterruptExt;
use crate::pac::i2c;
use crate::time::Hertz;
use crate::Peripheral;
#[non_exhaustive]
#[derive(Copy, Clone)]
pub struct Config {
pub sda_pullup: bool,
pub scl_pullup: bool,
}
impl Default for Config {
fn default() -> Self {
Self {
sda_pullup: false,
scl_pullup: false,
}
}
}
pub struct State {
waker: AtomicWaker,
chunks_transferred: AtomicUsize,
@ -46,6 +63,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
tx_dma: impl Peripheral<P = TXDMA> + 'd,
rx_dma: impl Peripheral<P = RXDMA> + 'd,
freq: Hertz,
config: Config,
) -> Self {
into_ref!(peri, irq, scl, sda, tx_dma, rx_dma);
@ -53,8 +71,22 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
T::reset();
unsafe {
scl.set_as_af(scl.af_num(), AFType::OutputOpenDrain);
sda.set_as_af(sda.af_num(), AFType::OutputOpenDrain);
scl.set_as_af_pull(
scl.af_num(),
AFType::OutputOpenDrain,
match config.scl_pullup {
true => Pull::Up,
false => Pull::None,
},
);
sda.set_as_af_pull(
sda.af_num(),
AFType::OutputOpenDrain,
match config.sda_pullup {
true => Pull::Up,
false => Pull::None,
},
);
}
unsafe {

View file

@ -1,5 +1,4 @@
pub use bare_metal::Mutex;
pub use critical_section::CriticalSection;
pub use critical_section::{CriticalSection, Mutex};
pub use embassy_cortex_m::interrupt::*;
pub use crate::_generated::interrupt::*;

View file

@ -75,8 +75,8 @@ pub(crate) mod _generated {
// Reexports
pub use _generated::{peripherals, Peripherals};
pub use embassy_cortex_m::executor;
pub use embassy_cortex_m::interrupt::_export::interrupt;
pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
pub use embassy_macros::cortex_m_interrupt as interrupt;
#[cfg(feature = "unstable-pac")]
pub use stm32_metapac as pac;
#[cfg(not(feature = "unstable-pac"))]

View file

@ -63,7 +63,7 @@ seq_macro::seq!(N in 2..=128 {
match self {
PllClkDiv::NotDivided => 1,
#(
PllClkDiv::Div~N => (N + 1),
PllClkDiv::Div~N => N + 1,
)*
}
}
@ -81,7 +81,7 @@ seq_macro::seq!(N in 4..=512 {
pub enum PllN {
NotMultiplied,
#(
Mul~N = (N-1),
Mul~N = N-1,
)*
}
@ -90,7 +90,7 @@ seq_macro::seq!(N in 4..=512 {
match self {
PllN::NotMultiplied => 1,
#(
PllN::Mul~N => (N + 1),
PllN::Mul~N => N + 1,
)*
}
}

View file

@ -999,10 +999,17 @@ impl SdmmcInner {
fn clkcr_set_clkdiv(&self, freq: u32, width: BusWidth, ker_ck: Hertz, clock: &mut Hertz) -> Result<(), Error> {
let regs = self.0;
let width_u32 = match width {
BusWidth::One => 1u32,
BusWidth::Four => 4u32,
BusWidth::Eight => 8u32,
_ => panic!("Invalid Bus Width"),
};
let (clkdiv, new_clock) = clk_div(ker_ck, freq)?;
// Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7
// Section 55.5.8
let sdmmc_bus_bandwidth = new_clock.0 * (width as u32);
let sdmmc_bus_bandwidth = new_clock.0 * width_u32;
assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32);
*clock = new_clock;

View file

@ -504,7 +504,7 @@ impl<'d> SubGhz<'d, NoDma, NoDma> {
///
/// sg.set_standby(StandbyClk::Rc)?;
/// unsafe { sg.set_sleep(SleepCfg::default())? };
/// embassy_executor::time::Timer::after(embassy_executor::time::Duration::from_micros(500)).await;
/// embassy_time::Timer::after(embassy_time::Duration::from_micros(500)).await;
/// unsafe { wakeup() };
/// # Ok::<(), embassy_stm32::subghz::Error>(())
/// ```

View file

@ -439,9 +439,9 @@ impl From<Timeout> for [u8; 3] {
}
}
impl From<Timeout> for embassy_executor::time::Duration {
impl From<Timeout> for embassy_time::Duration {
fn from(to: Timeout) -> Self {
embassy_executor::time::Duration::from_micros(to.as_micros().into())
embassy_time::Duration::from_micros(to.as_micros().into())
}
}

View file

@ -44,17 +44,17 @@ impl From<RampTime> for core::time::Duration {
}
}
impl From<RampTime> for embassy_executor::time::Duration {
impl From<RampTime> for embassy_time::Duration {
fn from(rt: RampTime) -> Self {
match rt {
RampTime::Micros10 => embassy_executor::time::Duration::from_micros(10),
RampTime::Micros20 => embassy_executor::time::Duration::from_micros(20),
RampTime::Micros40 => embassy_executor::time::Duration::from_micros(40),
RampTime::Micros80 => embassy_executor::time::Duration::from_micros(80),
RampTime::Micros200 => embassy_executor::time::Duration::from_micros(200),
RampTime::Micros800 => embassy_executor::time::Duration::from_micros(800),
RampTime::Micros1700 => embassy_executor::time::Duration::from_micros(1700),
RampTime::Micros3400 => embassy_executor::time::Duration::from_micros(3400),
RampTime::Micros10 => embassy_time::Duration::from_micros(10),
RampTime::Micros20 => embassy_time::Duration::from_micros(20),
RampTime::Micros40 => embassy_time::Duration::from_micros(40),
RampTime::Micros80 => embassy_time::Duration::from_micros(80),
RampTime::Micros200 => embassy_time::Duration::from_micros(200),
RampTime::Micros800 => embassy_time::Duration::from_micros(800),
RampTime::Micros1700 => embassy_time::Duration::from_micros(1700),
RampTime::Micros3400 => embassy_time::Duration::from_micros(3400),
}
}
}

View file

@ -4,8 +4,8 @@ use core::sync::atomic::{compiler_fence, Ordering};
use core::{mem, ptr};
use atomic_polyfill::{AtomicU32, AtomicU8};
use embassy_executor::time::driver::{AlarmHandle, Driver};
use embassy_executor::time::TICKS_PER_SECOND;
use embassy_time::driver::{AlarmHandle, Driver};
use embassy_time::TICKS_PER_SECOND;
use embassy_util::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_util::blocking_mutex::Mutex;
use stm32_metapac::timer::regs;
@ -133,7 +133,7 @@ struct RtcDriver {
const ALARM_STATE_NEW: AlarmState = AlarmState::new();
embassy_executor::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
embassy_time::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
period: AtomicU32::new(0),
alarm_count: AtomicU8::new(0),
alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]),

View file

@ -5,8 +5,8 @@ use core::sync::atomic::Ordering;
use core::task::Poll;
use atomic_polyfill::{AtomicBool, AtomicU8};
use embassy_executor::time::{block_for, Duration};
use embassy_hal_common::into_ref;
use embassy_time::{block_for, Duration};
use embassy_usb::driver::{self, EndpointAllocError, EndpointError, Event, Unsupported};
use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
use embassy_util::waitqueue::AtomicWaker;

54
embassy-time/Cargo.toml Normal file
View file

@ -0,0 +1,54 @@
[package]
name = "embassy-time"
version = "0.1.0"
edition = "2021"
[package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-v$VERSION/embassy-time/src/"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-time/src/"
features = ["nightly", "defmt", "unstable-traits", "std"]
target = "x86_64-unknown-linux-gnu"
[features]
std = ["tick-1mhz"]
wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-1mhz"]
# Enable nightly-only features
nightly = ["embedded-hal-async"]
# Implement embedded-hal 1.0 alpha and embedded-hal-async traits.
# Implement embedded-hal-async traits if `nightly` is set as well.
unstable-traits = ["embedded-hal-1"]
# Display a timestamp of the number of seconds since startup next to defmt log messages
# To use this you must have a time driver provided.
defmt-timestamp-uptime = ["defmt"]
# Set the `embassy_time` tick rate.
# NOTE: This feature is only intended to be enabled by crates providing the time driver implementation.
# If you're not writing your own driver, check the driver documentation to customize the tick rate.
# If you're writing a driver and your tick rate is not listed here, please add it and send a PR!
tick-32768hz = []
tick-1000hz = []
tick-1mhz = []
tick-16mhz = []
[dependencies]
defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" }
embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true}
embedded-hal-async = { version = "0.1.0-alpha.1", optional = true}
futures-util = { version = "0.3.17", default-features = false }
embassy-macros = { version = "0.1.0", path = "../embassy-macros"}
atomic-polyfill = "1.0.1"
critical-section = "1.1"
cfg-if = "1.0.0"
# WASM dependencies
wasm-bindgen = { version = "0.2.76", features = ["nightly"], optional = true }
js-sys = { version = "0.3", optional = true }
wasm-timer = { version = "0.2.5", optional = true }

View file

@ -33,7 +33,7 @@ mod eh1 {
cfg_if::cfg_if! {
if #[cfg(all(feature = "unstable-traits", feature = "nightly"))] {
use crate::time::Timer;
use crate::Timer;
use core::future::Future;
use futures_util::FutureExt;

View file

@ -1,17 +1,17 @@
//! Time driver interface
//!
//! This module defines the interface a driver needs to implement to power the `embassy_executor::time` module.
//! This module defines the interface a driver needs to implement to power the `embassy_time` module.
//!
//! # Implementing a driver
//!
//! - Define a struct `MyDriver`
//! - Implement [`Driver`] for it
//! - Register it as the global driver with [`time_driver_impl`].
//! - Enable the Cargo features `embassy-executor/time` and one of `embassy-executor/time-tick-*` corresponding to the
//! - Enable the Cargo features `embassy-executor/time` and one of `embassy-time/tick-*` corresponding to the
//! tick rate of your driver.
//!
//! If you wish to make the tick rate configurable by the end user, you should do so by exposing your own
//! Cargo features and having each enable the corresponding `embassy-executor/time-tick-*`.
//! Cargo features and having each enable the corresponding `embassy-time/tick-*`.
//!
//! # Linkage details
//!
@ -34,10 +34,10 @@
//! # Example
//!
//! ```
//! use embassy_executor::time::driver::{Driver, AlarmHandle};
//! use embassy_time::driver::{Driver, AlarmHandle};
//!
//! struct MyDriver{}; // not public!
//! embassy_executor::time_driver_impl!(static DRIVER: MyDriver = MyDriver{});
//! embassy_time::time_driver_impl!(static DRIVER: MyDriver = MyDriver{});
//!
//! impl Driver for MyDriver {
//! fn now(&self) -> u64 {
@ -121,17 +121,25 @@ extern "Rust" {
fn _embassy_time_set_alarm(alarm: AlarmHandle, timestamp: u64);
}
pub(crate) fn now() -> u64 {
/// See [`Driver::now`]
pub fn now() -> u64 {
unsafe { _embassy_time_now() }
}
/// See [`Driver::allocate_alarm`]
///
/// Safety: it is UB to make the alarm fire before setting a callback.
pub(crate) unsafe fn allocate_alarm() -> Option<AlarmHandle> {
pub unsafe fn allocate_alarm() -> Option<AlarmHandle> {
_embassy_time_allocate_alarm()
}
pub(crate) fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
/// See [`Driver::set_alarm_callback`]
pub fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
unsafe { _embassy_time_set_alarm_callback(alarm, callback, ctx) }
}
pub(crate) fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
/// See [`Driver::set_alarm`]
pub fn set_alarm(alarm: AlarmHandle, timestamp: u64) {
unsafe { _embassy_time_set_alarm(alarm, timestamp) }
}
@ -145,26 +153,22 @@ macro_rules! time_driver_impl {
#[no_mangle]
fn _embassy_time_now() -> u64 {
<$t as $crate::time::driver::Driver>::now(&$name)
<$t as $crate::driver::Driver>::now(&$name)
}
#[no_mangle]
unsafe fn _embassy_time_allocate_alarm() -> Option<$crate::time::driver::AlarmHandle> {
<$t as $crate::time::driver::Driver>::allocate_alarm(&$name)
unsafe fn _embassy_time_allocate_alarm() -> Option<$crate::driver::AlarmHandle> {
<$t as $crate::driver::Driver>::allocate_alarm(&$name)
}
#[no_mangle]
fn _embassy_time_set_alarm_callback(
alarm: $crate::time::driver::AlarmHandle,
callback: fn(*mut ()),
ctx: *mut (),
) {
<$t as $crate::time::driver::Driver>::set_alarm_callback(&$name, alarm, callback, ctx)
fn _embassy_time_set_alarm_callback(alarm: $crate::driver::AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
<$t as $crate::driver::Driver>::set_alarm_callback(&$name, alarm, callback, ctx)
}
#[no_mangle]
fn _embassy_time_set_alarm(alarm: $crate::time::driver::AlarmHandle, timestamp: u64) {
<$t as $crate::time::driver::Driver>::set_alarm(&$name, alarm, timestamp)
fn _embassy_time_set_alarm(alarm: $crate::driver::AlarmHandle, timestamp: u64) {
<$t as $crate::driver::Driver>::set_alarm(&$name, alarm, timestamp)
}
};
}

View file

@ -6,7 +6,7 @@ use std::{mem, ptr, thread};
use atomic_polyfill::{AtomicU8, Ordering};
use crate::time::driver::{AlarmHandle, Driver};
use crate::driver::{AlarmHandle, Driver};
const ALARM_COUNT: usize = 4;

View file

@ -7,7 +7,7 @@ use atomic_polyfill::{AtomicU8, Ordering};
use wasm_bindgen::prelude::*;
use wasm_timer::Instant as StdInstant;
use crate::time::driver::{AlarmHandle, Driver};
use crate::driver::{AlarmHandle, Driver};
const ALARM_COUNT: usize = 4;

225
embassy-time/src/fmt.rs Normal file
View file

@ -0,0 +1,225 @@
#![macro_use]
#![allow(unused_macros)]
#[cfg(all(feature = "defmt", feature = "log"))]
compile_error!("You may not enable both `defmt` and `log` features.");
macro_rules! assert {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::assert!($($x)*);
#[cfg(feature = "defmt")]
::defmt::assert!($($x)*);
}
};
}
macro_rules! assert_eq {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::assert_eq!($($x)*);
#[cfg(feature = "defmt")]
::defmt::assert_eq!($($x)*);
}
};
}
macro_rules! assert_ne {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::assert_ne!($($x)*);
#[cfg(feature = "defmt")]
::defmt::assert_ne!($($x)*);
}
};
}
macro_rules! debug_assert {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::debug_assert!($($x)*);
#[cfg(feature = "defmt")]
::defmt::debug_assert!($($x)*);
}
};
}
macro_rules! debug_assert_eq {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::debug_assert_eq!($($x)*);
#[cfg(feature = "defmt")]
::defmt::debug_assert_eq!($($x)*);
}
};
}
macro_rules! debug_assert_ne {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::debug_assert_ne!($($x)*);
#[cfg(feature = "defmt")]
::defmt::debug_assert_ne!($($x)*);
}
};
}
macro_rules! todo {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::todo!($($x)*);
#[cfg(feature = "defmt")]
::defmt::todo!($($x)*);
}
};
}
macro_rules! unreachable {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::unreachable!($($x)*);
#[cfg(feature = "defmt")]
::defmt::unreachable!($($x)*);
}
};
}
macro_rules! panic {
($($x:tt)*) => {
{
#[cfg(not(feature = "defmt"))]
::core::panic!($($x)*);
#[cfg(feature = "defmt")]
::defmt::panic!($($x)*);
}
};
}
macro_rules! trace {
($s:literal $(, $x:expr)* $(,)?) => {
{
#[cfg(feature = "log")]
::log::trace!($s $(, $x)*);
#[cfg(feature = "defmt")]
::defmt::trace!($s $(, $x)*);
#[cfg(not(any(feature = "log", feature="defmt")))]
let _ = ($( & $x ),*);
}
};
}
macro_rules! debug {
($s:literal $(, $x:expr)* $(,)?) => {
{
#[cfg(feature = "log")]
::log::debug!($s $(, $x)*);
#[cfg(feature = "defmt")]
::defmt::debug!($s $(, $x)*);
#[cfg(not(any(feature = "log", feature="defmt")))]
let _ = ($( & $x ),*);
}
};
}
macro_rules! info {
($s:literal $(, $x:expr)* $(,)?) => {
{
#[cfg(feature = "log")]
::log::info!($s $(, $x)*);
#[cfg(feature = "defmt")]
::defmt::info!($s $(, $x)*);
#[cfg(not(any(feature = "log", feature="defmt")))]
let _ = ($( & $x ),*);
}
};
}
macro_rules! warn {
($s:literal $(, $x:expr)* $(,)?) => {
{
#[cfg(feature = "log")]
::log::warn!($s $(, $x)*);
#[cfg(feature = "defmt")]
::defmt::warn!($s $(, $x)*);
#[cfg(not(any(feature = "log", feature="defmt")))]
let _ = ($( & $x ),*);
}
};
}
macro_rules! error {
($s:literal $(, $x:expr)* $(,)?) => {
{
#[cfg(feature = "log")]
::log::error!($s $(, $x)*);
#[cfg(feature = "defmt")]
::defmt::error!($s $(, $x)*);
#[cfg(not(any(feature = "log", feature="defmt")))]
let _ = ($( & $x ),*);
}
};
}
#[cfg(feature = "defmt")]
macro_rules! unwrap {
($($x:tt)*) => {
::defmt::unwrap!($($x)*)
};
}
#[cfg(not(feature = "defmt"))]
macro_rules! unwrap {
($arg:expr) => {
match $crate::fmt::Try::into_result($arg) {
::core::result::Result::Ok(t) => t,
::core::result::Result::Err(e) => {
::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
}
}
};
($arg:expr, $($msg:expr),+ $(,)? ) => {
match $crate::fmt::Try::into_result($arg) {
::core::result::Result::Ok(t) => t,
::core::result::Result::Err(e) => {
::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
}
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct NoneError;
pub trait Try {
type Ok;
type Error;
fn into_result(self) -> Result<Self::Ok, Self::Error>;
}
impl<T> Try for Option<T> {
type Ok = T;
type Error = NoneError;
#[inline]
fn into_result(self) -> Result<T, NoneError> {
self.ok_or(NoneError)
}
}
impl<T, E> Try for Result<T, E> {
type Ok = T;
type Error = E;
#[inline]
fn into_result(self) -> Self {
self
}
}

View file

@ -1,3 +1,8 @@
#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)]
#![cfg_attr(feature = "nightly", feature(generic_associated_types, type_alias_impl_trait))]
#![allow(clippy::new_without_default)]
#![warn(missing_docs)]
//! Timekeeping, delays and timeouts.
//!
//! Timekeeping is done with elapsed time since system boot. Time is represented in
@ -26,7 +31,7 @@
//! like `2021-08-24 13:33:21`).
//!
//! If persistence across reboots is not needed, support can be built on top of
//! `embassy_executor::time` by storing the offset between "seconds elapsed since boot"
//! `embassy_time` by storing the offset between "seconds elapsed since boot"
//! and "seconds since unix epoch".
//!
//! # Time driver
@ -35,12 +40,13 @@
//! Only one driver can be active in a program.
//!
//! All methods and structs transparently call into the active driver. This makes it
//! possible for libraries to use `embassy_executor::time` in a driver-agnostic way without
//! possible for libraries to use `embassy_time` in a driver-agnostic way without
//! requiring generic parameters.
//!
//! For more details, check the [`driver`] module.
#![deny(missing_docs)]
// This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt;
mod delay;
pub mod driver;
@ -50,7 +56,6 @@ mod timer;
#[cfg(feature = "std")]
mod driver_std;
#[cfg(feature = "wasm")]
mod driver_wasm;
@ -59,24 +64,24 @@ pub use duration::Duration;
pub use instant::Instant;
pub use timer::{with_timeout, Ticker, TimeoutError, Timer};
#[cfg(feature = "time-tick-1000hz")]
#[cfg(feature = "tick-1000hz")]
const TPS: u64 = 1_000;
#[cfg(feature = "time-tick-32768hz")]
#[cfg(feature = "tick-32768hz")]
const TPS: u64 = 32_768;
#[cfg(feature = "time-tick-1mhz")]
#[cfg(feature = "tick-1mhz")]
const TPS: u64 = 1_000_000;
#[cfg(feature = "time-tick-16mhz")]
#[cfg(feature = "tick-16mhz")]
const TPS: u64 = 16_000_000;
/// Ticks per second of the global timebase.
///
/// This value is specified by the `time-tick-*` Cargo features, which
/// This value is specified by the `tick-*` Cargo features, which
/// should be set by the time driver. Some drivers support a fixed tick rate, others
/// allow you to choose a tick rate with Cargo features of their own. You should not
/// set the `time-tick-*` features for embassy yourself as an end user.
/// set the `tick-*` features for embassy yourself as an end user.
pub const TICKS_PER_SECOND: u64 = TPS;
const fn gcd(a: u64, b: u64) -> u64 {
@ -89,3 +94,6 @@ const fn gcd(a: u64, b: u64) -> u64 {
pub(crate) const GCD_1K: u64 = gcd(TICKS_PER_SECOND, 1_000);
pub(crate) const GCD_1M: u64 = gcd(TICKS_PER_SECOND, 1_000_000);
#[cfg(feature = "defmt-timestamp-uptime")]
defmt::timestamp! {"{=u64:us}", Instant::now().as_micros() }

View file

@ -1,12 +1,11 @@
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
use core::task::{Context, Poll, Waker};
use futures_util::future::{select, Either};
use futures_util::{pin_mut, Stream};
use crate::executor::raw;
use crate::time::{Duration, Instant};
use crate::{Duration, Instant};
/// Error returned by [`with_timeout`] on timeout.
#[derive(Debug, Clone, PartialEq, Eq)]
@ -49,7 +48,7 @@ impl Timer {
/// # #![feature(type_alias_impl_trait)]
/// #
/// # fn foo() {}
/// use embassy_executor::time::{Duration, Timer};
/// use embassy_time::{Duration, Timer};
///
/// #[embassy_executor::task]
/// async fn demo_sleep_seconds() {
@ -73,7 +72,7 @@ impl Future for Timer {
if self.yielded_once && self.expires_at <= Instant::now() {
Poll::Ready(())
} else {
unsafe { raw::register_timer(self.expires_at, cx.waker()) };
schedule_wake(self.expires_at, cx.waker());
self.yielded_once = true;
Poll::Pending
}
@ -88,7 +87,7 @@ impl Future for Timer {
/// ``` no_run
/// # #![feature(type_alias_impl_trait)]
/// #
/// use embassy_executor::time::{Duration, Timer};
/// use embassy_time::{Duration, Timer};
/// # fn foo() {}
///
/// #[embassy_executor::task]
@ -108,7 +107,7 @@ impl Future for Timer {
/// ``` no_run
/// # #![feature(type_alias_impl_trait)]
/// #
/// use embassy_executor::time::{Duration, Ticker};
/// use embassy_time::{Duration, Ticker};
/// use futures::StreamExt;
/// # fn foo(){}
///
@ -144,8 +143,16 @@ impl Stream for Ticker {
self.expires_at += dur;
Poll::Ready(Some(()))
} else {
unsafe { raw::register_timer(self.expires_at, cx.waker()) };
schedule_wake(self.expires_at, cx.waker());
Poll::Pending
}
}
}
extern "Rust" {
fn _embassy_time_schedule_wake(at: Instant, waker: &Waker);
}
fn schedule_wake(at: Instant, waker: &Waker) {
unsafe { _embassy_time_schedule_wake(at, waker) }
}

View file

@ -6,10 +6,8 @@ edition = "2021"
[package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-hid-v$VERSION/embassy-usb-hid/src/"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-hid/src/"
features = ["defmt", "embassy-executor/time-tick-1mhz"]
flavors = [
{ name = "default", target = "thumbv7em-none-eabihf" },
]
features = ["defmt"]
target = "thumbv7em-none-eabi"
[features]
default = ["usbd-hid"]

Some files were not shown because too many files have changed in this diff Show more