aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Dario Nieuwenhuis <dirbaio@dirbaio.net> 2022-08-11 01:49:33 +0200
committerGravatar Dario Nieuwenhuis <dirbaio@dirbaio.net> 2022-08-11 23:31:08 +0200
commit3a15a6b4b320fa328e8ab99c31f81536960dd280 (patch)
tree4c3ef55e91988845873479460e438afea445c919 /src
parent4e908625204a1e95dd3fd5bdcd8d66d6bc11c3bc (diff)
downloadcortex-m-3a15a6b4b320fa328e8ab99c31f81536960dd280.tar.gz
cortex-m-3a15a6b4b320fa328e8ab99c31f81536960dd280.tar.zst
cortex-m-3a15a6b4b320fa328e8ab99c31f81536960dd280.zip
Add implementation for critical-section 1.0
Co-Authored-By: Markus Reiter <me@reitermark.us>
Diffstat (limited to 'src')
-rw-r--r--src/critical_section.rs27
-rw-r--r--src/interrupt.rs22
-rw-r--r--src/lib.rs7
-rw-r--r--src/macros.rs2
-rw-r--r--src/peripheral/mod.rs3
-rw-r--r--src/peripheral/sau.rs5
6 files changed, 48 insertions, 18 deletions
diff --git a/src/critical_section.rs b/src/critical_section.rs
new file mode 100644
index 0000000..688058d
--- /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 was_active = primask::read().is_active();
+ interrupt::disable();
+ was_active
+ }
+
+ unsafe fn release(was_active: RawRestoreState) {
+ // Only re-enable interrupts if they were enabled before the critical section.
+ if was_active {
+ interrupt::enable()
+ }
+ }
+ }
+}
+
+pub use critical_section::with;
diff --git a/src/interrupt.rs b/src/interrupt.rs
index 72450c4..f6ce990 100644
--- a/src/interrupt.rs
+++ b/src/interrupt.rs
@@ -1,6 +1,5 @@
//! Interrupts
-pub use bare_metal::{CriticalSection, Mutex};
#[cfg(cortex_m)]
use core::arch::asm;
#[cfg(cortex_m)]
@@ -27,7 +26,7 @@ pub unsafe trait InterruptNumber: Copy {
fn number(self) -> u16;
}
-/// Disables all interrupts
+/// Disables all interrupts in the current core.
#[cfg(cortex_m)]
#[inline]
pub fn disable() {
@@ -39,11 +38,11 @@ pub fn disable() {
compiler_fence(Ordering::SeqCst);
}
-/// Enables all the interrupts
+/// Enables all the interrupts in the current core.
///
/// # Safety
///
-/// - Do not call this function inside an `interrupt::free` critical section
+/// - Do not call this function inside a critical section.
#[cfg(cortex_m)]
#[inline]
pub unsafe fn enable() {
@@ -53,21 +52,26 @@ pub unsafe fn enable() {
asm!("cpsie i", options(nomem, nostack, preserves_flags));
}
-/// Execute closure `f` in an interrupt-free context.
+/// Execute closure `f` with interrupts disabled in the current core.
///
-/// This as also known as a "critical section".
+/// This method does not synchronise multiple cores and may disable required
+/// interrupts on some platforms; see the `critical-section` crate for a cross-platform
+/// way to enter a critical section which provides a `CriticalSection` token.
+///
+/// This crate provides an implementation for `critical-section` suitable for single-core systems,
+/// based on disabling all interrupts. It can be enabled with the `critical-section-single-core` feature.
#[cfg(cortex_m)]
#[inline]
pub fn free<F, R>(f: F) -> R
where
- F: FnOnce(&CriticalSection) -> R,
+ F: FnOnce() -> R,
{
let primask = crate::register::primask::read();
// disable interrupts
disable();
- let r = f(unsafe { &CriticalSection::new() });
+ let r = f();
// If the interrupts were active before our `disable` call, then re-enable
// them. Otherwise, keep them disabled
@@ -85,7 +89,7 @@ where
#[inline]
pub fn free<F, R>(_: F) -> R
where
- F: FnOnce(&CriticalSection) -> R,
+ F: FnOnce() -> R,
{
panic!("cortex_m::interrupt::free() is only functional on cortex-m platforms");
}
diff --git a/src/lib.rs b/src/lib.rs
index e430dd8..97fd97a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -43,15 +43,16 @@
// Don't warn about feature(asm) being stable on Rust >= 1.59.0
#![allow(stable_features)]
-extern crate bare_metal;
-extern crate volatile_register;
-
#[macro_use]
mod macros;
pub mod asm;
#[cfg(armv8m)]
pub mod cmse;
+// This is only public so the `singleton` macro does not require depending on
+// the `critical-section` crate separately.
+#[doc(hidden)]
+pub mod critical_section;
pub mod delay;
pub mod interrupt;
#[cfg(all(not(armv6m), not(armv8m_base)))]
diff --git a/src/macros.rs b/src/macros.rs
index 512c932..21bf78b 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -62,7 +62,7 @@ macro_rules! iprintln {
#[macro_export]
macro_rules! singleton {
($name:ident: $ty:ty = $expr:expr) => {
- $crate::interrupt::free(|_| {
+ $crate::critical_section::with(|_| {
// this is a tuple of a MaybeUninit and a bool because using an Option here is
// problematic: Due to niche-optimization, an Option could end up producing a non-zero
// initializer value which would move the entire static from `.bss` into `.data`...
diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs
index c316886..bf18151 100644
--- a/src/peripheral/mod.rs
+++ b/src/peripheral/mod.rs
@@ -57,7 +57,6 @@
//!
//! - ARMv7-M Architecture Reference Manual (Issue E.b) - Chapter B3
-use crate::interrupt;
use core::marker::PhantomData;
use core::ops;
@@ -164,7 +163,7 @@ impl Peripherals {
/// Returns all the core peripherals *once*
#[inline]
pub fn take() -> Option<Self> {
- interrupt::free(|_| {
+ critical_section::with(|_| {
if unsafe { TAKEN } {
None
} else {
diff --git a/src/peripheral/sau.rs b/src/peripheral/sau.rs
index da91aca..6b8477f 100644
--- a/src/peripheral/sau.rs
+++ b/src/peripheral/sau.rs
@@ -7,7 +7,6 @@
//!
//! For reference please check the section B8.3 of the Armv8-M Architecture Reference Manual.
-use crate::interrupt;
use crate::peripheral::SAU;
use bitfield::bitfield;
use volatile_register::{RO, RW};
@@ -162,7 +161,7 @@ impl SAU {
/// This function is executed under a critical section to prevent having inconsistent results.
#[inline]
pub fn set_region(&mut self, region_number: u8, region: SauRegion) -> Result<(), SauError> {
- interrupt::free(|_| {
+ critical_section::with(|_| {
let base_address = region.base_address;
let limit_address = region.limit_address;
let attribute = region.attribute;
@@ -215,7 +214,7 @@ impl SAU {
/// This function is executed under a critical section to prevent having inconsistent results.
#[inline]
pub fn get_region(&mut self, region_number: u8) -> Result<SauRegion, SauError> {
- interrupt::free(|_| {
+ critical_section::with(|_| {
if region_number >= self.region_numbers() {
Err(SauError::RegionNumberTooBig)
} else {