EFM32 Gecko Software Documentation  efm32g-doc-5.1.2
rtcdriver.c
Go to the documentation of this file.
1 /***************************************************************************/
16 #include <string.h>
17 
18 #include "em_device.h"
19 #include "em_cmu.h"
20 #include "em_common.h"
21 #include "em_core.h"
22 
23 #if defined( RTCC_PRESENT ) && ( RTCC_COUNT == 1 )
24 #define RTCDRV_USE_RTCC
25 #else
26 #define RTCDRV_USE_RTC
27 #endif
28 
29 #if defined( RTCDRV_USE_RTCC )
30 #include "em_rtcc.h"
31 #else
32 #include "em_rtc.h"
33 #endif
34 
35 #include "rtcdriver.h"
36 #if defined( EMDRV_RTCDRV_SLEEPDRV_INTEGRATION )
37 #include "sleep.h"
38 #endif
39 
41 
42 #if defined( EMDRV_RTCDRV_SLEEPDRV_INTEGRATION ) \
43  && !defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG ) \
44  && defined( RTCDRV_USE_RTC )
45 // Do not allow EM3/EM4 energy modes when the RTC is running.
46 #define EMODE_DYNAMIC
47 #endif
48 
49 #if defined( EMDRV_RTCDRV_SLEEPDRV_INTEGRATION ) \
50  && defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG ) \
51  && defined( RTCDRV_USE_RTC )
52 // Always deny EM3/EM4 energy modes when wallclock is enabled.
53 #define EMODE_NEVER_ALLOW_EM3EM4
54 #endif
55 
56 //
57 // Various #define's to enable use of both RTC and RTCC.
58 //
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
79 
80 #else
81 // To get the math correct we must have the MSB of the underlying 24bit
82 // counter in the MSB position of a uint32_t datatype.
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
102 
103 #endif
104 
105 // Maximum number of ticks per overflow period (not the maximum tick value)
106 #define MAX_RTC_TICK_CNT (RTC_MAX_VALUE+1UL)
107 #define RTC_CLOSE_TO_MAX_VALUE (RTC_MAX_VALUE-100UL)
108 
109 #if defined(_EFM32_GECKO_FAMILY)
110 // Assume 32kHz RTC/RTCC clock, cmuClkDiv_2 prescaler, 16 ticks per millisecond
111 #define RTC_DIVIDER ( cmuClkDiv_2 )
112 #else
113 // Assume 32kHz RTC/RTCC clock, cmuClkDiv_8 prescaler, 4 ticks per millisecond
114 #define RTC_DIVIDER ( cmuClkDiv_8 )
115 #endif
116 
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 )
123 
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 ) \
128  / RTC_CLOCK )
129 
130 #define TICKS_TO_SEC_ROUNDING_FACTOR ( RTC_CLOCK / 2 )
131 #define TICKS_TO_SEC( ticks ) ( ( ( (uint64_t)(ticks) \
132  * RTC_DIVIDER ) \
133  + TICKS_TO_SEC_ROUNDING_FACTOR ) \
134  / RTC_CLOCK )
135 #define TICK_TIME_USEC ( 1000000 * RTC_DIVIDER / RTC_CLOCK )
136 
137 typedef struct Timer
138 {
139  uint64_t remaining;
140  uint64_t ticks;
141  int periodicCompensationUsec;
142  unsigned int periodicDriftUsec;
143  RTCDRV_Callback_t callback;
144  bool running;
145  bool doCallback;
146  bool allocated;
147  RTCDRV_TimerType_t timerType;
148  void *user;
149 } Timer_t;
150 
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;
159 #endif
160 
161 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
162 static volatile uint32_t wallClockOverflowCnt;
163 static uint32_t wallClockTimeBase;
164 #endif
165 
166 #if defined( RTCDRV_USE_RTC )
167 static const RTC_Init_TypeDef initRTC =
168 {
169  true, // Start counting when init completed.
170  false, // Disable updating RTC during debug halt.
171  false // Count until max. to wrap around.
172 };
173 
174 #elif defined( RTCDRV_USE_RTCC )
175 static RTCC_Init_TypeDef initRTCC =
176 {
177  true, /* Start counting when init completed. */
178  false, /* Disable updating RTC during debug halt. */
179  false, /* Prescaler counts until max. before wrap around. */
180  false, /* Counter counts until max. before wrap around. */
181  rtccCntPresc_8, /* Set RTCC prescaler to 8 */
182  rtccCntTickPresc, /* Count according to prescaler configuration */
183 #if defined(_RTCC_CTRL_BUMODETSEN_MASK)
184  false, /* Disable storing RTCC counter value in RTCC_CCV2 upon backup mode entry. */
185 #endif
186  false, /* LFXO fail detection disabled */
187  rtccCntModeNormal, /* Use RTCC in normal mode and not in calender mode */
188  false /* No leap year correction. */
189 };
190 
191 static RTCC_CCChConf_TypeDef initRTCCCompareChannel =
192 {
193  rtccCapComChModeCompare, /* Use Compare mode */
194  rtccCompMatchOutActionPulse,/* Don't care */
195  rtccPRSCh0, /* PRS not used */
196  rtccInEdgeNone, /* Capture Input not used */
197  rtccCompBaseCnt, /* Compare with Base CNT register */
198  0, /* Compare mask */
199  rtccDayCompareModeMonth /* Don't care */
200 };
201 #endif
202 
203 // default to LFXO unless specifically directed to use LFRCO
204 #if defined(EMDRV_RTCDRV_USE_LFRCO)
205  #define RTCDRV_OSC cmuSelect_LFRCO
206 #else
207  #define RTCDRV_OSC cmuSelect_LFXO
208 #endif
209 
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 );
214 
216 
217 /***************************************************************************/
232 {
234  int i = 0;
235  Ecode_t retVal = 0;
236 
238  // Iterate through the table of the timers until the first available.
239  while ( ( i < EMDRV_RTCDRV_NUM_TIMERS ) && ( timer[ i ].allocated ) ) {
240  i++;
241  }
242 
243  // Check if we reached the end of the table.
244  if ( i == EMDRV_RTCDRV_NUM_TIMERS ) {
246  } else {
247  // Check if a NULL pointer was passed.
248  if ( id != NULL ) {
249  timer[ i ].allocated = true;
250  *id = i;
251  retVal = ECODE_EMDRV_RTCDRV_OK;
252  } else {
254  }
255  }
257 
258  return retVal;
259 }
260 
261 /***************************************************************************/
270 Ecode_t RTCDRV_Delay( uint32_t ms )
271 {
272  uint64_t totalTicks;
273 
274  totalTicks = MSEC_TO_TICKS( ms );
275 
276  while ( totalTicks > RTC_CLOSE_TO_MAX_VALUE ) {
277  delayTicks( RTC_CLOSE_TO_MAX_VALUE );
278  totalTicks -= RTC_CLOSE_TO_MAX_VALUE;
279  }
280  delayTicks( totalTicks );
281 
282  return ECODE_EMDRV_RTCDRV_OK;
283 }
284 
285 /***************************************************************************/
299 {
300  // Check if valid timer ID.
301  if ( id >= EMDRV_RTCDRV_NUM_TIMERS ) {
303  }
304 
306  timer[ id ].running = false;
307  timer[ id ].allocated = false;
308  )
309 
310  return ECODE_EMDRV_RTCDRV_OK;
311 }
312 
313 /***************************************************************************/
325 {
326  if ( rtcdrvIsInitialized == true ) {
327  return ECODE_EMDRV_RTCDRV_OK;
328  }
329  rtcdrvIsInitialized = true;
330 
331  // Ensure LE modules are clocked.
332  CMU_ClockEnable( cmuClock_CORELE, true );
333 
334 #if defined( CMU_LFECLKEN0_RTCC )
335  // Enable LFECLK in CMU (will also enable oscillator if not enabled).
336  CMU_ClockSelectSet( cmuClock_LFE, RTCDRV_OSC );
337 #else
338  // Enable LFACLK in CMU (will also enable oscillator if not enabled).
339  CMU_ClockSelectSet( cmuClock_LFA, RTCDRV_OSC );
340 #endif
341 
342 #if defined( RTCDRV_USE_RTC )
343  // Set clock divider.
344  CMU_ClockDivSet( cmuClock_RTC, RTC_DIVIDER );
345 
346  // Enable RTC module clock.
347  CMU_ClockEnable( cmuClock_RTC, true );
348 
349  // Initialize RTC.
350  RTC_Init( &initRTC );
351 
352 #elif defined( RTCDRV_USE_RTCC )
353  // Set clock divider.
354  initRTCC.presc = (RTCC_CntPresc_TypeDef)CMU_DivToLog2( RTC_DIVIDER );
355 
356  // Enable RTCC module clock.
357  CMU_ClockEnable( cmuClock_RTCC, true );
358 
359  // Initialize RTCC.
360  RTCC_Init( &initRTCC );
361 
362  // Set up Compare channel.
363  RTCC_ChannelInit( 1, &initRTCCCompareChannel );
364 #endif
365 
366  // Disable RTC/RTCC interrupt generation.
367  RTC_INTDISABLE( RTC_ALL_INTS );
368  RTC_INTCLEAR( RTC_ALL_INTS );
369 
370  RTC_COUNTERRESET();
371 
372  // Clear and then enable RTC interrupts in NVIC.
373  NVIC_CLEARPENDINGIRQ();
374  NVIC_ENABLEIRQ();
375 
376 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
377  // Enable overflow interrupt for wallclock.
378  RTC_INTENABLE( RTC_OF_INT );
379 #endif
380 
381  // Reset RTCDRV internal data structures/variables.
382  memset( timer, 0, sizeof( timer ) );
383  inTimerIRQ = false;
384  rtcRunning = false;
385  startTimerNestingLevel = 0;
386 #if defined( EMODE_DYNAMIC )
387  sleepBlocked = false;
388 #endif
389 
390 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
391  wallClockOverflowCnt = 0;
392  wallClockTimeBase = 0;
393 
394 #if defined( EMODE_NEVER_ALLOW_EM3EM4 )
395  // Always block EM3 and EM4 if wallclock is running.
397 #endif
398 
399 #endif
400 
401  return ECODE_EMDRV_RTCDRV_OK;
402 }
403 
404 /***************************************************************************/
418 {
419  // Disable and clear all interrupt sources.
420  NVIC_DISABLEIRQ();
421  RTC_INTDISABLE( RTC_ALL_INTS );
422  RTC_INTCLEAR( RTC_ALL_INTS );
423  NVIC_CLEARPENDINGIRQ();
424 
425  // Disable RTC module and its clock.
426 #if defined( RTCDRV_USE_RTC )
427  RTC_Enable( false );
428  CMU_ClockEnable( cmuClock_RTC, false );
429 #elif defined( RTCDRV_USE_RTCC )
430  RTCC_Enable( false );
431  CMU_ClockEnable( cmuClock_RTCC, false );
432 #endif
433 
434 #if defined( EMODE_NEVER_ALLOW_EM3EM4 )
435  // End EM3 and EM4 blocking.
437 #endif
438 
439 #if defined( EMODE_DYNAMIC )
440  // End EM3 and EM4 blocking if a block start has been set.
441  if ( sleepBlocked ) {
443  }
444 #endif
445 
446  // Mark the driver as uninitialized.
447  rtcdrvIsInitialized = false;
448 
449  return ECODE_EMDRV_RTCDRV_OK;
450 }
451 
452 /***************************************************************************/
469 {
471 
472  // Check if valid timer ID.
473  if ( id >= EMDRV_RTCDRV_NUM_TIMERS ) {
475  }
476 
477  // Check pointer validity.
478  if ( isRunning == NULL ) {
480  }
481 
483  // Check if timer is reserved.
484  if ( ! timer[ id ].allocated ) {
487  }
488  *isRunning = timer[ id ].running;
490 
491  return ECODE_EMDRV_RTCDRV_OK;
492 }
493 
494 /***************************************************************************/
516  RTCDRV_TimerType_t type,
517  uint32_t timeout,
518  RTCDRV_Callback_t callback,
519  void *user )
520 {
522 
523  uint32_t timeElapsed, cnt, compVal, loopCnt = 0;
524  uint32_t timeToNextTimerCompletion;
525 
526  // Check if valid timer ID.
527  if ( id >= EMDRV_RTCDRV_NUM_TIMERS ) {
529  }
530 
531 
533  if ( ! timer[ id ].allocated ) {
536  }
537 
538  if ( timeout == 0 ) {
539  if ( callback != NULL ) {
540  callback( id, user );
541  }
543  return ECODE_EMDRV_RTCDRV_OK;
544  }
545 
546  cnt = RTC_COUNTERGET();
547 
548  timer[ id ].callback = callback;
549  timer[ id ].ticks = MSEC_TO_TICKS( timeout );
550  if (rtcdrvTimerTypePeriodic == type) {
551  // Calculate compensation value for periodic timers.
552  timer[ id ].periodicCompensationUsec = 1000 * timeout -
553  (timer[ id ].ticks * TICK_TIME_USEC);
554  timer[ id ].periodicDriftUsec = TICK_TIME_USEC/2;
555  }
556  else
557  {
558  // Compensate for the fact that CNT is normally COMP0+1 after a
559  // compare match event on some devices.
560  timer[ id ].ticks -= RTC_ONESHOT_TICK_ADJUST;
561  }
562  // Add one tick in order to compensate if RTC is close to an increment event.
563  timer[ id ].remaining = timer[ id ].ticks + 1;
564  timer[ id ].running = true;
565  timer[ id ].timerType = type;
566  timer[ id ].user = user;
567 
568  if ( inTimerIRQ == true ) {
569  // Exit now, remaining processing will be done in IRQ handler.
571  return ECODE_EMDRV_RTCDRV_OK;
572  }
573 
574  // StartTimer() may recurse, keep track of recursion level.
575  if ( startTimerNestingLevel < UINT32_MAX ) {
576  startTimerNestingLevel++;
577  }
578 
579  if ( rtcRunning == false ) {
580 
581 #if defined( RTCDRV_USE_RTC )
582  lastStart = ( cnt ) & RTC_COUNTER_MASK;
583 #elif defined( RTCDRV_USE_RTCC )
584  lastStart = cnt;
585 #endif
586 
587  RTC_INTCLEAR( RTC_COMP_INT );
588 
589  compVal = SL_MIN( timer[ id ].remaining, RTC_CLOSE_TO_MAX_VALUE );
590  RTC_COMPARESET( cnt + compVal );
591 
592  // Start the timer system by enabling the compare interrupt.
593  RTC_INTENABLE( RTC_COMP_INT );
594 
595 #if defined( EMODE_DYNAMIC )
596  // When RTC is running, we can not allow EM3 or EM4.
597  if ( sleepBlocked == false ) {
598  sleepBlocked = true;
600  }
601 #endif
602 
603  rtcRunning = true;
604 
605  } else {
606 
607  // The timer system is running. We must stop, update timers with the time
608  // elapsed so far, find the timer with the shortest timeout and then restart.
609  // As StartTimer() may be called from the callbacks we only do this
610  // processing at the first nesting level.
611  if ( startTimerNestingLevel == 1 ) {
612 
613  timer[ id ].running = false;
614  // This loop is repeated if CNT is incremented while processing.
615  do {
616 
617  RTC_INTDISABLE( RTC_COMP_INT );
618 
619  timeElapsed = TIMEDIFF( cnt, lastStart );
620 #if defined( RTCDRV_USE_RTC )
621  // Compensate for the fact that CNT is normally COMP0+1 after a
622  // compare match event.
623  if ( timeElapsed == RTC_MAX_VALUE ) {
624  timeElapsed = 0;
625  }
626 #endif
627 
628  // Update all timers with elapsed time.
629  checkAllTimers( timeElapsed );
630 
631  // Execute timer callbacks.
632  executeTimerCallbacks();
633 
634  // Set timer to running only after checkAllTimers() is called once.
635  if ( loopCnt == 0 ) {
636  timer[ id ].running = true;
637  }
638  loopCnt++;
639 
640  // Restart RTC according to next timeout.
641  rescheduleRtc( cnt );
642 
643  cnt = RTC_COUNTERGET();
644  timeElapsed = TIMEDIFF( cnt, lastStart );
645  timeToNextTimerCompletion = TIMEDIFF( RTC_COMPAREGET(), lastStart );
646 
647  /* If the counter has passed the COMP(ARE) register value since we
648  checked the timers, then we should recheck the timers and reschedule
649  again. */
650  }
651  while ( rtcRunning && (timeElapsed > timeToNextTimerCompletion));
652  }
653  }
654 
655  if ( startTimerNestingLevel > 0 ) {
656  startTimerNestingLevel--;
657  }
658 
660  return ECODE_EMDRV_RTCDRV_OK;
661 }
662 
663 /***************************************************************************/
675 {
677 
678  // Check if valid timer ID.
679  if ( id >= EMDRV_RTCDRV_NUM_TIMERS ) {
681  }
682 
684  if ( ! timer[ id ].allocated ) {
687  }
688 
689  timer[ id ].running = false;
691 
692  return ECODE_EMDRV_RTCDRV_OK;
693 }
694 
695 /***************************************************************************/
711 Ecode_t RTCDRV_TimeRemaining( RTCDRV_TimerID_t id, uint32_t *timeRemaining )
712 {
714  uint64_t ticksLeft;
715  uint32_t currentCnt, lastRtcStart;
716 
717  // Check if valid timer ID.
718  if ( id >= EMDRV_RTCDRV_NUM_TIMERS ) {
720  }
721 
722  // Check pointer validity.
723  if ( timeRemaining == NULL ) {
725  }
726 
728  // Check if timer is reserved.
729  if ( ! timer[ id ].allocated ) {
732  }
733 
734  // Check if timer is running.
735  if ( ! timer[ id ].running ) {
738  }
739 
740  ticksLeft = timer[ id ].remaining;
741  currentCnt = RTC_COUNTERGET();
742  lastRtcStart = lastStart;
744 
745  // Get number of RTC clock ticks elapsed since last RTC reschedule.
746  currentCnt = TIMEDIFF( currentCnt, lastRtcStart );
747 
748  if ( currentCnt > ticksLeft ) {
749  ticksLeft = 0;
750  } else {
751  ticksLeft -= currentCnt;
752  }
753 
754  *timeRemaining = TICKS_TO_MSEC( ticksLeft );
755 
756  return ECODE_EMDRV_RTCDRV_OK;
757 }
758 
759 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
760 /***************************************************************************/
767 uint32_t RTCDRV_GetWallClock( void )
768 {
769  return wallClockTimeBase
770  + (uint32_t)TICKS_TO_SEC( RTCDRV_GetWallClockTicks32() );
771 }
772 #endif
773 
774 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
775 /***************************************************************************/
784 {
785  uint32_t overflows, ticks;
786 
787  /* Need to re-read data in case overflow cnt is incremented while we read. */
788  do
789  {
790  overflows = wallClockOverflowCnt;
791  ticks = RTC_COUNTERGET();
792  } while ( overflows != wallClockOverflowCnt );
793 
794 #if ( RTC_COUNTER_BITS < 32 )
795  return ( overflows << RTC_COUNTER_BITS ) + ticks;
796 #else
797  return ticks;
798 #endif
799 }
800 #endif
801 
802 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
803 /***************************************************************************/
811 {
812  uint64_t overflows, ticks;
813 
814  /* Need to re-read data in case overflow cnt is incremented while we read. */
815  do
816  {
817  overflows = wallClockOverflowCnt;
818  ticks = RTC_COUNTERGET();
819  } while ( overflows != wallClockOverflowCnt );
820 
821  return ( overflows << RTC_COUNTER_BITS ) + ticks;
822 }
823 #endif
824 
825 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
826 /***************************************************************************/
835 Ecode_t RTCDRV_SetWallClock( uint32_t secs )
836 {
837  wallClockTimeBase = secs - TICKS_TO_SEC( RTCDRV_GetWallClockTicks32() );
838  return ECODE_EMDRV_RTCDRV_OK;
839 }
840 #endif
841 
842 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
843 /***************************************************************************/
852 uint64_t RTCDRV_MsecsToTicks( uint32_t ms )
853 {
854  return MSEC_TO_TICKS( ms );
855 }
856 #endif
857 
858 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
859 /***************************************************************************/
868 uint64_t RTCDRV_SecsToTicks( uint32_t secs )
869 {
870  return MSEC_TO_TICKS( 1000 * secs );
871 }
872 #endif
873 
874 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
875 /***************************************************************************/
884 uint32_t RTCDRV_TicksToMsec( uint64_t ticks )
885 {
886  return TICKS_TO_MSEC( ticks );
887 }
888 #endif
889 
890 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
891 /***************************************************************************/
900 uint32_t RTCDRV_TicksToSec( uint64_t ticks )
901 {
902  return TICKS_TO_MSEC( ticks ) / 1000;
903 }
904 #endif
905 
907 
908 #if defined( RTCDRV_USE_RTC )
909 void RTC_IRQHandler(void)
910 #elif defined( RTCDRV_USE_RTCC )
911 void RTCC_IRQHandler(void)
912 #endif
913 {
915  uint32_t flags, timeElapsed, cnt, timeToNextTimerCompletion;
916 
918 
919  // CNT will normally be COMP0+1 at this point,
920  // unless IRQ latency exceeded one tick period.
921 
922  flags = RTC_INTGET();
923 
924  // Acknowledge all RTC interrupts that are enabled which aren't processed
925  // below to prevent looping in the IRQ handler if these become enabled
926  RTC_INTCLEAR(flags & ~(RTC_COMP_INT | RTC_OF_INT));
927 
928  if ( flags & RTC_COMP_INT ) {
929 
930  // Stop timer system by disabling the compare IRQ.
931  // Update all timers with the time elapsed, call callbacks if needed,
932  // then find the timer with the shortest timeout (if any at all) and
933  // reenable the compare IRQ if needed.
934 
935  inTimerIRQ = true;
936 
937  cnt = RTC_COUNTERGET();
938 
939  // This loop is repeated if CNT is incremented while processing.
940  do {
941 
942  RTC_INTDISABLE( RTC_COMP_INT );
943 
944  timeElapsed = TIMEDIFF( cnt, lastStart );
945 
946  // Update all timers with elapsed time.
947  checkAllTimers( timeElapsed );
948 
949  // Execute timer callbacks.
950  executeTimerCallbacks();
951 
952  // Restart RTC according to next timeout.
953  rescheduleRtc( cnt );
954 
955  cnt = RTC_COUNTERGET();
956  timeElapsed = TIMEDIFF( cnt, lastStart );
957  timeToNextTimerCompletion = TIMEDIFF( RTC_COMPAREGET(), lastStart );
958  /* If the counter has passed the COMP(ARE) register value since we
959  checked the timers, then we should recheck the timers and reschedule
960  again. */
961  }
962  while ( rtcRunning && (timeElapsed > timeToNextTimerCompletion));
963  inTimerIRQ = false;
964  }
965 
966 #if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
967  if ( flags & RTC_OF_INT )
968  {
969  RTC_INTCLEAR( RTC_OF_INT );
970  wallClockOverflowCnt++;
971  }
972 #endif
973 
975 }
976 
977 static void checkAllTimers( uint32_t timeElapsed )
978 {
979  int i;
980 #if defined( EMODE_DYNAMIC )
981  int numOfTimersRunning = 0;
982 #endif
983 
984  // Iterate through the timer table.
985  // Update time remaining, check for timeout and rescheduling of periodic
986  // timers, check for callbacks.
987 
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++;
993 #endif
994  if ( timer[ i ].remaining > timeElapsed ) {
995  timer[ i ].remaining -= timeElapsed;
996  } else {
997  if ( timer[ i ].timerType == rtcdrvTimerTypeOneshot ) {
998  timer[ i ].running = false;
999 #if defined( EMODE_DYNAMIC )
1000  numOfTimersRunning--;
1001 #endif
1002  } else {
1003  // Compensate overdue periodic timers to avoid accumlating errors.
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) {
1009  // Add a tick if the timer drift is longer than the time of
1010  // one tick.
1011  timer[ i ].remaining += 1;
1012  timer[ i ].periodicDriftUsec -= TICK_TIME_USEC;
1013  }
1014  }
1015  else {
1016  timer[ i ].periodicDriftUsec -= timer[i].periodicCompensationUsec;
1017  if (timer[ i ].periodicDriftUsec >= TICK_TIME_USEC) {
1018  // Subtract one tick if the timer drift is longer than the time
1019  // of one tick.
1020  timer[ i ].remaining -= 1;
1021  timer[ i ].periodicDriftUsec -= TICK_TIME_USEC;
1022  }
1023  }
1024  }
1025  if ( timer[ i ].callback != NULL ) {
1026  timer[ i ].doCallback = true;
1027  }
1028  }
1029  }
1030  }
1031 
1032 #if defined( EMODE_DYNAMIC )
1033  // If no timers are running, we can remove block on EM3 and EM4 sleep modes.
1034  if ( ( numOfTimersRunning == 0 ) && ( sleepBlocked == true ) ) {
1035  sleepBlocked = false;
1037  }
1038 #endif
1039 }
1040 
1041 static void delayTicks( uint32_t ticks )
1042 {
1043  uint32_t startTime;
1044  volatile uint32_t now;
1045 
1046  if ( ticks ) {
1047  startTime = RTC_COUNTERGET();
1048  do {
1049  now = RTC_COUNTERGET();
1050  } while ( TIMEDIFF( now, startTime ) < ticks );
1051  }
1052 }
1053 
1054 static void executeTimerCallbacks( void )
1055 {
1056  int i;
1057 
1058  for ( i = 0; i < EMDRV_RTCDRV_NUM_TIMERS; i++ ) {
1059  if ( timer[ i ].doCallback ) {
1060  timer[ i ].callback( i, timer[ i ].user );
1061  }
1062  }
1063 }
1064 
1065 static void rescheduleRtc( uint32_t rtcCnt )
1066 {
1067  int i;
1068  uint64_t min = UINT64_MAX;
1069 
1070  // Find the timer with shortest timeout.
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;
1075  }
1076  }
1077 
1078  rtcRunning = false;
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;
1084  } else
1085 #endif
1086  {
1087  lastStart = rtcCnt;
1088  }
1089  RTC_INTCLEAR( RTC_COMP_INT );
1090 
1091  RTC_COMPARESET( rtcCnt + min );
1092 
1093 #if defined( EMODE_DYNAMIC )
1094  // When RTC is running, we can not allow EM3 or EM4.
1095  if ( sleepBlocked == false ) {
1096  sleepBlocked = true;
1098  }
1099 #endif
1100 
1101  rtcRunning = true;
1102 
1103  // Reenable compare IRQ.
1104  RTC_INTENABLE( RTC_COMP_INT );
1105  }
1106 }
1108 
1109 /******** THE REST OF THE FILE IS DOCUMENTATION ONLY !**********************/
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.
Definition: em_cmu.c:2521
uint64_t RTCDRV_SecsToTicks(uint32_t secs)
Convert from seconds to RTC/RTCC ticks.
Definition: rtcdriver.c:868
void SLEEP_SleepBlockEnd(SLEEP_EnergyMode_t eMode)
End sleep block in the requested energy mode.
Definition: sleep.c:295
#define CORE_DECLARE_IRQ_STATE
Definition: em_core.h:85
uint32_t RTCDRV_TimerID_t
Timer ID.
Definition: rtcdriver.h:47
Periodic timer.
Definition: rtcdriver.h:68
#define ECODE_EMDRV_RTCDRV_OK
Success return value.
Definition: rtcdriver.h:39
Oneshot timer.
Definition: rtcdriver.h:67
#define ECODE_EMDRV_RTCDRV_TIMER_NOT_RUNNING
Timer is not running.
Definition: rtcdriver.h:44
Ecode_t RTCDRV_AllocateTimer(RTCDRV_TimerID_t *id)
Allocate timer.
Definition: rtcdriver.c:231
Ecode_t RTCDRV_SetWallClock(uint32_t secs)
Set wallclock time.
Definition: rtcdriver.c:835
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.
Definition: sleep.c:249
Ecode_t RTCDRV_TimeRemaining(RTCDRV_TimerID_t id, uint32_t *timeRemaining)
Get time left before a given timer expires.
Definition: rtcdriver.c:711
#define ECODE_EMDRV_RTCDRV_PARAM_ERROR
Illegal input parameter.
Definition: rtcdriver.h:43
General purpose utilities.
RTCDRV timer API definition.
RTCDRV_TimerType_t
Timer type enumerator.
Definition: rtcdriver.h:66
#define ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID
Illegal timer id.
Definition: rtcdriver.h:41
Ecode_t RTCDRV_StopTimer(RTCDRV_TimerID_t id)
Stop a given timer.
Definition: rtcdriver.c:674
Ecode_t RTCDRV_Init(void)
Initialize RTCDRV driver.
Definition: rtcdriver.c:324
#define CORE_ENTER_ATOMIC()
Definition: em_core.h:138
#define ECODE_EMDRV_RTCDRV_ALL_TIMERS_USED
No timers available.
Definition: rtcdriver.h:40
uint32_t RTCDRV_GetWallClockTicks32(void)
Get wallclock tick count as a 32bit value. At 4 ticks per millisecond, overflow occurs after approxim...
Definition: rtcdriver.c:783
uint32_t RTCDRV_GetWallClock(void)
Get wallclock time.
Definition: rtcdriver.c:767
#define CORE_ATOMIC_SECTION(yourcode)
Definition: em_core.h:126
uint32_t RTCDRV_TicksToMsec(uint64_t ticks)
Convert from RTC/RTCC ticks to milliseconds.
Definition: rtcdriver.c:884
uint64_t RTCDRV_GetWallClockTicks64(void)
Get wallclock tick count as a 64 bit value. This will never overflow.
Definition: rtcdriver.c:810
uint64_t RTCDRV_MsecsToTicks(uint32_t ms)
Convert from milliseconds to RTC/RTCC ticks.
Definition: rtcdriver.c:852
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.
Definition: em_cmu.h:1311
Ecode_t RTCDRV_Delay(uint32_t ms)
Millisecond delay function.
Definition: rtcdriver.c:270
Ecode_t RTCDRV_FreeTimer(RTCDRV_TimerID_t id)
Free timer.
Definition: rtcdriver.c:298
uint32_t Ecode_t
Typedef for API function error code return values.
Definition: ecode.h:51
void RTC_Init(const RTC_Init_TypeDef *init)
Initialize RTC.
Definition: em_rtc.c:305
Core interrupt handling API.
void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
Enable/disable a clock.
Definition: em_cmu.c:1453
#define ECODE_EMDRV_RTCDRV_TIMER_NOT_ALLOCATED
Timer is not allocated.
Definition: rtcdriver.h:42
#define CORE_EXIT_ATOMIC()
Definition: em_core.h:142
Ecode_t RTCDRV_DeInit(void)
Deinitialize RTCDRV driver.
Definition: rtcdriver.c:417
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.
Definition: rtcdriver.h:63
void RTC_Enable(bool enable)
Enable/disable RTC.
Definition: em_rtc.c:217
Ecode_t RTCDRV_StartTimer(RTCDRV_TimerID_t id, RTCDRV_TimerType_t type, uint32_t timeout, RTCDRV_Callback_t callback, void *user)
Start a timer.
Definition: rtcdriver.c:515
#define SL_MIN(a, b)
Macro for getting minimum value. No sideeffects, a and b are evaluated once only. ...
Definition: em_common.h:137
Ecode_t RTCDRV_IsRunning(RTCDRV_TimerID_t id, bool *isRunning)
Check if a given timer is running.
Definition: rtcdriver.c:468
uint32_t RTCDRV_TicksToSec(uint64_t ticks)
Convert from RTC/RTCC ticks to seconds.
Definition: rtcdriver.c:900
void CMU_ClockDivSet(CMU_Clock_TypeDef clock, CMU_ClkDiv_TypeDef div)
Set clock divisor/prescaler.
Definition: em_cmu.c:1244
Energy Modes management driver.