23 #if defined( RTCC_PRESENT ) && ( RTCC_COUNT == 1 )
24 #define RTCDRV_USE_RTCC
26 #define RTCDRV_USE_RTC
29 #if defined( RTCDRV_USE_RTCC )
36 #if defined( EMDRV_RTCDRV_SLEEPDRV_INTEGRATION )
42 #if defined( EMDRV_RTCDRV_SLEEPDRV_INTEGRATION ) \
43 && !defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG ) \
44 && defined( RTCDRV_USE_RTC )
49 #if defined( EMDRV_RTCDRV_SLEEPDRV_INTEGRATION ) \
50 && defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG ) \
51 && defined( RTCDRV_USE_RTC )
53 #define EMODE_NEVER_ALLOW_EM3EM4
59 #if defined( RTCDRV_USE_RTCC )
60 #define TIMEDIFF( a, b ) ((a) - (b))
61 #define RTC_COUNTERGET() RTCC_CounterGet()
62 #define RTC_COUNTER_BITS 32
63 #define RTC_ALL_INTS _RTCC_IF_MASK
64 #define RTC_OF_INT RTCC_IF_OF
65 #define RTC_COMP_INT RTCC_IF_CC1
66 #define RTC_COUNTER_MASK (_RTCC_CNT_MASK)
67 #define RTC_MAX_VALUE (_RTCC_CNT_MASK)
68 #define RTC_INTDISABLE( x ) RTCC_IntDisable( x )
69 #define RTC_INTENABLE( x ) RTCC_IntEnable( x )
70 #define RTC_INTCLEAR( x ) RTCC_IntClear( x )
71 #define RTC_INTGET() RTCC_IntGetEnabled()
72 #define RTC_COUNTERRESET() RTCC->CNT = _RTCC_CNT_RESETVALUE
73 #define RTC_COMPARESET( x ) RTCC_ChannelCCVSet( 1, x )
74 #define RTC_COMPAREGET() RTCC_ChannelCCVGet( 1 )
75 #define NVIC_CLEARPENDINGIRQ() NVIC_ClearPendingIRQ( RTCC_IRQn )
76 #define NVIC_DISABLEIRQ() NVIC_DisableIRQ( RTCC_IRQn )
77 #define NVIC_ENABLEIRQ() NVIC_EnableIRQ( RTCC_IRQn )
78 #define RTC_ONESHOT_TICK_ADJUST 0
83 #define TIMEDIFF( a, b ) ((( (a)<<8) - ((b)<<8) ) >> 8 )
84 #define RTC_COUNTERGET() RTC_CounterGet()
85 #define RTC_COUNTER_BITS 24
86 #define RTC_ALL_INTS _RTC_IF_MASK
87 #define RTC_OF_INT RTC_IF_OF
88 #define RTC_COMP_INT RTC_IF_COMP0
89 #define RTC_COUNTER_MASK (_RTC_CNT_MASK)
90 #define RTC_MAX_VALUE (_RTC_CNT_MASK)
91 #define RTC_INTDISABLE( x ) RTC_IntDisable( x )
92 #define RTC_INTENABLE( x ) RTC_IntEnable( x )
93 #define RTC_INTCLEAR( x ) RTC_IntClear( x )
94 #define RTC_INTGET() RTC_IntGetEnabled()
95 #define RTC_COUNTERRESET() RTC_CounterReset()
96 #define RTC_COMPARESET( x ) RTC_CompareSet( 0, (x) & _RTC_COMP0_MASK )
97 #define RTC_COMPAREGET() RTC_CompareGet( 0 )
98 #define NVIC_CLEARPENDINGIRQ() NVIC_ClearPendingIRQ( RTC_IRQn )
99 #define NVIC_DISABLEIRQ() NVIC_DisableIRQ( RTC_IRQn )
100 #define NVIC_ENABLEIRQ() NVIC_EnableIRQ( RTC_IRQn )
101 #define RTC_ONESHOT_TICK_ADJUST 1
106 #define MAX_RTC_TICK_CNT (RTC_MAX_VALUE+1UL)
107 #define RTC_CLOSE_TO_MAX_VALUE (RTC_MAX_VALUE-100UL)
109 #if defined(_EFM32_GECKO_FAMILY)
111 #define RTC_DIVIDER ( cmuClkDiv_2 )
114 #define RTC_DIVIDER ( cmuClkDiv_8 )
117 #define RTC_CLOCK ( 32768U )
118 #define MSEC_TO_TICKS_DIVIDER ( 1000U * RTC_DIVIDER )
119 #define MSEC_TO_TICKS_ROUNDING_FACTOR ( MSEC_TO_TICKS_DIVIDER / 2 )
120 #define MSEC_TO_TICKS( ms ) ( ( ( (uint64_t)(ms) * RTC_CLOCK ) \
121 + MSEC_TO_TICKS_ROUNDING_FACTOR ) \
122 / MSEC_TO_TICKS_DIVIDER )
124 #define TICKS_TO_MSEC_ROUNDING_FACTOR ( RTC_CLOCK / 2 )
125 #define TICKS_TO_MSEC( ticks ) ( ( ( (uint64_t)(ticks) \
126 * RTC_DIVIDER * 1000U ) \
127 + TICKS_TO_MSEC_ROUNDING_FACTOR ) \
130 #define TICKS_TO_SEC_ROUNDING_FACTOR ( RTC_CLOCK / 2 )
131 #define TICKS_TO_SEC( ticks ) ( ( ( (uint64_t)(ticks) \
133 + TICKS_TO_SEC_ROUNDING_FACTOR ) \
135 #define TICK_TIME_USEC ( 1000000 * RTC_DIVIDER / RTC_CLOCK )
141 int periodicCompensationUsec;
142 unsigned int periodicDriftUsec;
151 static Timer_t timer[ EMDRV_RTCDRV_NUM_TIMERS ];
152 static uint32_t lastStart;
153 static volatile uint32_t startTimerNestingLevel;
154 static bool inTimerIRQ;
155 static bool rtcRunning;
156 static bool rtcdrvIsInitialized =
false;
157 #if defined( EMODE_DYNAMIC )
158 static bool sleepBlocked;
161 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
162 static volatile uint32_t wallClockOverflowCnt;
163 static uint32_t wallClockTimeBase;
166 #if defined( RTCDRV_USE_RTC )
174 #elif defined( RTCDRV_USE_RTCC )
175 static RTCC_Init_TypeDef initRTCC =
183 #if defined(_RTCC_CTRL_BUMODETSEN_MASK)
191 static RTCC_CCChConf_TypeDef initRTCCCompareChannel =
193 rtccCapComChModeCompare,
194 rtccCompMatchOutActionPulse,
199 rtccDayCompareModeMonth
204 #if defined(EMDRV_RTCDRV_USE_LFRCO)
205 #define RTCDRV_OSC cmuSelect_LFRCO
207 #define RTCDRV_OSC cmuSelect_LFXO
210 static void checkAllTimers( uint32_t timeElapsed );
211 static void delayTicks( uint32_t ticks );
212 static void executeTimerCallbacks(
void );
213 static void rescheduleRtc( uint32_t rtcCnt );
239 while ( ( i < EMDRV_RTCDRV_NUM_TIMERS ) && ( timer[ i ].allocated ) ) {
244 if ( i == EMDRV_RTCDRV_NUM_TIMERS ) {
249 timer[ i ].allocated =
true;
274 totalTicks = MSEC_TO_TICKS( ms );
276 while ( totalTicks > RTC_CLOSE_TO_MAX_VALUE ) {
277 delayTicks( RTC_CLOSE_TO_MAX_VALUE );
278 totalTicks -= RTC_CLOSE_TO_MAX_VALUE;
280 delayTicks( totalTicks );
301 if (
id >= EMDRV_RTCDRV_NUM_TIMERS ) {
306 timer[
id ].running =
false;
307 timer[ id ].allocated =
false;
326 if ( rtcdrvIsInitialized ==
true ) {
329 rtcdrvIsInitialized =
true;
334 #if defined( CMU_LFECLKEN0_RTCC )
342 #if defined( RTCDRV_USE_RTC )
352 #elif defined( RTCDRV_USE_RTCC )
354 initRTCC.presc = (RTCC_CntPresc_TypeDef)
CMU_DivToLog2( RTC_DIVIDER );
360 RTCC_Init( &initRTCC );
363 RTCC_ChannelInit( 1, &initRTCCCompareChannel );
367 RTC_INTDISABLE( RTC_ALL_INTS );
368 RTC_INTCLEAR( RTC_ALL_INTS );
373 NVIC_CLEARPENDINGIRQ();
376 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
378 RTC_INTENABLE( RTC_OF_INT );
382 memset( timer, 0,
sizeof( timer ) );
385 startTimerNestingLevel = 0;
386 #if defined( EMODE_DYNAMIC )
387 sleepBlocked =
false;
390 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
391 wallClockOverflowCnt = 0;
392 wallClockTimeBase = 0;
394 #if defined( EMODE_NEVER_ALLOW_EM3EM4 )
421 RTC_INTDISABLE( RTC_ALL_INTS );
422 RTC_INTCLEAR( RTC_ALL_INTS );
423 NVIC_CLEARPENDINGIRQ();
426 #if defined( RTCDRV_USE_RTC )
429 #elif defined( RTCDRV_USE_RTCC )
430 RTCC_Enable(
false );
434 #if defined( EMODE_NEVER_ALLOW_EM3EM4 )
439 #if defined( EMODE_DYNAMIC )
441 if ( sleepBlocked ) {
447 rtcdrvIsInitialized =
false;
473 if (
id >= EMDRV_RTCDRV_NUM_TIMERS ) {
478 if ( isRunning == NULL ) {
484 if ( ! timer[
id ].allocated ) {
488 *isRunning = timer[ id ].running;
523 uint32_t timeElapsed, cnt, compVal, loopCnt = 0;
524 uint32_t timeToNextTimerCompletion;
527 if (
id >= EMDRV_RTCDRV_NUM_TIMERS ) {
533 if ( ! timer[
id ].allocated ) {
538 if ( timeout == 0 ) {
539 if ( callback != NULL ) {
540 callback(
id, user );
546 cnt = RTC_COUNTERGET();
548 timer[ id ].callback = callback;
549 timer[ id ].ticks = MSEC_TO_TICKS( timeout );
552 timer[ id ].periodicCompensationUsec = 1000 * timeout -
553 (timer[ id ].ticks * TICK_TIME_USEC);
554 timer[ id ].periodicDriftUsec = TICK_TIME_USEC/2;
560 timer[ id ].ticks -= RTC_ONESHOT_TICK_ADJUST;
563 timer[ id ].remaining = timer[ id ].ticks + 1;
564 timer[ id ].running =
true;
565 timer[ id ].timerType = type;
566 timer[ id ].user = user;
568 if ( inTimerIRQ ==
true ) {
575 if ( startTimerNestingLevel < UINT32_MAX ) {
576 startTimerNestingLevel++;
579 if ( rtcRunning ==
false ) {
581 #if defined( RTCDRV_USE_RTC )
582 lastStart = ( cnt ) & RTC_COUNTER_MASK;
583 #elif defined( RTCDRV_USE_RTCC )
587 RTC_INTCLEAR( RTC_COMP_INT );
589 compVal =
SL_MIN( timer[
id ].remaining, RTC_CLOSE_TO_MAX_VALUE );
590 RTC_COMPARESET( cnt + compVal );
593 RTC_INTENABLE( RTC_COMP_INT );
595 #if defined( EMODE_DYNAMIC )
597 if ( sleepBlocked ==
false ) {
611 if ( startTimerNestingLevel == 1 ) {
613 timer[ id ].running =
false;
617 RTC_INTDISABLE( RTC_COMP_INT );
619 timeElapsed = TIMEDIFF( cnt, lastStart );
620 #if defined( RTCDRV_USE_RTC )
623 if ( timeElapsed == RTC_MAX_VALUE ) {
629 checkAllTimers( timeElapsed );
632 executeTimerCallbacks();
635 if ( loopCnt == 0 ) {
636 timer[ id ].running =
true;
641 rescheduleRtc( cnt );
643 cnt = RTC_COUNTERGET();
644 timeElapsed = TIMEDIFF( cnt, lastStart );
645 timeToNextTimerCompletion = TIMEDIFF( RTC_COMPAREGET(), lastStart );
651 while ( rtcRunning && (timeElapsed > timeToNextTimerCompletion));
655 if ( startTimerNestingLevel > 0 ) {
656 startTimerNestingLevel--;
679 if (
id >= EMDRV_RTCDRV_NUM_TIMERS ) {
684 if ( ! timer[
id ].allocated ) {
689 timer[ id ].running =
false;
715 uint32_t currentCnt, lastRtcStart;
718 if (
id >= EMDRV_RTCDRV_NUM_TIMERS ) {
723 if ( timeRemaining == NULL ) {
729 if ( ! timer[
id ].allocated ) {
735 if ( ! timer[
id ].running ) {
740 ticksLeft = timer[ id ].remaining;
741 currentCnt = RTC_COUNTERGET();
742 lastRtcStart = lastStart;
746 currentCnt = TIMEDIFF( currentCnt, lastRtcStart );
748 if ( currentCnt > ticksLeft ) {
751 ticksLeft -= currentCnt;
754 *timeRemaining = TICKS_TO_MSEC( ticksLeft );
759 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
769 return wallClockTimeBase
774 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
785 uint32_t overflows, ticks;
790 overflows = wallClockOverflowCnt;
791 ticks = RTC_COUNTERGET();
792 }
while ( overflows != wallClockOverflowCnt );
794 #if ( RTC_COUNTER_BITS < 32 )
795 return ( overflows << RTC_COUNTER_BITS ) + ticks;
802 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
812 uint64_t overflows, ticks;
817 overflows = wallClockOverflowCnt;
818 ticks = RTC_COUNTERGET();
819 }
while ( overflows != wallClockOverflowCnt );
821 return ( overflows << RTC_COUNTER_BITS ) + ticks;
825 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
842 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
854 return MSEC_TO_TICKS( ms );
858 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
870 return MSEC_TO_TICKS( 1000 * secs );
874 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
886 return TICKS_TO_MSEC( ticks );
890 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
902 return TICKS_TO_MSEC( ticks ) / 1000;
908 #if defined( RTCDRV_USE_RTC )
909 void RTC_IRQHandler(
void)
910 #elif defined( RTCDRV_USE_RTCC )
911 void RTCC_IRQHandler(
void)
915 uint32_t flags, timeElapsed, cnt, timeToNextTimerCompletion;
922 flags = RTC_INTGET();
926 RTC_INTCLEAR(flags & ~(RTC_COMP_INT | RTC_OF_INT));
928 if ( flags & RTC_COMP_INT ) {
937 cnt = RTC_COUNTERGET();
942 RTC_INTDISABLE( RTC_COMP_INT );
944 timeElapsed = TIMEDIFF( cnt, lastStart );
947 checkAllTimers( timeElapsed );
950 executeTimerCallbacks();
953 rescheduleRtc( cnt );
955 cnt = RTC_COUNTERGET();
956 timeElapsed = TIMEDIFF( cnt, lastStart );
957 timeToNextTimerCompletion = TIMEDIFF( RTC_COMPAREGET(), lastStart );
962 while ( rtcRunning && (timeElapsed > timeToNextTimerCompletion));
966 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
967 if ( flags & RTC_OF_INT )
969 RTC_INTCLEAR( RTC_OF_INT );
970 wallClockOverflowCnt++;
977 static void checkAllTimers( uint32_t timeElapsed )
980 #if defined( EMODE_DYNAMIC )
981 int numOfTimersRunning = 0;
988 for ( i = 0; i < EMDRV_RTCDRV_NUM_TIMERS; i++ ) {
989 timer[ i ].doCallback =
false;
990 if ( timer[ i ].running ==
true ) {
991 #if defined( EMODE_DYNAMIC )
992 numOfTimersRunning++;
994 if ( timer[ i ].remaining > timeElapsed ) {
995 timer[ i ].remaining -= timeElapsed;
998 timer[ i ].running =
false;
999 #if defined( EMODE_DYNAMIC )
1000 numOfTimersRunning--;
1004 timer[ i ].remaining = timer[ i ].ticks - timeElapsed +
1005 timer[ i ].remaining;
1006 if ( timer[ i ].periodicCompensationUsec > 0 ) {
1007 timer[ i ].periodicDriftUsec += timer[i].periodicCompensationUsec;
1008 if (timer[ i ].periodicDriftUsec >= TICK_TIME_USEC) {
1011 timer[ i ].remaining += 1;
1012 timer[ i ].periodicDriftUsec -= TICK_TIME_USEC;
1016 timer[ i ].periodicDriftUsec -= timer[i].periodicCompensationUsec;
1017 if (timer[ i ].periodicDriftUsec >= TICK_TIME_USEC) {
1020 timer[ i ].remaining -= 1;
1021 timer[ i ].periodicDriftUsec -= TICK_TIME_USEC;
1025 if ( timer[ i ].callback != NULL ) {
1026 timer[ i ].doCallback =
true;
1032 #if defined( EMODE_DYNAMIC )
1034 if ( ( numOfTimersRunning == 0 ) && ( sleepBlocked ==
true ) ) {
1035 sleepBlocked =
false;
1041 static void delayTicks( uint32_t ticks )
1044 volatile uint32_t now;
1047 startTime = RTC_COUNTERGET();
1049 now = RTC_COUNTERGET();
1050 }
while ( TIMEDIFF( now, startTime ) < ticks );
1054 static void executeTimerCallbacks(
void )
1058 for ( i = 0; i < EMDRV_RTCDRV_NUM_TIMERS; i++ ) {
1059 if ( timer[ i ].doCallback ) {
1060 timer[ i ].callback( i, timer[ i ].user );
1065 static void rescheduleRtc( uint32_t rtcCnt )
1068 uint64_t min = UINT64_MAX;
1071 for ( i = 0; i < EMDRV_RTCDRV_NUM_TIMERS; i++ ) {
1072 if ( ( timer[ i ].running ==
true )
1073 && ( timer[ i ].remaining < min ) ) {
1074 min = timer[ i ].remaining;
1079 if ( min != UINT64_MAX ) {
1080 min =
SL_MIN( min, RTC_CLOSE_TO_MAX_VALUE );
1081 #if defined( RTCDRV_USE_RTC )
1082 if ( inTimerIRQ ==
false ) {
1083 lastStart = ( rtcCnt ) & RTC_COUNTER_MASK;
1089 RTC_INTCLEAR( RTC_COMP_INT );
1091 RTC_COMPARESET( rtcCnt + min );
1093 #if defined( EMODE_DYNAMIC )
1095 if ( sleepBlocked ==
false ) {
1096 sleepBlocked =
true;
1104 RTC_INTENABLE( RTC_COMP_INT );
Clock management unit (CMU) API.
void CMU_ClockSelectSet(CMU_Clock_TypeDef clock, CMU_Select_TypeDef ref)
Select reference clock/oscillator used for a clock branch.
uint64_t RTCDRV_SecsToTicks(uint32_t secs)
Convert from seconds to RTC/RTCC ticks.
void SLEEP_SleepBlockEnd(SLEEP_EnergyMode_t eMode)
End sleep block in the requested energy mode.
#define CORE_DECLARE_IRQ_STATE
uint32_t RTCDRV_TimerID_t
Timer ID.
#define ECODE_EMDRV_RTCDRV_OK
Success return value.
#define ECODE_EMDRV_RTCDRV_TIMER_NOT_RUNNING
Timer is not running.
Ecode_t RTCDRV_AllocateTimer(RTCDRV_TimerID_t *id)
Allocate timer.
Ecode_t RTCDRV_SetWallClock(uint32_t secs)
Set wallclock time.
CMSIS Cortex-M Peripheral Access Layer for Silicon Laboratories microcontroller devices.
void SLEEP_SleepBlockBegin(SLEEP_EnergyMode_t eMode)
Begin sleep block in the requested energy mode.
Ecode_t RTCDRV_TimeRemaining(RTCDRV_TimerID_t id, uint32_t *timeRemaining)
Get time left before a given timer expires.
#define ECODE_EMDRV_RTCDRV_PARAM_ERROR
Illegal input parameter.
General purpose utilities.
RTCDRV timer API definition.
RTCDRV_TimerType_t
Timer type enumerator.
#define ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID
Illegal timer id.
Ecode_t RTCDRV_StopTimer(RTCDRV_TimerID_t id)
Stop a given timer.
Ecode_t RTCDRV_Init(void)
Initialize RTCDRV driver.
#define CORE_ENTER_ATOMIC()
#define ECODE_EMDRV_RTCDRV_ALL_TIMERS_USED
No timers available.
uint32_t RTCDRV_GetWallClockTicks32(void)
Get wallclock tick count as a 32bit value. At 4 ticks per millisecond, overflow occurs after approxim...
uint32_t RTCDRV_GetWallClock(void)
Get wallclock time.
#define CORE_ATOMIC_SECTION(yourcode)
uint32_t RTCDRV_TicksToMsec(uint64_t ticks)
Convert from RTC/RTCC ticks to milliseconds.
uint64_t RTCDRV_GetWallClockTicks64(void)
Get wallclock tick count as a 64 bit value. This will never overflow.
uint64_t RTCDRV_MsecsToTicks(uint32_t ms)
Convert from milliseconds to RTC/RTCC ticks.
Real Time Counter (RTCC) peripheral API.
__STATIC_INLINE uint32_t CMU_DivToLog2(CMU_ClkDiv_TypeDef div)
Convert dividend to logarithmic value. Only works for even numbers equal to 2^n.
Ecode_t RTCDRV_Delay(uint32_t ms)
Millisecond delay function.
Ecode_t RTCDRV_FreeTimer(RTCDRV_TimerID_t id)
Free timer.
uint32_t Ecode_t
Typedef for API function error code return values.
void RTC_Init(const RTC_Init_TypeDef *init)
Initialize RTC.
Core interrupt handling API.
void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
Enable/disable a clock.
#define ECODE_EMDRV_RTCDRV_TIMER_NOT_ALLOCATED
Timer is not allocated.
#define CORE_EXIT_ATOMIC()
Ecode_t RTCDRV_DeInit(void)
Deinitialize RTCDRV driver.
Real Time Counter (RTC) peripheral API.
void(* RTCDRV_Callback_t)(RTCDRV_TimerID_t id, void *user)
Typedef for the user supplied callback function which is called when a timer elapse.
void RTC_Enable(bool enable)
Enable/disable RTC.
Ecode_t RTCDRV_StartTimer(RTCDRV_TimerID_t id, RTCDRV_TimerType_t type, uint32_t timeout, RTCDRV_Callback_t callback, void *user)
Start a timer.
#define SL_MIN(a, b)
Macro for getting minimum value. No sideeffects, a and b are evaluated once only. ...
Ecode_t RTCDRV_IsRunning(RTCDRV_TimerID_t id, bool *isRunning)
Check if a given timer is running.
uint32_t RTCDRV_TicksToSec(uint64_t ticks)
Convert from RTC/RTCC ticks to seconds.
void CMU_ClockDivSet(CMU_Clock_TypeDef clock, CMU_ClkDiv_TypeDef div)
Set clock divisor/prescaler.
Energy Modes management driver.