Skip to content

Commit

Permalink
feat: td-systick-multi-alarms feature
Browse files Browse the repository at this point in the history
  • Loading branch information
decaday committed Dec 2, 2024
1 parent ff50a64 commit ba3f660
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 10 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ time-driver-tim15 = ["_time-driver"]

time-driver-systick = ["portable-atomic"]

# td == time-driver, to avoid confliction
# By default, only one alarm is provided (similar to a 2-channel timer). Enabling this feature provides three alarms (similar to a 4-channel timer).
# Of course, this will also increase the execution time of the interrupt handler.
td-systick-multi-alarms = ["time-driver-systick"]

_time-driver = []


Expand Down
2 changes: 1 addition & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ fn main() {
.to_ascii_lowercase(),
),
Err(GetOneError::None) => None,
Err(GetOneError::Multiple) => panic!("Multiple py32xx Cargo features enabled"),
Err(GetOneError::Multiple) => panic!("Multiple time-driver-xxx Cargo features enabled"),
};

let time_driver_singleton = match time_driver.as_ref().map(|x| x.as_ref()) {
Expand Down
67 changes: 58 additions & 9 deletions src/systick_time_driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use embassy_sync::blocking_mutex::Mutex;
use embassy_time_driver::{AlarmHandle, Driver, TICK_HZ};

// Maximum number of supported alarms
#[cfg(feature = "td-systick-multi-alarms")]
const ALARM_COUNT: usize = 3;

// Alarm state structure to manage individual alarms
Expand Down Expand Up @@ -40,7 +41,10 @@ pub(crate) struct SysTickDriver {
// Number of allocated alarms
alarm_count: AtomicU8,
// Mutex-protected array of alarms
#[cfg(feature = "td-systick-multi-alarms")]
alarms: Mutex<CriticalSectionRawMutex, [AlarmState; ALARM_COUNT]>,
#[cfg(not(feature = "td-systick-multi-alarms"))]
alarm: Mutex<CriticalSectionRawMutex, AlarmState>,
}

// Constant initialization for alarm states
Expand All @@ -51,7 +55,10 @@ const ALARM_STATE_NEW: AlarmState = AlarmState::new();
embassy_time_driver::time_driver_impl!(static DRIVER: SysTickDriver = SysTickDriver {
ticks: AtomicU64::new(0),
alarm_count: AtomicU8::new(0),
#[cfg(feature = "td-systick-multi-alarms")]
alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]),
#[cfg(not(feature = "td-systick-multi-alarms"))]
alarm: Mutex::const_new(CriticalSectionRawMutex::new(), ALARM_STATE_NEW),
});

impl SysTickDriver {
Expand Down Expand Up @@ -84,15 +91,29 @@ impl SysTickDriver {
let current_ticks = self.ticks.fetch_add(1, Ordering::Relaxed);

// Check and trigger any due alarms
#[cfg(feature = "td-systick-multi-alarms")]
for n in 0..ALARM_COUNT {
self.check_and_trigger_alarm(n, current_ticks, cs);
}

#[cfg(not(feature = "td-systick-multi-alarms"))]
self.check_and_trigger_alarm(current_ticks, cs);
});
}

// Check if an alarm is due and trigger it if necessary
fn check_and_trigger_alarm(&self, n: usize, current_time: u64, cs: CriticalSection) {
#[inline]
fn check_and_trigger_alarm(&self,
#[cfg(feature = "td-systick-multi-alarms")]
n: usize,
current_time: u64,
cs: CriticalSection) {

#[cfg(feature = "td-systick-multi-alarms")]
let alarm = &self.alarms.borrow(cs)[n];
#[cfg(not(feature = "td-systick-multi-alarms"))]
let alarm = &self.alarm.borrow(cs);

let alarm_timestamp = alarm.timestamp.get();

// Check if alarm is scheduled and due
Expand All @@ -117,30 +138,58 @@ impl Driver for SysTickDriver {
// Allocate a new alarm
unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
critical_section::with(|_| {
let id = self.alarm_count.load(Ordering::Relaxed);
if id < ALARM_COUNT as u8 {
self.alarm_count.store(id + 1, Ordering::Relaxed);
Some(AlarmHandle::new(id as u8))
} else {
None
#[cfg(feature = "td-systick-multi-alarms")]
{
let id = self.alarm_count.load(Ordering::Relaxed);
if id < ALARM_COUNT as u8 {
self.alarm_count.store(id + 1, Ordering::Relaxed);
Some(AlarmHandle::new(id as u8))
} else {
None
}
}

#[cfg(not(feature = "td-systick-multi-alarms"))]
{
if self.alarm_count.load(Ordering::Relaxed) < 1 {
self.alarm_count.store(1, Ordering::Relaxed);
Some(AlarmHandle::new(0))
} else {
None
}
}
})
}

// Set alarm callback
#[allow(unused_variables)]
fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
critical_section::with(|cs| {
#[cfg(feature = "td-systick-multi-alarms")]
let alarm_state = &self.alarms.borrow(cs)[alarm.id() as usize];
#[cfg(not(feature = "td-systick-multi-alarms"))]
let alarm_state = &self.alarm.borrow(cs);
alarm_state.callback.set(callback as *const ());
alarm_state.ctx.set(ctx);
});
}

// Set alarm timestamp
#[allow(unused_variables)]
fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool {
critical_section::with(|cs| {
let n = alarm.id() as usize;
let alarm_state = &self.alarms.borrow(cs)[n];
let alarm_state = {
#[cfg(feature = "td-systick-multi-alarms")]
{
let n = alarm.id() as usize;
&self.alarms.borrow(cs)[n]
}
#[cfg(not(feature = "td-systick-multi-alarms"))]
{
&self.alarm.borrow(cs)
}
};


let current_time = self.now();
if timestamp <= current_time {
Expand Down

0 comments on commit ba3f660

Please sign in to comment.