Add embassy-cortex-m crate.
- Move Interrupt and InterruptExecutor from `embassy` to `embassy-cortex-m`. - Move Unborrow from `embassy` to `embassy-hal-common` (nothing in `embassy` requires it anymore) - Move PeripheralMutex from `embassy-hal-common` to `embassy-cortex-m`.
This commit is contained in:
47
embassy-cortex-m/Cargo.toml
Normal file
47
embassy-cortex-m/Cargo.toml
Normal file
@ -0,0 +1,47 @@
|
||||
[package]
|
||||
name = "embassy-cortex-m"
|
||||
version = "0.1.0"
|
||||
authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
|
||||
edition = "2018"
|
||||
resolver = "2"
|
||||
|
||||
[package.metadata.embassy_docs]
|
||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-cortex-m-v$VERSION/embassy-cortex-m/src/"
|
||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/master/embassy-cortex-m/src/"
|
||||
features = []
|
||||
flavors = [
|
||||
{ name = "thumbv6m-none-eabi", target = "thumbv6m-none-eabi", features = [] },
|
||||
{ name = "thumbv7m-none-eabi", target = "thumbv7m-none-eabi", features = [] },
|
||||
{ name = "thumbv7em-none-eabi", target = "thumbv7em-none-eabi", features = [] },
|
||||
{ name = "thumbv7em-none-eabihf", target = "thumbv7em-none-eabihf", features = [] },
|
||||
{ name = "thumbv8m.base-none-eabi", target = "thumbv8m.base-none-eabi", features = [] },
|
||||
{ name = "thumbv8m.main-none-eabi", target = "thumbv8m.main-none-eabi", features = [] },
|
||||
{ name = "thumbv8m.main-none-eabihf", target = "thumbv8m.main-none-eabihf", features = [] },
|
||||
]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
# Define the number of NVIC priority bits.
|
||||
prio-bits-0 = []
|
||||
prio-bits-1 = []
|
||||
prio-bits-2 = []
|
||||
prio-bits-3 = []
|
||||
prio-bits-4 = []
|
||||
prio-bits-5 = []
|
||||
prio-bits-6 = []
|
||||
prio-bits-7 = []
|
||||
prio-bits-8 = []
|
||||
|
||||
[dependencies]
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
|
||||
embassy = { version = "0.1.0", path = "../embassy"}
|
||||
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"
|
||||
cfg-if = "1.0.0"
|
||||
cortex-m = "0.7.3"
|
||||
|
29
embassy-cortex-m/build.rs
Normal file
29
embassy-cortex-m/build.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
||||
if target.starts_with("thumbv6m-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv6m");
|
||||
} else if target.starts_with("thumbv7m-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv7m");
|
||||
} else if target.starts_with("thumbv7em-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv7m");
|
||||
println!("cargo:rustc-cfg=armv7em"); // (not currently used)
|
||||
} else if target.starts_with("thumbv8m.base") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv8m");
|
||||
println!("cargo:rustc-cfg=armv8m_base");
|
||||
} else if target.starts_with("thumbv8m.main") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv8m");
|
||||
println!("cargo:rustc-cfg=armv8m_main");
|
||||
}
|
||||
|
||||
if target.ends_with("-eabihf") {
|
||||
println!("cargo:rustc-cfg=has_fpu");
|
||||
}
|
||||
}
|
89
embassy-cortex-m/src/executor.rs
Normal file
89
embassy-cortex-m/src/executor.rs
Normal file
@ -0,0 +1,89 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use embassy::executor::{raw, SendSpawner};
|
||||
|
||||
pub use embassy::executor::Executor;
|
||||
|
||||
fn pend_by_number(n: u16) {
|
||||
#[derive(Clone, Copy)]
|
||||
struct N(u16);
|
||||
unsafe impl cortex_m::interrupt::InterruptNumber for N {
|
||||
fn number(self) -> u16 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
cortex_m::peripheral::NVIC::pend(N(n))
|
||||
}
|
||||
|
||||
/// Interrupt mode executor.
|
||||
///
|
||||
/// This executor runs tasks in interrupt mode. The interrupt handler is set up
|
||||
/// to poll tasks, and when a task is woken the interrupt is pended from software.
|
||||
///
|
||||
/// This allows running async tasks at a priority higher than thread mode. One
|
||||
/// use case is to leave thread mode free for non-async tasks. Another use case is
|
||||
/// to run multiple executors: one in thread mode for low priority tasks and another in
|
||||
/// interrupt mode for higher priority tasks. Higher priority tasks will preempt lower
|
||||
/// priority ones.
|
||||
///
|
||||
/// It is even possible to run multiple interrupt mode executors at different priorities,
|
||||
/// by assigning different priorities to the interrupts. For an example on how to do this,
|
||||
/// See the 'multiprio' example for 'embassy-nrf'.
|
||||
///
|
||||
/// To use it, you have to pick an interrupt that won't be used by the hardware.
|
||||
/// Some chips reserve some interrupts for this purpose, sometimes named "software interrupts" (SWI).
|
||||
/// If this is not the case, you may use an interrupt from any unused peripheral.
|
||||
///
|
||||
/// It is somewhat more complex to use, it's recommended to use the thread-mode
|
||||
/// [`Executor`] instead, if it works for your use case.
|
||||
pub struct InterruptExecutor<I: Interrupt> {
|
||||
irq: I,
|
||||
inner: raw::Executor,
|
||||
not_send: PhantomData<*mut ()>,
|
||||
}
|
||||
|
||||
impl<I: Interrupt> InterruptExecutor<I> {
|
||||
/// Create a new Executor.
|
||||
pub fn new(irq: I) -> Self {
|
||||
let ctx = irq.number() as *mut ();
|
||||
Self {
|
||||
irq,
|
||||
inner: raw::Executor::new(|ctx| pend_by_number(ctx as u16), ctx),
|
||||
not_send: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Start the executor.
|
||||
///
|
||||
/// This initializes the executor, configures and enables the interrupt, and returns.
|
||||
/// 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`] because the executor effectively runs in a
|
||||
/// different "thread" (the interrupt), so spawning tasks on it is effectively
|
||||
/// sending them.
|
||||
///
|
||||
/// To obtain a [`Spawner`] for this executor, use [`Spawner::for_current_executor`] from
|
||||
/// a task running in it.
|
||||
///
|
||||
/// This function requires `&'static mut self`. This means you have to store the
|
||||
/// Executor instance in a place where it'll live forever and grants you mutable
|
||||
/// access. There's a few ways to do this:
|
||||
///
|
||||
/// - a [Forever](crate::util::Forever) (safe)
|
||||
/// - a `static mut` (unsafe)
|
||||
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
|
||||
pub fn start(&'static mut self) -> SendSpawner {
|
||||
self.irq.disable();
|
||||
|
||||
self.irq.set_handler(|ctx| unsafe {
|
||||
let executor = &*(ctx as *const raw::Executor);
|
||||
executor.poll();
|
||||
});
|
||||
self.irq.set_handler_context(&self.inner as *const _ as _);
|
||||
self.irq.enable();
|
||||
|
||||
self.inner.spawner().make_send()
|
||||
}
|
||||
}
|
228
embassy-cortex-m/src/fmt.rs
Normal file
228
embassy-cortex-m/src/fmt.rs
Normal file
@ -0,0 +1,228 @@
|
||||
#![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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt-timestamp-uptime")]
|
||||
defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
|
||||
|
||||
#[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
|
||||
}
|
||||
}
|
735
embassy-cortex-m/src/interrupt.rs
Normal file
735
embassy-cortex-m/src/interrupt.rs
Normal file
@ -0,0 +1,735 @@
|
||||
use atomic_polyfill::{compiler_fence, AtomicPtr, Ordering};
|
||||
use core::mem;
|
||||
use core::ptr;
|
||||
use cortex_m::peripheral::NVIC;
|
||||
use embassy_hal_common::Unborrow;
|
||||
|
||||
pub use embassy_macros::cortex_m_interrupt_take as take;
|
||||
|
||||
/// Implementation detail, do not use outside embassy crates.
|
||||
#[doc(hidden)]
|
||||
pub struct Handler {
|
||||
pub func: AtomicPtr<()>,
|
||||
pub ctx: AtomicPtr<()>,
|
||||
}
|
||||
|
||||
impl Handler {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
func: AtomicPtr::new(ptr::null_mut()),
|
||||
ctx: AtomicPtr::new(ptr::null_mut()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) struct NrWrap(pub(crate) u16);
|
||||
unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap {
|
||||
fn number(self) -> u16 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe trait Interrupt: Unborrow<Target = Self> {
|
||||
fn number(&self) -> u16;
|
||||
unsafe fn steal() -> Self;
|
||||
|
||||
/// Implementation detail, do not use outside embassy crates.
|
||||
#[doc(hidden)]
|
||||
unsafe fn __handler(&self) -> &'static Handler;
|
||||
}
|
||||
|
||||
pub trait InterruptExt: Interrupt {
|
||||
fn set_handler(&self, func: unsafe fn(*mut ()));
|
||||
fn remove_handler(&self);
|
||||
fn set_handler_context(&self, ctx: *mut ());
|
||||
fn enable(&self);
|
||||
fn disable(&self);
|
||||
#[cfg(not(armv6m))]
|
||||
fn is_active(&self) -> bool;
|
||||
fn is_enabled(&self) -> bool;
|
||||
fn is_pending(&self) -> bool;
|
||||
fn pend(&self);
|
||||
fn unpend(&self);
|
||||
fn get_priority(&self) -> Priority;
|
||||
fn set_priority(&self, prio: Priority);
|
||||
}
|
||||
|
||||
impl<T: Interrupt + ?Sized> InterruptExt for T {
|
||||
fn set_handler(&self, func: unsafe fn(*mut ())) {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
let handler = unsafe { self.__handler() };
|
||||
handler.func.store(func as *mut (), Ordering::Relaxed);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
fn remove_handler(&self) {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
let handler = unsafe { self.__handler() };
|
||||
handler.func.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
fn set_handler_context(&self, ctx: *mut ()) {
|
||||
let handler = unsafe { self.__handler() };
|
||||
handler.ctx.store(ctx, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn enable(&self) {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
unsafe {
|
||||
NVIC::unmask(NrWrap(self.number()));
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn disable(&self) {
|
||||
NVIC::mask(NrWrap(self.number()));
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(not(armv6m))]
|
||||
fn is_active(&self) -> bool {
|
||||
NVIC::is_active(NrWrap(self.number()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_enabled(&self) -> bool {
|
||||
NVIC::is_enabled(NrWrap(self.number()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_pending(&self) -> bool {
|
||||
NVIC::is_pending(NrWrap(self.number()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pend(&self) {
|
||||
NVIC::pend(NrWrap(self.number()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn unpend(&self) {
|
||||
NVIC::unpend(NrWrap(self.number()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_priority(&self) -> Priority {
|
||||
Priority::from(NVIC::get_priority(NrWrap(self.number())))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_priority(&self, prio: Priority) {
|
||||
unsafe {
|
||||
let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
|
||||
nvic.set_priority(NrWrap(self.number()), prio.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for Priority {
|
||||
fn from(priority: u8) -> Self {
|
||||
unsafe { mem::transmute(priority & PRIO_MASK) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Priority> for u8 {
|
||||
fn from(p: Priority) -> Self {
|
||||
p as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "prio-bits-0")]
|
||||
const PRIO_MASK: u8 = 0x00;
|
||||
#[cfg(feature = "prio-bits-1")]
|
||||
const PRIO_MASK: u8 = 0x80;
|
||||
#[cfg(feature = "prio-bits-2")]
|
||||
const PRIO_MASK: u8 = 0xc0;
|
||||
#[cfg(feature = "prio-bits-3")]
|
||||
const PRIO_MASK: u8 = 0xe0;
|
||||
#[cfg(feature = "prio-bits-4")]
|
||||
const PRIO_MASK: u8 = 0xf0;
|
||||
#[cfg(feature = "prio-bits-5")]
|
||||
const PRIO_MASK: u8 = 0xf8;
|
||||
#[cfg(feature = "prio-bits-6")]
|
||||
const PRIO_MASK: u8 = 0xfc;
|
||||
#[cfg(feature = "prio-bits-7")]
|
||||
const PRIO_MASK: u8 = 0xfe;
|
||||
#[cfg(feature = "prio-bits-8")]
|
||||
const PRIO_MASK: u8 = 0xff;
|
||||
|
||||
#[cfg(feature = "prio-bits-0")]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(u8)]
|
||||
pub enum Priority {
|
||||
P0 = 0x0,
|
||||
}
|
||||
|
||||
#[cfg(feature = "prio-bits-1")]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(u8)]
|
||||
pub enum Priority {
|
||||
P0 = 0x0,
|
||||
P1 = 0x80,
|
||||
}
|
||||
|
||||
#[cfg(feature = "prio-bits-2")]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(u8)]
|
||||
pub enum Priority {
|
||||
P0 = 0x0,
|
||||
P1 = 0x40,
|
||||
P2 = 0x80,
|
||||
P3 = 0xc0,
|
||||
}
|
||||
|
||||
#[cfg(feature = "prio-bits-3")]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(u8)]
|
||||
pub enum Priority {
|
||||
P0 = 0x0,
|
||||
P1 = 0x20,
|
||||
P2 = 0x40,
|
||||
P3 = 0x60,
|
||||
P4 = 0x80,
|
||||
P5 = 0xa0,
|
||||
P6 = 0xc0,
|
||||
P7 = 0xe0,
|
||||
}
|
||||
|
||||
#[cfg(feature = "prio-bits-4")]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(u8)]
|
||||
pub enum Priority {
|
||||
P0 = 0x0,
|
||||
P1 = 0x10,
|
||||
P2 = 0x20,
|
||||
P3 = 0x30,
|
||||
P4 = 0x40,
|
||||
P5 = 0x50,
|
||||
P6 = 0x60,
|
||||
P7 = 0x70,
|
||||
P8 = 0x80,
|
||||
P9 = 0x90,
|
||||
P10 = 0xa0,
|
||||
P11 = 0xb0,
|
||||
P12 = 0xc0,
|
||||
P13 = 0xd0,
|
||||
P14 = 0xe0,
|
||||
P15 = 0xf0,
|
||||
}
|
||||
|
||||
#[cfg(feature = "prio-bits-5")]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(u8)]
|
||||
pub enum Priority {
|
||||
P0 = 0x0,
|
||||
P1 = 0x8,
|
||||
P2 = 0x10,
|
||||
P3 = 0x18,
|
||||
P4 = 0x20,
|
||||
P5 = 0x28,
|
||||
P6 = 0x30,
|
||||
P7 = 0x38,
|
||||
P8 = 0x40,
|
||||
P9 = 0x48,
|
||||
P10 = 0x50,
|
||||
P11 = 0x58,
|
||||
P12 = 0x60,
|
||||
P13 = 0x68,
|
||||
P14 = 0x70,
|
||||
P15 = 0x78,
|
||||
P16 = 0x80,
|
||||
P17 = 0x88,
|
||||
P18 = 0x90,
|
||||
P19 = 0x98,
|
||||
P20 = 0xa0,
|
||||
P21 = 0xa8,
|
||||
P22 = 0xb0,
|
||||
P23 = 0xb8,
|
||||
P24 = 0xc0,
|
||||
P25 = 0xc8,
|
||||
P26 = 0xd0,
|
||||
P27 = 0xd8,
|
||||
P28 = 0xe0,
|
||||
P29 = 0xe8,
|
||||
P30 = 0xf0,
|
||||
P31 = 0xf8,
|
||||
}
|
||||
|
||||
#[cfg(feature = "prio-bits-6")]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(u8)]
|
||||
pub enum Priority {
|
||||
P0 = 0x0,
|
||||
P1 = 0x4,
|
||||
P2 = 0x8,
|
||||
P3 = 0xc,
|
||||
P4 = 0x10,
|
||||
P5 = 0x14,
|
||||
P6 = 0x18,
|
||||
P7 = 0x1c,
|
||||
P8 = 0x20,
|
||||
P9 = 0x24,
|
||||
P10 = 0x28,
|
||||
P11 = 0x2c,
|
||||
P12 = 0x30,
|
||||
P13 = 0x34,
|
||||
P14 = 0x38,
|
||||
P15 = 0x3c,
|
||||
P16 = 0x40,
|
||||
P17 = 0x44,
|
||||
P18 = 0x48,
|
||||
P19 = 0x4c,
|
||||
P20 = 0x50,
|
||||
P21 = 0x54,
|
||||
P22 = 0x58,
|
||||
P23 = 0x5c,
|
||||
P24 = 0x60,
|
||||
P25 = 0x64,
|
||||
P26 = 0x68,
|
||||
P27 = 0x6c,
|
||||
P28 = 0x70,
|
||||
P29 = 0x74,
|
||||
P30 = 0x78,
|
||||
P31 = 0x7c,
|
||||
P32 = 0x80,
|
||||
P33 = 0x84,
|
||||
P34 = 0x88,
|
||||
P35 = 0x8c,
|
||||
P36 = 0x90,
|
||||
P37 = 0x94,
|
||||
P38 = 0x98,
|
||||
P39 = 0x9c,
|
||||
P40 = 0xa0,
|
||||
P41 = 0xa4,
|
||||
P42 = 0xa8,
|
||||
P43 = 0xac,
|
||||
P44 = 0xb0,
|
||||
P45 = 0xb4,
|
||||
P46 = 0xb8,
|
||||
P47 = 0xbc,
|
||||
P48 = 0xc0,
|
||||
P49 = 0xc4,
|
||||
P50 = 0xc8,
|
||||
P51 = 0xcc,
|
||||
P52 = 0xd0,
|
||||
P53 = 0xd4,
|
||||
P54 = 0xd8,
|
||||
P55 = 0xdc,
|
||||
P56 = 0xe0,
|
||||
P57 = 0xe4,
|
||||
P58 = 0xe8,
|
||||
P59 = 0xec,
|
||||
P60 = 0xf0,
|
||||
P61 = 0xf4,
|
||||
P62 = 0xf8,
|
||||
P63 = 0xfc,
|
||||
}
|
||||
|
||||
#[cfg(feature = "prio-bits-7")]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(u8)]
|
||||
pub enum Priority {
|
||||
P0 = 0x0,
|
||||
P1 = 0x2,
|
||||
P2 = 0x4,
|
||||
P3 = 0x6,
|
||||
P4 = 0x8,
|
||||
P5 = 0xa,
|
||||
P6 = 0xc,
|
||||
P7 = 0xe,
|
||||
P8 = 0x10,
|
||||
P9 = 0x12,
|
||||
P10 = 0x14,
|
||||
P11 = 0x16,
|
||||
P12 = 0x18,
|
||||
P13 = 0x1a,
|
||||
P14 = 0x1c,
|
||||
P15 = 0x1e,
|
||||
P16 = 0x20,
|
||||
P17 = 0x22,
|
||||
P18 = 0x24,
|
||||
P19 = 0x26,
|
||||
P20 = 0x28,
|
||||
P21 = 0x2a,
|
||||
P22 = 0x2c,
|
||||
P23 = 0x2e,
|
||||
P24 = 0x30,
|
||||
P25 = 0x32,
|
||||
P26 = 0x34,
|
||||
P27 = 0x36,
|
||||
P28 = 0x38,
|
||||
P29 = 0x3a,
|
||||
P30 = 0x3c,
|
||||
P31 = 0x3e,
|
||||
P32 = 0x40,
|
||||
P33 = 0x42,
|
||||
P34 = 0x44,
|
||||
P35 = 0x46,
|
||||
P36 = 0x48,
|
||||
P37 = 0x4a,
|
||||
P38 = 0x4c,
|
||||
P39 = 0x4e,
|
||||
P40 = 0x50,
|
||||
P41 = 0x52,
|
||||
P42 = 0x54,
|
||||
P43 = 0x56,
|
||||
P44 = 0x58,
|
||||
P45 = 0x5a,
|
||||
P46 = 0x5c,
|
||||
P47 = 0x5e,
|
||||
P48 = 0x60,
|
||||
P49 = 0x62,
|
||||
P50 = 0x64,
|
||||
P51 = 0x66,
|
||||
P52 = 0x68,
|
||||
P53 = 0x6a,
|
||||
P54 = 0x6c,
|
||||
P55 = 0x6e,
|
||||
P56 = 0x70,
|
||||
P57 = 0x72,
|
||||
P58 = 0x74,
|
||||
P59 = 0x76,
|
||||
P60 = 0x78,
|
||||
P61 = 0x7a,
|
||||
P62 = 0x7c,
|
||||
P63 = 0x7e,
|
||||
P64 = 0x80,
|
||||
P65 = 0x82,
|
||||
P66 = 0x84,
|
||||
P67 = 0x86,
|
||||
P68 = 0x88,
|
||||
P69 = 0x8a,
|
||||
P70 = 0x8c,
|
||||
P71 = 0x8e,
|
||||
P72 = 0x90,
|
||||
P73 = 0x92,
|
||||
P74 = 0x94,
|
||||
P75 = 0x96,
|
||||
P76 = 0x98,
|
||||
P77 = 0x9a,
|
||||
P78 = 0x9c,
|
||||
P79 = 0x9e,
|
||||
P80 = 0xa0,
|
||||
P81 = 0xa2,
|
||||
P82 = 0xa4,
|
||||
P83 = 0xa6,
|
||||
P84 = 0xa8,
|
||||
P85 = 0xaa,
|
||||
P86 = 0xac,
|
||||
P87 = 0xae,
|
||||
P88 = 0xb0,
|
||||
P89 = 0xb2,
|
||||
P90 = 0xb4,
|
||||
P91 = 0xb6,
|
||||
P92 = 0xb8,
|
||||
P93 = 0xba,
|
||||
P94 = 0xbc,
|
||||
P95 = 0xbe,
|
||||
P96 = 0xc0,
|
||||
P97 = 0xc2,
|
||||
P98 = 0xc4,
|
||||
P99 = 0xc6,
|
||||
P100 = 0xc8,
|
||||
P101 = 0xca,
|
||||
P102 = 0xcc,
|
||||
P103 = 0xce,
|
||||
P104 = 0xd0,
|
||||
P105 = 0xd2,
|
||||
P106 = 0xd4,
|
||||
P107 = 0xd6,
|
||||
P108 = 0xd8,
|
||||
P109 = 0xda,
|
||||
P110 = 0xdc,
|
||||
P111 = 0xde,
|
||||
P112 = 0xe0,
|
||||
P113 = 0xe2,
|
||||
P114 = 0xe4,
|
||||
P115 = 0xe6,
|
||||
P116 = 0xe8,
|
||||
P117 = 0xea,
|
||||
P118 = 0xec,
|
||||
P119 = 0xee,
|
||||
P120 = 0xf0,
|
||||
P121 = 0xf2,
|
||||
P122 = 0xf4,
|
||||
P123 = 0xf6,
|
||||
P124 = 0xf8,
|
||||
P125 = 0xfa,
|
||||
P126 = 0xfc,
|
||||
P127 = 0xfe,
|
||||
}
|
||||
|
||||
#[cfg(feature = "prio-bits-8")]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(u8)]
|
||||
pub enum Priority {
|
||||
P0 = 0x0,
|
||||
P1 = 0x1,
|
||||
P2 = 0x2,
|
||||
P3 = 0x3,
|
||||
P4 = 0x4,
|
||||
P5 = 0x5,
|
||||
P6 = 0x6,
|
||||
P7 = 0x7,
|
||||
P8 = 0x8,
|
||||
P9 = 0x9,
|
||||
P10 = 0xa,
|
||||
P11 = 0xb,
|
||||
P12 = 0xc,
|
||||
P13 = 0xd,
|
||||
P14 = 0xe,
|
||||
P15 = 0xf,
|
||||
P16 = 0x10,
|
||||
P17 = 0x11,
|
||||
P18 = 0x12,
|
||||
P19 = 0x13,
|
||||
P20 = 0x14,
|
||||
P21 = 0x15,
|
||||
P22 = 0x16,
|
||||
P23 = 0x17,
|
||||
P24 = 0x18,
|
||||
P25 = 0x19,
|
||||
P26 = 0x1a,
|
||||
P27 = 0x1b,
|
||||
P28 = 0x1c,
|
||||
P29 = 0x1d,
|
||||
P30 = 0x1e,
|
||||
P31 = 0x1f,
|
||||
P32 = 0x20,
|
||||
P33 = 0x21,
|
||||
P34 = 0x22,
|
||||
P35 = 0x23,
|
||||
P36 = 0x24,
|
||||
P37 = 0x25,
|
||||
P38 = 0x26,
|
||||
P39 = 0x27,
|
||||
P40 = 0x28,
|
||||
P41 = 0x29,
|
||||
P42 = 0x2a,
|
||||
P43 = 0x2b,
|
||||
P44 = 0x2c,
|
||||
P45 = 0x2d,
|
||||
P46 = 0x2e,
|
||||
P47 = 0x2f,
|
||||
P48 = 0x30,
|
||||
P49 = 0x31,
|
||||
P50 = 0x32,
|
||||
P51 = 0x33,
|
||||
P52 = 0x34,
|
||||
P53 = 0x35,
|
||||
P54 = 0x36,
|
||||
P55 = 0x37,
|
||||
P56 = 0x38,
|
||||
P57 = 0x39,
|
||||
P58 = 0x3a,
|
||||
P59 = 0x3b,
|
||||
P60 = 0x3c,
|
||||
P61 = 0x3d,
|
||||
P62 = 0x3e,
|
||||
P63 = 0x3f,
|
||||
P64 = 0x40,
|
||||
P65 = 0x41,
|
||||
P66 = 0x42,
|
||||
P67 = 0x43,
|
||||
P68 = 0x44,
|
||||
P69 = 0x45,
|
||||
P70 = 0x46,
|
||||
P71 = 0x47,
|
||||
P72 = 0x48,
|
||||
P73 = 0x49,
|
||||
P74 = 0x4a,
|
||||
P75 = 0x4b,
|
||||
P76 = 0x4c,
|
||||
P77 = 0x4d,
|
||||
P78 = 0x4e,
|
||||
P79 = 0x4f,
|
||||
P80 = 0x50,
|
||||
P81 = 0x51,
|
||||
P82 = 0x52,
|
||||
P83 = 0x53,
|
||||
P84 = 0x54,
|
||||
P85 = 0x55,
|
||||
P86 = 0x56,
|
||||
P87 = 0x57,
|
||||
P88 = 0x58,
|
||||
P89 = 0x59,
|
||||
P90 = 0x5a,
|
||||
P91 = 0x5b,
|
||||
P92 = 0x5c,
|
||||
P93 = 0x5d,
|
||||
P94 = 0x5e,
|
||||
P95 = 0x5f,
|
||||
P96 = 0x60,
|
||||
P97 = 0x61,
|
||||
P98 = 0x62,
|
||||
P99 = 0x63,
|
||||
P100 = 0x64,
|
||||
P101 = 0x65,
|
||||
P102 = 0x66,
|
||||
P103 = 0x67,
|
||||
P104 = 0x68,
|
||||
P105 = 0x69,
|
||||
P106 = 0x6a,
|
||||
P107 = 0x6b,
|
||||
P108 = 0x6c,
|
||||
P109 = 0x6d,
|
||||
P110 = 0x6e,
|
||||
P111 = 0x6f,
|
||||
P112 = 0x70,
|
||||
P113 = 0x71,
|
||||
P114 = 0x72,
|
||||
P115 = 0x73,
|
||||
P116 = 0x74,
|
||||
P117 = 0x75,
|
||||
P118 = 0x76,
|
||||
P119 = 0x77,
|
||||
P120 = 0x78,
|
||||
P121 = 0x79,
|
||||
P122 = 0x7a,
|
||||
P123 = 0x7b,
|
||||
P124 = 0x7c,
|
||||
P125 = 0x7d,
|
||||
P126 = 0x7e,
|
||||
P127 = 0x7f,
|
||||
P128 = 0x80,
|
||||
P129 = 0x81,
|
||||
P130 = 0x82,
|
||||
P131 = 0x83,
|
||||
P132 = 0x84,
|
||||
P133 = 0x85,
|
||||
P134 = 0x86,
|
||||
P135 = 0x87,
|
||||
P136 = 0x88,
|
||||
P137 = 0x89,
|
||||
P138 = 0x8a,
|
||||
P139 = 0x8b,
|
||||
P140 = 0x8c,
|
||||
P141 = 0x8d,
|
||||
P142 = 0x8e,
|
||||
P143 = 0x8f,
|
||||
P144 = 0x90,
|
||||
P145 = 0x91,
|
||||
P146 = 0x92,
|
||||
P147 = 0x93,
|
||||
P148 = 0x94,
|
||||
P149 = 0x95,
|
||||
P150 = 0x96,
|
||||
P151 = 0x97,
|
||||
P152 = 0x98,
|
||||
P153 = 0x99,
|
||||
P154 = 0x9a,
|
||||
P155 = 0x9b,
|
||||
P156 = 0x9c,
|
||||
P157 = 0x9d,
|
||||
P158 = 0x9e,
|
||||
P159 = 0x9f,
|
||||
P160 = 0xa0,
|
||||
P161 = 0xa1,
|
||||
P162 = 0xa2,
|
||||
P163 = 0xa3,
|
||||
P164 = 0xa4,
|
||||
P165 = 0xa5,
|
||||
P166 = 0xa6,
|
||||
P167 = 0xa7,
|
||||
P168 = 0xa8,
|
||||
P169 = 0xa9,
|
||||
P170 = 0xaa,
|
||||
P171 = 0xab,
|
||||
P172 = 0xac,
|
||||
P173 = 0xad,
|
||||
P174 = 0xae,
|
||||
P175 = 0xaf,
|
||||
P176 = 0xb0,
|
||||
P177 = 0xb1,
|
||||
P178 = 0xb2,
|
||||
P179 = 0xb3,
|
||||
P180 = 0xb4,
|
||||
P181 = 0xb5,
|
||||
P182 = 0xb6,
|
||||
P183 = 0xb7,
|
||||
P184 = 0xb8,
|
||||
P185 = 0xb9,
|
||||
P186 = 0xba,
|
||||
P187 = 0xbb,
|
||||
P188 = 0xbc,
|
||||
P189 = 0xbd,
|
||||
P190 = 0xbe,
|
||||
P191 = 0xbf,
|
||||
P192 = 0xc0,
|
||||
P193 = 0xc1,
|
||||
P194 = 0xc2,
|
||||
P195 = 0xc3,
|
||||
P196 = 0xc4,
|
||||
P197 = 0xc5,
|
||||
P198 = 0xc6,
|
||||
P199 = 0xc7,
|
||||
P200 = 0xc8,
|
||||
P201 = 0xc9,
|
||||
P202 = 0xca,
|
||||
P203 = 0xcb,
|
||||
P204 = 0xcc,
|
||||
P205 = 0xcd,
|
||||
P206 = 0xce,
|
||||
P207 = 0xcf,
|
||||
P208 = 0xd0,
|
||||
P209 = 0xd1,
|
||||
P210 = 0xd2,
|
||||
P211 = 0xd3,
|
||||
P212 = 0xd4,
|
||||
P213 = 0xd5,
|
||||
P214 = 0xd6,
|
||||
P215 = 0xd7,
|
||||
P216 = 0xd8,
|
||||
P217 = 0xd9,
|
||||
P218 = 0xda,
|
||||
P219 = 0xdb,
|
||||
P220 = 0xdc,
|
||||
P221 = 0xdd,
|
||||
P222 = 0xde,
|
||||
P223 = 0xdf,
|
||||
P224 = 0xe0,
|
||||
P225 = 0xe1,
|
||||
P226 = 0xe2,
|
||||
P227 = 0xe3,
|
||||
P228 = 0xe4,
|
||||
P229 = 0xe5,
|
||||
P230 = 0xe6,
|
||||
P231 = 0xe7,
|
||||
P232 = 0xe8,
|
||||
P233 = 0xe9,
|
||||
P234 = 0xea,
|
||||
P235 = 0xeb,
|
||||
P236 = 0xec,
|
||||
P237 = 0xed,
|
||||
P238 = 0xee,
|
||||
P239 = 0xef,
|
||||
P240 = 0xf0,
|
||||
P241 = 0xf1,
|
||||
P242 = 0xf2,
|
||||
P243 = 0xf3,
|
||||
P244 = 0xf4,
|
||||
P245 = 0xf5,
|
||||
P246 = 0xf6,
|
||||
P247 = 0xf7,
|
||||
P248 = 0xf8,
|
||||
P249 = 0xf9,
|
||||
P250 = 0xfa,
|
||||
P251 = 0xfb,
|
||||
P252 = 0xfc,
|
||||
P253 = 0xfd,
|
||||
P254 = 0xfe,
|
||||
P255 = 0xff,
|
||||
}
|
8
embassy-cortex-m/src/lib.rs
Normal file
8
embassy-cortex-m/src/lib.rs
Normal file
@ -0,0 +1,8 @@
|
||||
#![no_std]
|
||||
|
||||
// This mod MUST go first, so that the others see its macros.
|
||||
pub(crate) mod fmt;
|
||||
|
||||
pub mod executor;
|
||||
pub mod interrupt;
|
||||
pub mod peripheral;
|
134
embassy-cortex-m/src/peripheral.rs
Normal file
134
embassy-cortex-m/src/peripheral.rs
Normal file
@ -0,0 +1,134 @@
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::MaybeUninit;
|
||||
use cortex_m::peripheral::scb::VectActive;
|
||||
use cortex_m::peripheral::{NVIC, SCB};
|
||||
|
||||
use crate::interrupt::{Interrupt, InterruptExt, Priority};
|
||||
|
||||
/// A type which can be used as state with `PeripheralMutex`.
|
||||
///
|
||||
/// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt,
|
||||
/// and `&mut T` is only `Send` where `T: Send`.
|
||||
pub trait PeripheralState: Send {
|
||||
type Interrupt: Interrupt;
|
||||
fn on_interrupt(&mut self);
|
||||
}
|
||||
|
||||
pub struct StateStorage<S>(MaybeUninit<S>);
|
||||
|
||||
impl<S> StateStorage<S> {
|
||||
pub const fn new() -> Self {
|
||||
Self(MaybeUninit::uninit())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PeripheralMutex<'a, S: PeripheralState> {
|
||||
state: *mut S,
|
||||
_phantom: PhantomData<&'a mut S>,
|
||||
irq: S::Interrupt,
|
||||
}
|
||||
|
||||
/// Whether `irq` can be preempted by the current interrupt.
|
||||
pub(crate) fn can_be_preempted(irq: &impl Interrupt) -> bool {
|
||||
match SCB::vect_active() {
|
||||
// Thread mode can't preempt anything.
|
||||
VectActive::ThreadMode => false,
|
||||
// Exceptions don't always preempt interrupts,
|
||||
// but there isn't much of a good reason to be keeping a `PeripheralMutex` in an exception anyway.
|
||||
VectActive::Exception(_) => true,
|
||||
VectActive::Interrupt { irqn } => {
|
||||
#[derive(Clone, Copy)]
|
||||
struct NrWrap(u16);
|
||||
unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap {
|
||||
fn number(self) -> u16 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
NVIC::get_priority(NrWrap(irqn.into())) < irq.get_priority().into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S: PeripheralState> PeripheralMutex<'a, S> {
|
||||
/// Create a new `PeripheralMutex` wrapping `irq`, with `init` initializing the initial state.
|
||||
///
|
||||
/// Registers `on_interrupt` as the `irq`'s handler, and enables it.
|
||||
pub fn new(
|
||||
irq: S::Interrupt,
|
||||
storage: &'a mut StateStorage<S>,
|
||||
init: impl FnOnce() -> S,
|
||||
) -> Self {
|
||||
if can_be_preempted(&irq) {
|
||||
panic!("`PeripheralMutex` cannot be created in an interrupt with higher priority than the interrupt it wraps");
|
||||
}
|
||||
|
||||
let state_ptr = storage.0.as_mut_ptr();
|
||||
|
||||
// Safety: The pointer is valid and not used by anyone else
|
||||
// because we have the `&mut StateStorage`.
|
||||
unsafe { state_ptr.write(init()) };
|
||||
|
||||
irq.disable();
|
||||
irq.set_handler(|p| unsafe {
|
||||
// Safety: it's OK to get a &mut to the state, since
|
||||
// - We checked that the thread owning the `PeripheralMutex` can't preempt us in `new`.
|
||||
// Interrupts' priorities can only be changed with raw embassy `Interrupts`,
|
||||
// which can't safely store a `PeripheralMutex` across invocations.
|
||||
// - We can't have preempted a with() call because the irq is disabled during it.
|
||||
let state = &mut *(p as *mut S);
|
||||
state.on_interrupt();
|
||||
});
|
||||
irq.set_handler_context(state_ptr as *mut ());
|
||||
irq.enable();
|
||||
|
||||
Self {
|
||||
irq,
|
||||
state: state_ptr,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with<R>(&mut self, f: impl FnOnce(&mut S) -> R) -> R {
|
||||
self.irq.disable();
|
||||
|
||||
// Safety: it's OK to get a &mut to the state, since the irq is disabled.
|
||||
let state = unsafe { &mut *self.state };
|
||||
let r = f(state);
|
||||
|
||||
self.irq.enable();
|
||||
|
||||
r
|
||||
}
|
||||
|
||||
/// Returns whether the wrapped interrupt is currently in a pending state.
|
||||
pub fn is_pending(&self) -> bool {
|
||||
self.irq.is_pending()
|
||||
}
|
||||
|
||||
/// Forces the wrapped interrupt into a pending state.
|
||||
pub fn pend(&self) {
|
||||
self.irq.pend()
|
||||
}
|
||||
|
||||
/// Forces the wrapped interrupt out of a pending state.
|
||||
pub fn unpend(&self) {
|
||||
self.irq.unpend()
|
||||
}
|
||||
|
||||
/// Gets the priority of the wrapped interrupt.
|
||||
pub fn priority(&self) -> Priority {
|
||||
self.irq.get_priority()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S: PeripheralState> Drop for PeripheralMutex<'a, S> {
|
||||
fn drop(&mut self) {
|
||||
self.irq.disable();
|
||||
self.irq.remove_handler();
|
||||
|
||||
// safety:
|
||||
// - we initialized the state in `new`, so we know it's initialized.
|
||||
// - the irq is disabled, so it won't preempt us while dropping.
|
||||
unsafe { self.state.drop_in_place() }
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user