Skip to content

Commit

Permalink
Extract embassy support into esp-hal-embassy package (#1595)
Browse files Browse the repository at this point in the history
* Extract embassy support into `esp-hal-embassy` package

* Update relevant packages/examples/tests to get CI green again

* Add back `defmt` support

* Re-export `Executor` and `InterruptExecutor` rather than making `executor` module public

* Document the `esp-hal-embassy` package

* Update `CHANGELOG.md`

* Hack together a "fix" for the `SYSTIMER` time driver

* Make `clippy` shut up
  • Loading branch information
jessebraham authored Jun 3, 2024
1 parent cb91828 commit 48e3e91
Show file tree
Hide file tree
Showing 54 changed files with 659 additions and 345 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ exclude = [
"esp-backtrace",
"esp-build",
"esp-hal",
"esp-hal-embassy",
"esp-hal-procmacros",
"esp-hal-smartled",
"esp-ieee802154",
Expand Down
48 changes: 48 additions & 0 deletions esp-hal-embassy/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
[package]
name = "esp-hal-embassy"
version = "0.1.0"
edition = "2021"
rust-version = "1.76.0"
description = "Embassy support for esp-hal"
repository = "https://github.com/esp-rs/esp-hal"
license = "MIT OR Apache-2.0"

[package.metadata.docs.rs]
default-target = "riscv32imac-unknown-none-elf"
features = ["esp32c6", "time-timg0"]

[dependencies]
critical-section = "1.1.2"
defmt = { version = "0.3.8", optional = true }
document-features = "0.2.8"
embassy-executor = "0.5.0"
embassy-time-driver = "0.1.0"
esp-hal = { version = "0.17.0", path = "../esp-hal" }
portable-atomic = "1.6.0"

[build-dependencies]
cfg-if = "1.0.0"
esp-build = { version = "0.1.0", path = "../esp-build" }
esp-metadata = { version = "0.1.0", path = "../esp-metadata" }

[features]
esp32 = ["esp-hal/esp32"]
esp32c2 = ["esp-hal/esp32c2"]
esp32c3 = ["esp-hal/esp32c3"]
esp32c6 = ["esp-hal/esp32c6"]
esp32h2 = ["esp-hal/esp32h2"]
esp32s2 = ["esp-hal/esp32s2"]
esp32s3 = ["esp-hal/esp32s3"]

## Implement `defmt::Format` on certain types.
defmt = ["dep:defmt", "embassy-executor/defmt", "esp-hal/defmt"]
## Use the executor-integrated `embassy-time` timer queue.
integrated-timers = ["embassy-executor/integrated-timers"]

#! ### Time Driver Feature Flags
## SYSTIMER (16MHz)
time-systimer-16mhz = ["embassy-time-driver/tick-hz-16_000_000"]
## SYSTIMER (80MHz)
time-systimer-80mhz = ["embassy-time-driver/tick-hz-80_000_000"]
## TIMG0 (1MHz)
time-timg0 = ["embassy-time-driver/tick-hz-1_000_000"]
35 changes: 35 additions & 0 deletions esp-hal-embassy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# esp-hal-embassy

[![Crates.io](https://img.shields.io/crates/v/esp-hal-embassy?labelColor=1C2C2E&color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp-hal-embassy)
[![docs.rs](https://img.shields.io/docsrs/esp-hal-embassy?labelColor=1C2C2E&color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp-hal-embassy)
![MSRV](https://img.shields.io/badge/MSRV-1.76-blue?labelColor=1C2C2E&style=flat-square)
![Crates.io](https://img.shields.io/crates/l/esp-hal-embassy?labelColor=1C2C2E&style=flat-square)
[![Matrix](https://img.shields.io/matrix/esp-rs:matrix.org?label=join%20matrix&labelColor=1C2C2E&color=BEC5C9&logo=matrix&style=flat-square)](https://matrix.to/#/#esp-rs:matrix.org)

[Embassy] support for `esp-hal`.

[embassy]: https://github.com/embassy-rs/embassy

## [Documentation]

[documentation]: https://docs.rs/esp-hal-embassy/

## Minimum Supported Rust Version (MSRV)

This crate is guaranteed to compile on stable Rust 1.76 and up. It _might_
compile with older versions but that may change in any new patch release.

## License

Licensed under either of:

- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in
the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without
any additional terms or conditions.
53 changes: 53 additions & 0 deletions esp-hal-embassy/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use std::{error::Error, str::FromStr};

use esp_build::assert_unique_used_features;
use esp_metadata::{Chip, Config};

fn main() -> Result<(), Box<dyn Error>> {
// NOTE: update when adding new device support!
// Ensure that exactly one chip has been specified:
assert_unique_used_features!(
"esp32", "esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32s2", "esp32s3"
);

// If the `embassy` feature is enabled, ensure that a time driver implementation
// is available:
cfg_if::cfg_if! {
if #[cfg(feature = "esp32")] {
assert_unique_used_features!("time-timg0");
} else if #[cfg(feature = "esp32s2")] {
assert_unique_used_features!("time-systimer-80mhz", "time-timg0");
} else {
assert_unique_used_features!("time-systimer-16mhz", "time-timg0");
}
}

// NOTE: update when adding new device support!
// Determine the name of the configured device:
let device_name = if cfg!(feature = "esp32") {
"esp32"
} else if cfg!(feature = "esp32c2") {
"esp32c2"
} else if cfg!(feature = "esp32c3") {
"esp32c3"
} else if cfg!(feature = "esp32c6") {
"esp32c6"
} else if cfg!(feature = "esp32h2") {
"esp32h2"
} else if cfg!(feature = "esp32s2") {
"esp32s2"
} else if cfg!(feature = "esp32s3") {
"esp32s3"
} else {
unreachable!() // We've confirmed exactly one known device was selected
};

// Load the configuration file for the configured device:
let chip = Chip::from_str(device_name)?;
let config = Config::for_chip(&chip);

// Define all necessary configuration symbols for the configured device:
config.define_symbols();

Ok(())
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
//! Interrupt-mode executor.
use core::{cell::UnsafeCell, mem::MaybeUninit};

use embassy_executor::{raw, SendSpawner};
use portable_atomic::{AtomicUsize, Ordering};

use crate::{
use esp_hal::{
get_core,
interrupt::{self, InterruptHandler},
system::SoftwareInterrupt,
};
use portable_atomic::{AtomicUsize, Ordering};

static mut EXECUTORS: [CallbackContext; 4] = [
CallbackContext::new(),
Expand Down Expand Up @@ -43,7 +43,7 @@ impl CallbackContext {
}

fn get(&self) -> *mut raw::Executor {
unsafe { (*self.raw_executor.get()) as *mut raw::Executor }
unsafe { *self.raw_executor.get() }
}

fn set(&self, executor: *mut raw::Executor) {
Expand All @@ -58,7 +58,7 @@ fn handle_interrupt<const NUM: u8>() {
swi.reset();

unsafe {
let executor = EXECUTORS[NUM as usize].get().as_mut().unwrap();
let executor = unwrap!(EXECUTORS[NUM as usize].get().as_mut());
executor.poll();
}
}
Expand Down Expand Up @@ -151,7 +151,7 @@ impl<const SWI: u8> InterruptExecutor<SWI> {
if self.core.load(Ordering::Acquire) == usize::MAX {
panic!("InterruptExecutor::spawner() called on uninitialized executor.");
}
let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
let executor = unsafe { (*self.executor.get()).assume_init_ref() };
executor.spawner().make_send()
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
pub use self::{interrupt::*, thread::*};

mod interrupt;
mod thread;

pub use interrupt::*;
pub use thread::*;

#[export_name = "__pender"]
fn __pender(context: *mut ()) {
use crate::system::SoftwareInterrupt;
use esp_hal::system::SoftwareInterrupt;

let context = (context as usize).to_le_bytes();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
//! Multicore-aware thread-mode embassy executor.
use core::marker::PhantomData;

use embassy_executor::{raw, Spawner};
use portable_atomic::{AtomicBool, Ordering};
use esp_hal::get_core;
#[cfg(multi_core)]
use procmacros::handler;

use crate::get_core;
use esp_hal::macros::handler;
#[cfg(multi_core)]
use crate::peripherals::SYSTEM;
use esp_hal::peripherals::SYSTEM;
use portable_atomic::{AtomicBool, Ordering};

pub(crate) const THREAD_MODE_CONTEXT: u8 = 16;

Expand Down Expand Up @@ -39,7 +39,7 @@ pub(crate) fn pend_thread_mode(core: usize) {
// If we are pending a task on the current core, we're done. Otherwise, we
// need to make sure the other core wakes up.
#[cfg(multi_core)]
if core != crate::get_core() as usize {
if core != get_core() as usize {
// We need to clear the interrupt from software. We don't actually
// need it to trigger and run the interrupt handler, we just need to
// kick waiti to return.
Expand Down Expand Up @@ -78,7 +78,7 @@ impl Executor {
pub fn new() -> Self {
#[cfg(multi_core)]
unsafe {
crate::system::SoftwareInterrupt::<3>::steal()
esp_hal::system::SoftwareInterrupt::<3>::steal()
.set_interrupt_handler(software3_interrupt)
}

Expand Down Expand Up @@ -179,3 +179,9 @@ impl Executor {
// here
}
}

impl Default for Executor {
fn default() -> Self {
Self::new()
}
}
Loading

0 comments on commit 48e3e91

Please sign in to comment.