33#![ no_std]
44
55use cortex_m:: peripheral:: { syst:: SystClkSource , DCB , DWT , SYST } ;
6- pub use fugit:: { self , ExtU32 } ;
6+ pub use fugit:: { self , ExtU32 , ExtU64 } ;
77use rtic_monotonic:: Monotonic ;
88
9- /// DWT and Systick combination implementing `embedded_time::Clock` and `rtic_monotonic::Monotonic`
9+ /// DWT and Systick combination implementing `rtic_monotonic::Monotonic`.
10+ ///
11+ /// This implementation is tickless. It does not use periodic interrupts to count
12+ /// "ticks" (like `systick-monotonic`) but only to obtain actual desired compare
13+ /// events and to manage overflows.
1014///
1115/// The frequency of the DWT and SysTick is encoded using the parameter `TIMER_HZ`.
16+ /// They must be equal.
17+ ///
18+ /// Note that the SysTick interrupt must not be disabled longer than half the
19+ /// cycle counter overflow period (typically a couple seconds).
1220pub struct DwtSystick < const TIMER_HZ : u32 > {
1321 dwt : DWT ,
1422 systick : SYST ,
23+ #[ cfg( feature = "extend" ) ]
24+ last : u64 ,
1525}
1626
1727impl < const TIMER_HZ : u32 > DwtSystick < TIMER_HZ > {
1828 /// Enable the DWT and provide a new `Monotonic` based on DWT and SysTick.
1929 ///
2030 /// Note that the `sysclk` parameter should come from e.g. the HAL's clock generation function
21- /// so the real speed and the declared speed can be compared.
31+ /// so the speed calculated at runtime and the declared speed (generic parameter
32+ /// `TIMER_HZ`) can be compared.
2233 #[ inline( always) ]
2334 pub fn new ( dcb : & mut DCB , dwt : DWT , systick : SYST , sysclk : u32 ) -> Self {
2435 assert ! ( TIMER_HZ == sysclk) ;
@@ -30,19 +41,49 @@ impl<const TIMER_HZ: u32> DwtSystick<TIMER_HZ> {
3041
3142 // We do not start the counter here, it is started in `reset`.
3243
33- DwtSystick { dwt, systick }
44+ DwtSystick {
45+ dwt,
46+ systick,
47+ #[ cfg( feature = "extend" ) ]
48+ last : 0 ,
49+ }
3450 }
3551}
3652
3753impl < const TIMER_HZ : u32 > Monotonic for DwtSystick < TIMER_HZ > {
38- const DISABLE_INTERRUPT_ON_EMPTY_QUEUE : bool = true ;
39-
40- type Instant = fugit:: TimerInstantU32 < TIMER_HZ > ;
41- type Duration = fugit:: TimerDurationU32 < TIMER_HZ > ;
42-
43- #[ inline( always) ]
44- fn now ( & mut self ) -> Self :: Instant {
45- Self :: Instant :: from_ticks ( self . dwt . cyccnt . read ( ) )
54+ cfg_if:: cfg_if! {
55+ if #[ cfg( not( feature = "extend" ) ) ] {
56+ const DISABLE_INTERRUPT_ON_EMPTY_QUEUE : bool = true ;
57+
58+ type Instant = fugit:: TimerInstantU32 <TIMER_HZ >;
59+ type Duration = fugit:: TimerDurationU32 <TIMER_HZ >;
60+
61+ #[ inline( always) ]
62+ fn now( & mut self ) -> Self :: Instant {
63+ Self :: Instant :: from_ticks( self . dwt. cyccnt. read( ) )
64+ }
65+ } else {
66+ // Need to detect and track overflows.
67+ const DISABLE_INTERRUPT_ON_EMPTY_QUEUE : bool = false ;
68+
69+ type Instant = fugit:: TimerInstantU64 <TIMER_HZ >;
70+ type Duration = fugit:: TimerDurationU64 <TIMER_HZ >;
71+
72+ #[ inline( always) ]
73+ fn now( & mut self ) -> Self :: Instant {
74+ let mut high = ( self . last >> 32 ) as u32 ;
75+ let low = self . last as u32 ;
76+ let now = self . dwt. cyccnt. read( ) ;
77+
78+ // Detect CYCCNT overflow
79+ if now. wrapping_sub( low) >= 1 << 31 {
80+ high = high. wrapping_add( 1 ) ;
81+ }
82+ self . last = ( ( high as u64 ) << 32 ) | ( now as u64 ) ;
83+
84+ Self :: Instant :: from_ticks( self . last)
85+ }
86+ }
4687 }
4788
4889 unsafe fn reset ( & mut self ) {
@@ -71,7 +112,7 @@ impl<const TIMER_HZ: u32> Monotonic for DwtSystick<TIMER_HZ> {
71112 Some ( x) => max. min ( x. ticks ( ) ) . max ( 1 ) ,
72113 } ;
73114
74- self . systick . set_reload ( dur) ;
115+ self . systick . set_reload ( dur as u32 ) ;
75116 self . systick . clear_current ( ) ;
76117 }
77118
@@ -84,4 +125,11 @@ impl<const TIMER_HZ: u32> Monotonic for DwtSystick<TIMER_HZ> {
84125 fn clear_compare_flag ( & mut self ) {
85126 // NOOP with SysTick interrupt
86127 }
128+
129+ #[ cfg( feature = "extend" ) ]
130+ fn on_interrupt ( & mut self ) {
131+ // Ensure `now()` is called regularly to track overflows.
132+ // Since SysTick is narrower than CYCCNT, this is sufficient.
133+ self . now ( ) ;
134+ }
87135}
0 commit comments