Skip to content

Instantly share code, notes, and snippets.

@rubberduck203
Last active February 11, 2020 00:41
Show Gist options
  • Save rubberduck203/20415cb0bdc0726b2ebf0903e7193665 to your computer and use it in GitHub Desktop.
Save rubberduck203/20415cb0bdc0726b2ebf0903e7193665 to your computer and use it in GitHub Desktop.
Spinlock that provides a bare_metal::CriticalSection to bare_metal::Mutex
//! Example implementation of a different way than interrupt::free to provide a critical section.
//!
#![no_main]
#![no_std]
extern crate panic_halt;
use cortex_m::peripheral::syst::SystClkSource;
use cortex_m::Peripherals;
use cortex_m_rt::{entry, exception};
use cortex_m_semihosting::hprintln;
use core::cell::Cell;
use bare_metal::{Mutex,CriticalSection};
use core::sync::atomic::{AtomicBool, Ordering};
static SPINLOCK: Spinlock = Spinlock(AtomicBool::new(false));
static COUNTER: Mutex<Cell<u32>> = Mutex::new(Cell::new(0));
#[entry]
fn main() -> ! {
let p = Peripherals::take().unwrap();
let mut syst = p.SYST;
// configures the system timer to trigger a SysTick exception every second
syst.set_clock_source(SystClkSource::Core);
syst.set_reload(8_000_000); // period = 1s
syst.enable_counter();
syst.enable_interrupt();
loop {}
}
#[exception]
fn SysTick() {
let mut count = 0;
SPINLOCK.transaction(|cs| {
count = COUNTER.borrow(cs).get();
count = count + 1;
COUNTER.borrow(cs).set(count);
});
hprintln!("{}", count).unwrap();
}
struct Spinlock(AtomicBool);
impl Spinlock {
fn lock(&self) {
while self.0.swap(true, Ordering::Acquire) {
continue;
}
}
fn unlock(&self) {
self.0.store(false, Ordering::Release);
}
//nearly identical to cortex-m's interrupt::free function
// if interrupt::free was a struct that implemented `lock` and `unlock`, the same code could be used.
fn transaction<F,R>(&self, f: F) -> R
where F: FnOnce(&CriticalSection) -> R {
self.lock();
let r = f(unsafe { &CriticalSection::new() });
self.unlock();
r
}
}
//! Spinlock that actually locks
//! Beware the deadlocks that can happen when using inside on an interrupt.
#![no_main]
#![no_std]
extern crate panic_halt;
use cortex_m::peripheral::syst::SystClkSource;
use cortex_m::Peripherals;
use cortex_m_rt::{entry, exception};
use cortex_m_semihosting::hprintln;
use core::cell::Cell;
use bare_metal::{Mutex,CriticalSection};
use core::sync::atomic::{AtomicBool, Ordering};
static SPINLOCK: Spinlock = Spinlock(AtomicBool::new(false));
static COUNTER: Mutex<Cell<u32>> = Mutex::new(Cell::new(0));
#[entry]
fn main() -> ! {
let p = Peripherals::take().unwrap();
let mut syst = p.SYST;
// configures the system timer to trigger a SysTick exception every second
syst.set_clock_source(SystClkSource::Core);
syst.set_reload(8_000_000); // period = 1s
// syst.set_reload(4_000_000); // period 0.5s
syst.enable_counter();
syst.enable_interrupt();
loop {
let mut count = 0;
SPINLOCK.transaction(|cs| {
// if you're in here when systick fires, deadlock, so keep it quick
count = COUNTER.borrow(cs).get();
});
hprintln!("{}", count).unwrap();
//cortex_m::asm::wfi();
}
}
#[exception]
fn SysTick() {
SPINLOCK.transaction(|cs| {
let count = COUNTER.borrow(cs).get();
COUNTER.borrow(cs).set(count + 1);
});
}
trait MutexT<T> {
fn lock(&self);
fn unlock(&self);
fn with_lock<F,R>(&self, f: F) -> R
where F: FnOnce(&CriticalSection) -> R {
self.lock();
let r = f(unsafe { &CriticalSection::new() });
self.unlock();
r
}
}
// impl<T> MutexT<T> for Spinlock {
// fn lock(&self) {
// }
// fn unlock(&self) {
// }
// }
struct Spinlock(AtomicBool);
impl Spinlock {
fn lock(&self) {
/*
* If current value is true (locked),
* spin until it is false (unlocked),
* then set it to true (locked) and exit.
*/
loop {
match self.0.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {
Ok(false) => break,
_ => continue
}
}
}
fn unlock(&self) {
self.0.store(false, Ordering::Release);
}
fn transaction<F,R>(&self, f: F) -> R
where F: FnOnce(&CriticalSection) -> R {
self.lock();
let r = f(unsafe { &CriticalSection::new() });
self.unlock();
r
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment