Skip to content

Commit 1be967a

Browse files
committed
Improve timeout implementation
1 parent e9152f9 commit 1be967a

File tree

2 files changed

+151
-48
lines changed

2 files changed

+151
-48
lines changed

freertos-rust/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ The freertos-build crate can be used to build and link FreeRTOS from source insi
1010
name = "freertos-next"
1111
readme = "README.md"
1212
repository = "https://github.com/mcu-rust/FreeRTOS"
13-
version = "0.5.0"
13+
version = "0.5.1"
1414

1515

1616
[lib]

freertos-rust/src/os_traits_impls.rs

Lines changed: 150 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
use crate::*;
22
use core::{cell::UnsafeCell, marker::PhantomData};
3-
use os_trait::{
4-
FakeRawMutex, KilohertzU32, MicrosDurationU32, TickInstant, TickTimeoutNs, TickTimeoutState,
5-
prelude::*,
6-
};
3+
use os_trait::{FakeRawMutex, MicrosDurationU32, prelude::*};
74

85
/// `OsInterface` implementation, the N can be choose between [`SemaphoreNotifier`]
96
pub struct FreeRTOS<N> {
@@ -20,8 +17,8 @@ where
2017
type RawMutex = FakeRawMutex;
2118
type Notifier = N::Notifier;
2219
type NotifyWaiter = N::Waiter;
23-
type Timeout = TickTimeoutNs<FreeRtosTickInstant>;
24-
type TimeoutState = TickTimeoutState<FreeRtosTickInstant>;
20+
type Timeout = FreeRtosTimeoutNs;
21+
type TimeoutState = FreeRtosTimeoutState;
2522
type Delay = FreeRtosTickDelayNs;
2623

2724
const O: Self = Self { _n: PhantomData };
@@ -33,7 +30,7 @@ where
3330

3431
#[inline]
3532
fn timeout() -> Self::Timeout {
36-
TickTimeoutNs::<FreeRtosTickInstant>::new()
33+
FreeRtosTimeoutNs::new()
3734
}
3835

3936
#[inline]
@@ -207,13 +204,13 @@ impl FreeRtosTickDelayNs {
207204
impl DelayNs for FreeRtosTickDelayNs {
208205
#[inline]
209206
fn delay_ns(&mut self, ns: u32) {
210-
let mut t = TickTimeoutNs::<FreeRtosTickInstant>::new().start_ns(ns);
207+
let mut t = FreeRtosTimeoutNs::new().start_ns(ns);
211208
while !t.timeout() {}
212209
}
213210

214211
#[inline]
215212
fn delay_us(&mut self, us: u32) {
216-
let mut t = TickTimeoutNs::<FreeRtosTickInstant>::new().start_us(us);
213+
let mut t = FreeRtosTimeoutNs::new().start_us(us);
217214
while !t.timeout() {
218215
CurrentTask::yield_now();
219216
}
@@ -225,65 +222,171 @@ impl DelayNs for FreeRtosTickDelayNs {
225222
}
226223
}
227224

228-
#[derive(Clone, Copy)]
229-
pub struct FreeRtosTickInstant {
230-
sys_tick: u32,
231-
tick_count: u32,
225+
#[derive(Default)]
226+
pub struct FreeRtosTimeoutNs {}
227+
228+
impl FreeRtosTimeoutNs {
229+
pub const fn new() -> Self {
230+
Self {}
231+
}
232232
}
233233

234-
#[cfg(cortex_m)]
235-
impl TickInstant for FreeRtosTickInstant {
234+
impl TimeoutNs for FreeRtosTimeoutNs {
235+
type TimeoutState = FreeRtosTimeoutState;
236+
236237
#[inline]
237-
fn frequency() -> KilohertzU32 {
238-
use os_trait::fugit::HertzU32;
239-
HertzU32::from_raw(utils::cpu_clock_hz()).convert()
238+
fn start_ns(&self, timeout: u32) -> Self::TimeoutState {
239+
Self::TimeoutState::new_ns(timeout)
240240
}
241241

242-
fn now() -> Self {
243-
use core::sync::atomic::{Ordering, compiler_fence};
244-
use cortex_m::peripheral::SYST;
242+
#[inline]
243+
fn start_us(&self, timeout: u32) -> Self::TimeoutState {
244+
Self::TimeoutState::new_us(timeout)
245+
}
245246

246-
let tick_count = FreeRtosUtils::get_tick_count();
247-
let sys_tick = SYST::get_current();
248-
compiler_fence(Ordering::Acquire);
249-
let tick_count2 = FreeRtosUtils::get_tick_count();
250-
let sys_tick2 = SYST::get_current();
247+
#[inline]
248+
fn start_ms(&self, timeout: u32) -> Self::TimeoutState {
249+
Self::TimeoutState::new_ms(timeout)
250+
}
251+
}
251252

252-
if tick_count != tick_count2 {
253-
Self {
254-
sys_tick: sys_tick2,
255-
tick_count: tick_count2,
256-
}
257-
} else {
253+
#[cfg(cortex_m)]
254+
pub use sys_tick_timeout::*;
255+
#[cfg(cortex_m)]
256+
mod sys_tick_timeout {
257+
use super::*;
258+
use core::sync::atomic::{Ordering, compiler_fence};
259+
use cortex_m::peripheral::SYST;
260+
261+
#[derive(Clone, Copy)]
262+
pub struct FreeRtosTimeoutState {
263+
sys_tick: u32,
264+
count: u32,
265+
timeout_tick: u64,
266+
}
267+
268+
impl FreeRtosTimeoutState {
269+
pub fn new_ns(timeout: u32) -> Self {
270+
let ns = timeout as u64;
271+
let timeout_tick = (ns * Self::frequency()).div_ceil(1_000_000);
272+
Self::new(timeout_tick)
273+
}
274+
275+
pub fn new_us(timeout: u32) -> Self {
276+
let us = timeout as u64;
277+
let timeout_tick = (us * Self::frequency()).div_ceil(1_000);
278+
Self::new(timeout_tick)
279+
}
280+
281+
pub fn new_ms(timeout: u32) -> Self {
282+
let ms = timeout as u64;
283+
let timeout_tick = ms * Self::frequency();
284+
Self::new(timeout_tick)
285+
}
286+
287+
#[inline]
288+
fn frequency() -> u64 {
289+
// to kHz
290+
(utils::cpu_clock_hz() / 1000) as u64
291+
}
292+
293+
fn new(timeout_tick: u64) -> Self {
294+
let (sys_tick, count) = Self::now();
295+
let (sys_tick, count) = Self::add(sys_tick, count, timeout_tick);
258296
Self {
259297
sys_tick,
260-
tick_count,
298+
count,
299+
timeout_tick,
300+
}
301+
}
302+
303+
fn now() -> (u32, u32) {
304+
let count = FreeRtosUtils::get_tick_count();
305+
let sys_tick = SYST::get_current();
306+
compiler_fence(Ordering::Acquire);
307+
let count2 = FreeRtosUtils::get_tick_count();
308+
let sys_tick2 = SYST::get_current();
309+
310+
if count != count2 {
311+
(sys_tick2, count2)
312+
} else {
313+
(sys_tick, count)
261314
}
262315
}
316+
317+
fn add(sys_tick: u32, count: u32, tick: u64) -> (u32, u32) {
318+
let reload = (SYST::get_reload() + 1) as u64;
319+
let mut diff_count = tick / reload;
320+
let diff_sys_tick = (tick - diff_count * reload) as u32;
321+
let new_sys_tick = if diff_sys_tick > sys_tick {
322+
diff_count += 1;
323+
sys_tick + reload as u32 - diff_sys_tick
324+
} else {
325+
sys_tick - diff_sys_tick
326+
};
327+
(new_sys_tick, count.wrapping_add(diff_count as u32))
328+
}
263329
}
264330

265-
fn tick_since(self, earlier: Self) -> u32 {
266-
use cortex_m::peripheral::SYST;
267-
let reload = SYST::get_reload() + 1;
268-
(self.tick_count - earlier.tick_count) * reload + earlier.sys_tick - self.sys_tick
331+
impl TimeoutState for FreeRtosTimeoutState {
332+
/// Can be reused without calling `restart()`.
333+
fn timeout(&mut self) -> bool {
334+
let (sys_tick, count) = Self::now();
335+
if count > self.count || (count == self.count && sys_tick < self.sys_tick) {
336+
(self.sys_tick, self.count) =
337+
Self::add(self.sys_tick, self.count, self.timeout_tick);
338+
true
339+
} else {
340+
false
341+
}
342+
}
343+
344+
fn restart(&mut self) {
345+
let (sys_tick, count) = Self::now();
346+
(self.sys_tick, self.count) = Self::add(sys_tick, count, self.timeout_tick);
347+
}
269348
}
270349
}
271350

272351
#[cfg(not(cortex_m))]
273-
impl TickInstant for FreeRtosTickInstant {
274-
#[inline]
275-
fn frequency() -> KilohertzU32 {
276-
todo!()
352+
pub use other_timeout::*;
353+
#[cfg(not(cortex_m))]
354+
mod other_timeout {
355+
use super::*;
356+
357+
#[derive(Clone, Copy)]
358+
pub struct FreeRtosTimeoutState {
359+
timeout: u32,
277360
}
278361

279-
fn now() -> Self {
280-
Self {
281-
sys_tick: 0,
282-
tick_count: 0,
362+
impl FreeRtosTimeoutState {
363+
pub fn new_ns(timeout: u32) -> Self {
364+
Self::new(timeout)
365+
}
366+
367+
pub fn new_us(timeout: u32) -> Self {
368+
Self::new(timeout)
369+
}
370+
371+
pub fn new_ms(timeout: u32) -> Self {
372+
Self::new(timeout)
373+
}
374+
375+
fn new(timeout: u32) -> Self {
376+
Self { timeout }
283377
}
284378
}
285379

286-
fn tick_since(self, _earlier: Self) -> u32 {
287-
self.tick_count + self.sys_tick
380+
impl TimeoutState for FreeRtosTimeoutState {
381+
/// Can be reused without calling `restart()`.
382+
#[inline]
383+
fn timeout(&mut self) -> bool {
384+
true
385+
}
386+
387+
#[inline]
388+
fn restart(&mut self) {
389+
self.timeout = 0;
390+
}
288391
}
289392
}

0 commit comments

Comments
 (0)