diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 72890855..37647224 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,6 @@ jobs: toolchain: ${{ matrix.rust }} override: true - name: Run tests - run: cargo test --all + run: cargo test --all --features critical-section-single-core # FIXME: test on macOS and Windows diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index d55d697f..7a836957 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -23,3 +23,4 @@ jobs: - uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} + args: --features critical-section-single-core diff --git a/CHANGELOG.md b/CHANGELOG.md index 95ed2030..4beab901 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Added `critical-section-single-core` feature which provides an implementation for the `critical_section` crate for single-core systems, based on disabling all interrupts. (#448) + ## [v0.7.5] - 2022-05-15 ### Deprecated diff --git a/Cargo.toml b/Cargo.toml index dc0678ee..6e745c59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ links = "cortex-m" # prevent multiple versions of this crate to be linked toget [dependencies] bare-metal = { version = "0.2.4", features = ["const-fn"] } +critical-section = "1.0.0-alpha.2" volatile-register = "0.2.0" bitfield = "0.13.2" embedded-hal = "0.2.4" @@ -32,6 +33,7 @@ cm7-r0p1 = ["cm7"] inline-asm = [] linker-plugin-lto = [] std = [] +critical-section-single-core = ["critical-section/restore-state-bool"] [workspace] members = ["xtask", "cortex-m-semihosting", "panic-semihosting", "panic-itm"] diff --git a/src/critical_section.rs b/src/critical_section.rs new file mode 100644 index 00000000..43886692 --- /dev/null +++ b/src/critical_section.rs @@ -0,0 +1,27 @@ +#[cfg(all(cortex_m, feature = "critical-section-single-core"))] +mod single_core_critical_section { + use critical_section::{set_impl, Impl, RawRestoreState}; + + use crate::interrupt; + use crate::register::primask; + + struct SingleCoreCriticalSection; + set_impl!(SingleCoreCriticalSection); + + unsafe impl Impl for SingleCoreCriticalSection { + unsafe fn acquire() -> RawRestoreState { + let active = primask::read().is_active(); + if active { + interrupt::disable(); + } + active + } + + unsafe fn release(was_active: RawRestoreState) { + // Only re-enable interrupts if they were enabled before the critical section. + if was_active { + interrupt::enable() + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 4790f980..1796b783 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,6 +90,7 @@ mod macros; pub mod asm; #[cfg(armv8m)] pub mod cmse; +mod critical_section; pub mod delay; pub mod interrupt; #[cfg(all(not(armv6m), not(armv8m_base)))] diff --git a/xtask/tests/ci.rs b/xtask/tests/ci.rs index 37466e92..4522c484 100644 --- a/xtask/tests/ci.rs +++ b/xtask/tests/ci.rs @@ -32,6 +32,13 @@ fn build(package: &str, target: &str, features: &[&str]) { cargo.args(&["--features", *feat]); } + // A `critical_section` implementation is always needed. + if package == "cortex-m" { + cargo.args(&["--features", "critical-section-single-core"]); + } else { + cargo.args(&["--features", "cortex-m/critical-section-single-core"]); + } + // Cargo features don't work right when invoked from the workspace root, so change to the // package's directory when necessary. if package != "cortex-m" {