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_IntGet()
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 )
82 #define TIMEDIFF( a, b ) ((( (a)<<8) - ((b)<<8) ) >> 8 )
83 #define RTC_COUNTERGET() RTC_CounterGet()
84 #define RTC_COUNTER_BITS 24
85 #define RTC_ALL_INTS _RTC_IF_MASK
86 #define RTC_OF_INT RTC_IF_OF
87 #define RTC_COMP_INT RTC_IF_COMP0
88 #define RTC_COUNTER_MASK (_RTC_CNT_MASK)
89 #define RTC_MAX_VALUE (_RTC_CNT_MASK)
90 #define RTC_INTDISABLE( x ) RTC_IntDisable( x )
91 #define RTC_INTENABLE( x ) RTC_IntEnable( x )
92 #define RTC_INTCLEAR( x ) RTC_IntClear( x )
93 #define RTC_INTGET() RTC_IntGet()
94 #define RTC_COUNTERRESET() RTC_CounterReset()
95 #define RTC_COMPARESET( x ) RTC_CompareSet( 0, (x) & _RTC_COMP0_MASK )
96 #define RTC_COMPAREGET() RTC_CompareGet( 0 )
97 #define NVIC_CLEARPENDINGIRQ() NVIC_ClearPendingIRQ( RTC_IRQn )
98 #define NVIC_DISABLEIRQ() NVIC_DisableIRQ( RTC_IRQn )
99 #define NVIC_ENABLEIRQ() NVIC_EnableIRQ( RTC_IRQn )
103 #define MAX_RTC_TICK_CNT (RTC_MAX_VALUE+1UL)
104 #define RTC_CLOSE_TO_MAX_VALUE (RTC_MAX_VALUE-100UL)
106 #if defined(_EFM32_GECKO_FAMILY)
108 #define RTC_DIVIDER ( cmuClkDiv_2 )
111 #define RTC_DIVIDER ( cmuClkDiv_8 )
114 #define RTC_CLOCK ( 32768U )
115 #define MSEC_TO_TICKS_DIVIDER ( 1000U * RTC_DIVIDER )
116 #define MSEC_TO_TICKS_ROUNDING_FACTOR ( MSEC_TO_TICKS_DIVIDER / 2 )
117 #define MSEC_TO_TICKS( ms ) ( ( ( (uint64_t)(ms) * RTC_CLOCK ) \
118 + MSEC_TO_TICKS_ROUNDING_FACTOR ) \
119 / MSEC_TO_TICKS_DIVIDER )
121 #define TICKS_TO_MSEC_ROUNDING_FACTOR ( RTC_CLOCK / 2 )
122 #define TICKS_TO_MSEC( ticks ) ( ( ( (uint64_t)(ticks) \
123 * RTC_DIVIDER * 1000U ) \
124 + TICKS_TO_MSEC_ROUNDING_FACTOR ) \
127 #define TICKS_TO_SEC_ROUNDING_FACTOR ( RTC_CLOCK / 2 )
128 #define TICKS_TO_SEC( ticks ) ( ( ( (uint64_t)(ticks) \
130 + TICKS_TO_SEC_ROUNDING_FACTOR ) \
132 #define TICK_TIME_USEC ( 1000000 * RTC_DIVIDER / RTC_CLOCK )
138 int periodicCompensationUsec;
139 unsigned int periodicDriftUsec;
148 static Timer_t timer[ EMDRV_RTCDRV_NUM_TIMERS ];
149 static uint32_t lastStart;
150 static volatile uint32_t startTimerNestingLevel;
151 static bool inTimerIRQ;
152 static bool rtcRunning;
153 static bool rtcdrvIsInitialized =
false;
154 #if defined( EMODE_DYNAMIC )
155 static bool sleepBlocked;
158 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
159 static volatile uint32_t wallClockOverflowCnt;
160 static uint32_t wallClockTimeBase;
163 #if defined( RTCDRV_USE_RTC )
164 static const RTC_Init_TypeDef initRTC =
171 #elif defined( RTCDRV_USE_RTCC )
180 #if defined(_RTCC_CTRL_BUMODETSEN_MASK)
201 #if defined(RTCDRV_USE_LFRCO)
202 #define RTCDRV_OSC cmuSelect_LFRCO
204 #define RTCDRV_OSC cmuSelect_LFXO
207 static void checkAllTimers( uint32_t timeElapsed );
208 static void delayTicks( uint32_t ticks );
209 static void executeTimerCallbacks(
void );
210 static void rescheduleRtc( uint32_t rtcCnt );
235 while ( ( i < EMDRV_RTCDRV_NUM_TIMERS ) && ( timer[ i ].allocated ) ) {
240 if ( i == EMDRV_RTCDRV_NUM_TIMERS ) {
245 timer[ i ].allocated =
true;
270 totalTicks = MSEC_TO_TICKS( ms );
272 while ( totalTicks > RTC_CLOSE_TO_MAX_VALUE ) {
273 delayTicks( RTC_CLOSE_TO_MAX_VALUE );
274 totalTicks -= RTC_CLOSE_TO_MAX_VALUE;
276 delayTicks( totalTicks );
297 if (
id >= EMDRV_RTCDRV_NUM_TIMERS ) {
303 timer[ id ].running =
false;
304 timer[ id ].allocated =
false;
324 if ( rtcdrvIsInitialized ==
true ) {
327 rtcdrvIsInitialized =
true;
332 #if defined( CMU_LFECLKEN0_RTCC )
340 #if defined( RTCDRV_USE_RTC )
348 RTC_Init( &initRTC );
350 #elif defined( RTCDRV_USE_RTCC )
365 RTC_INTDISABLE( RTC_ALL_INTS );
366 RTC_INTCLEAR( RTC_ALL_INTS );
371 NVIC_CLEARPENDINGIRQ();
374 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
376 RTC_INTENABLE( RTC_OF_INT );
380 memset( timer, 0,
sizeof( timer ) );
383 startTimerNestingLevel = 0;
384 #if defined( EMODE_DYNAMIC )
385 sleepBlocked =
false;
388 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
389 wallClockOverflowCnt = 0;
390 wallClockTimeBase = 0;
392 #if defined( EMODE_NEVER_ALLOW_EM3EM4 )
419 RTC_INTDISABLE( RTC_ALL_INTS );
420 RTC_INTCLEAR( RTC_ALL_INTS );
421 NVIC_CLEARPENDINGIRQ();
424 #if defined( RTCDRV_USE_RTC )
427 #elif defined( RTCDRV_USE_RTCC )
432 #if defined( EMODE_NEVER_ALLOW_EM3EM4 )
437 #if defined( EMODE_DYNAMIC )
439 if ( sleepBlocked ) {
445 rtcdrvIsInitialized =
false;
469 if (
id >= EMDRV_RTCDRV_NUM_TIMERS ) {
474 if ( isRunning == NULL ) {
480 if ( ! timer[
id ].allocated ) {
484 *isRunning = timer[ id ].running;
517 uint32_t timeElapsed, cnt, compVal, loopCnt = 0;
518 uint32_t timeToNextTimerCompletion;
521 if (
id >= EMDRV_RTCDRV_NUM_TIMERS ) {
526 if ( ! timer[
id ].allocated ) {
531 if ( timeout == 0 ) {
532 if ( callback != NULL ) {
533 callback(
id, user );
539 cnt = RTC_COUNTERGET();
541 timer[ id ].callback = callback;
542 timer[ id ].ticks = MSEC_TO_TICKS( timeout );
545 timer[ id ].periodicCompensationUsec = 1000 * timeout -
546 (timer[ id ].ticks * TICK_TIME_USEC);
547 timer[ id ].periodicDriftUsec = TICK_TIME_USEC/2;
550 timer[ id ].remaining = timer[ id ].ticks + 1;
551 timer[ id ].running =
true;
552 timer[ id ].timerType = type;
553 timer[ id ].user = user;
555 if ( inTimerIRQ ==
true ) {
562 if ( startTimerNestingLevel < UINT32_MAX ) {
563 startTimerNestingLevel++;
566 if ( rtcRunning ==
false ) {
568 #if defined( RTCDRV_USE_RTC )
569 lastStart = ( cnt ) & RTC_COUNTER_MASK;
570 #elif defined( RTCDRV_USE_RTCC )
574 RTC_INTCLEAR( RTC_COMP_INT );
576 compVal =
EFM32_MIN( timer[
id ].remaining, RTC_CLOSE_TO_MAX_VALUE );
577 RTC_COMPARESET( cnt + compVal );
580 RTC_INTENABLE( RTC_COMP_INT );
582 #if defined( EMODE_DYNAMIC )
584 if ( sleepBlocked ==
false ) {
598 if ( startTimerNestingLevel == 1 ) {
600 timer[ id ].running =
false;
604 RTC_INTDISABLE( RTC_COMP_INT );
606 timeElapsed = TIMEDIFF( cnt, lastStart );
607 #if defined( RTCDRV_USE_RTC )
610 if ( timeElapsed == RTC_MAX_VALUE ) {
616 checkAllTimers( timeElapsed );
619 executeTimerCallbacks();
622 if ( loopCnt == 0 ) {
623 timer[ id ].running =
true;
628 rescheduleRtc( cnt );
630 cnt = RTC_COUNTERGET();
631 timeElapsed = TIMEDIFF( cnt, lastStart );
632 timeToNextTimerCompletion = TIMEDIFF( RTC_COMPAREGET(), lastStart );
638 while ( rtcRunning && (timeElapsed > timeToNextTimerCompletion));
642 if ( startTimerNestingLevel > 0 ) {
643 startTimerNestingLevel--;
664 if (
id >= EMDRV_RTCDRV_NUM_TIMERS ) {
669 if ( ! timer[
id ].allocated ) {
674 timer[ id ].running =
false;
699 uint32_t timeLeft, currentCnt, lastRtcStart;
702 if (
id >= EMDRV_RTCDRV_NUM_TIMERS ) {
707 if ( timeRemaining == NULL ) {
713 if ( ! timer[
id ].allocated ) {
719 if ( ! timer[
id ].running ) {
724 timeLeft = timer[ id ].remaining;
725 currentCnt = RTC_COUNTERGET();
726 lastRtcStart = lastStart;
730 currentCnt = TIMEDIFF( currentCnt, lastRtcStart );
732 if ( currentCnt > timeLeft ) {
735 timeLeft -= currentCnt;
738 tmp = TICKS_TO_MSEC( timeLeft );
739 *timeRemaining = tmp;
744 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
754 return wallClockTimeBase
759 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
770 uint32_t overflows, ticks;
775 overflows = wallClockOverflowCnt;
776 ticks = RTC_COUNTERGET();
777 }
while ( overflows != wallClockOverflowCnt );
779 #if ( RTC_COUNTER_BITS < 32 )
780 return ( overflows << RTC_COUNTER_BITS ) + ticks;
787 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
797 uint64_t overflows, ticks;
802 overflows = wallClockOverflowCnt;
803 ticks = RTC_COUNTERGET();
804 }
while ( overflows != wallClockOverflowCnt );
806 return ( overflows << RTC_COUNTER_BITS ) + ticks;
810 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
827 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
839 return MSEC_TO_TICKS( ms );
843 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
855 return MSEC_TO_TICKS( 1000 * secs );
859 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
871 return TICKS_TO_MSEC( ticks );
875 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
887 return TICKS_TO_MSEC( ticks ) / 1000;
893 #if defined( RTCDRV_USE_RTC )
894 void RTC_IRQHandler(
void)
895 #elif defined( RTCDRV_USE_RTCC )
896 void RTCC_IRQHandler(
void)
899 uint32_t flags, timeElapsed, cnt, timeToNextTimerCompletion;
906 flags = RTC_INTGET();
908 if ( flags & RTC_COMP_INT ) {
917 cnt = RTC_COUNTERGET();
922 RTC_INTDISABLE( RTC_COMP_INT );
924 timeElapsed = TIMEDIFF( cnt, lastStart );
927 checkAllTimers( timeElapsed );
930 executeTimerCallbacks();
933 rescheduleRtc( cnt );
935 cnt = RTC_COUNTERGET();
936 timeElapsed = TIMEDIFF( cnt, lastStart );
937 timeToNextTimerCompletion = TIMEDIFF( RTC_COMPAREGET(), lastStart );
942 while ( rtcRunning && (timeElapsed > timeToNextTimerCompletion));
946 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
947 if ( flags & RTC_OF_INT )
949 RTC_INTCLEAR( RTC_OF_INT );
950 wallClockOverflowCnt++;
957 static void checkAllTimers( uint32_t timeElapsed )
960 #if defined( EMODE_DYNAMIC )
961 int numOfTimersRunning = 0;
968 for ( i = 0; i < EMDRV_RTCDRV_NUM_TIMERS; i++ ) {
969 timer[ i ].doCallback =
false;
970 if ( timer[ i ].running ==
true ) {
971 #if defined( EMODE_DYNAMIC )
972 numOfTimersRunning++;
974 if ( timer[ i ].remaining > timeElapsed ) {
975 timer[ i ].remaining -= timeElapsed;
978 timer[ i ].running =
false;
979 #if defined( EMODE_DYNAMIC )
980 numOfTimersRunning--;
984 timer[ i ].remaining = timer[ i ].ticks - timeElapsed +
985 timer[ i ].remaining;
986 if ( timer[ i ].periodicCompensationUsec > 0 ) {
987 timer[ i ].periodicDriftUsec += timer[i].periodicCompensationUsec;
988 if (timer[ i ].periodicDriftUsec >= TICK_TIME_USEC) {
991 timer[ i ].remaining += 1;
992 timer[ i ].periodicDriftUsec -= TICK_TIME_USEC;
996 timer[ i ].periodicDriftUsec -= timer[i].periodicCompensationUsec;
997 if (timer[ i ].periodicDriftUsec >= TICK_TIME_USEC) {
1000 timer[ i ].remaining -= 1;
1001 timer[ i ].periodicDriftUsec -= TICK_TIME_USEC;
1005 if ( timer[ i ].callback != NULL ) {
1006 timer[ i ].doCallback =
true;
1012 #if defined( EMODE_DYNAMIC )
1014 if ( ( numOfTimersRunning == 0 ) && ( sleepBlocked ==
true ) ) {
1015 sleepBlocked =
false;
1021 static void delayTicks( uint32_t ticks )
1024 volatile uint32_t now;
1027 startTime = RTC_COUNTERGET();
1029 now = RTC_COUNTERGET();
1030 }
while ( TIMEDIFF( now, startTime ) < ticks );
1034 static void executeTimerCallbacks(
void )
1038 for ( i = 0; i < EMDRV_RTCDRV_NUM_TIMERS; i++ ) {
1039 if ( timer[ i ].doCallback ) {
1040 timer[ i ].callback( i, timer[ i ].user );
1045 static void rescheduleRtc( uint32_t rtcCnt )
1048 uint64_t min = UINT64_MAX;
1051 for ( i = 0; i < EMDRV_RTCDRV_NUM_TIMERS; i++ ) {
1052 if ( ( timer[ i ].running ==
true )
1053 && ( timer[ i ].remaining < min ) ) {
1054 min = timer[ i ].remaining;
1059 if ( min != UINT64_MAX ) {
1060 min =
EFM32_MIN( min, RTC_CLOSE_TO_MAX_VALUE );
1061 #if defined( RTCDRV_USE_RTC )
1062 if ( inTimerIRQ ==
false ) {
1063 lastStart = ( rtcCnt ) & RTC_COUNTER_MASK;
1069 RTC_INTCLEAR( RTC_COMP_INT );
1071 RTC_COMPARESET( rtcCnt + min );
1073 #if defined( EMODE_DYNAMIC )
1075 if ( sleepBlocked ==
false ) {
1076 sleepBlocked =
true;
1084 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.
uint32_t RTCDRV_TimerID_t
Timer ID.
#define ECODE_EMDRV_RTCDRV_OK
Success return value.
void RTCC_Init(const RTCC_Init_TypeDef *init)
Initialize RTCC.
void RTCC_Enable(bool enable)
Enable/disable RTCC.
#define ECODE_EMDRV_RTCDRV_TIMER_NOT_RUNNING
Timer is not running.
__STATIC_INLINE uint32_t INT_Enable(void)
Enable interrupts.
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.
Emlib general purpose utilities.
RTCDRV timer API definition.
RTCDRV_TimerType_t
Timer type enumerator.
RTCC_CntPresc_TypeDef presc
#define ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID
Illegal timer id.
Interrupt enable/disable unit API.
Ecode_t RTCDRV_StopTimer(RTCDRV_TimerID_t id)
Stop a given timer.
Ecode_t RTCDRV_Init(void)
Initialize RTCDRV driver.
#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.
uint32_t RTCDRV_TicksToMsec(uint64_t ticks)
Convert from RTC/RTCC ticks to milliseconds.
void RTCC_ChannelInit(int ch, RTCC_CCChConf_TypeDef const *confPtr)
Configure the selected capture/compare channel of the RTCC.
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.
void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
Enable/disable a clock.
#define ECODE_EMDRV_RTCDRV_TIMER_NOT_ALLOCATED
Timer is not allocated.
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.
Ecode_t RTCDRV_StartTimer(RTCDRV_TimerID_t id, RTCDRV_TimerType_t type, uint32_t timeout, RTCDRV_Callback_t callback, void *user)
Start a timer.
uint32_t Ecode_t
Typedef for API function errorcode return values.
__STATIC_INLINE uint32_t INT_Disable(void)
Disable interrupts.
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.