示例#1
0
void RTCC_IRQHandler(void)
#endif
{
  uint32_t flags, timeElapsed, cnt, timeToNextTimerCompletion;

  INT_Disable();

  // CNT will normally be COMP0+1 at this point,
  // unless IRQ latency exceeded one tick period.

  flags = RTC_INTGET();

  if ( flags & RTC_COMP_INT ) {

    // Stop timer system by disabling the compare IRQ.
    // Update all timers with the time elapsed, call callbacks if needed,
    // then find the timer with the shortest timeout (if any at all) and
    // reenable the compare IRQ if needed.

    inTimerIRQ = true;

    cnt = RTC_COUNTERGET();

    // This loop is repeated if CNT is incremented while processing.
    do {

      RTC_INTDISABLE( RTC_COMP_INT );

      timeElapsed = TIMEDIFF( cnt, lastStart );

      // Update all timers with elapsed time.
      checkAllTimers( timeElapsed );

      // Execute timer callbacks.
      executeTimerCallbacks();

      // Restart RTC according to next timeout.
      rescheduleRtc( cnt );

      cnt = RTC_COUNTERGET();
      timeElapsed = TIMEDIFF( cnt, lastStart );
      timeToNextTimerCompletion = TIMEDIFF( RTC_COMPAREGET(), lastStart );
      /* If the counter has passed the COMP(ARE) register value since we
         checked the timers, then we should recheck the timers and reschedule
         again. */
    }
    while ( rtcRunning && (timeElapsed > timeToNextTimerCompletion));
    inTimerIRQ = false;
  }

#if defined( EMDRV_RTCDRV_WALLCLOCK_CONFIG )
  if ( flags & RTC_OF_INT )
  {
    RTC_INTCLEAR( RTC_OF_INT );
    wallClockOverflowCnt++;
  }
#endif

  INT_Enable();
}
示例#2
0
static void delayTicks( uint32_t ticks )
{
  uint32_t startTime;
  volatile uint32_t now;

  if ( ticks ) {
    startTime = RTC_COUNTERGET();
    do {
      now = RTC_COUNTERGET();
    } while ( TIMEDIFF( now, startTime ) < ticks );
  }
}
示例#3
0
/***************************************************************************//**
 * @brief
 *    Set wallclock time.
 *
 * @param[in] secs Value to set (seconds).
 *
 * @return
 *    @ref ECODE_EMDRV_RTCDRV_OK
 ******************************************************************************/
Ecode_t RTCDRV_SetWallClock( uint32_t secs )
{
  INT_Disable();
  wallClockTime     = secs;
  wallClockInitTime = RTC_COUNTERGET();
  INT_Enable();

  return ECODE_EMDRV_RTCDRV_OK;
}
示例#4
0
/***************************************************************************//**
 * @brief
 *    Get wallclock tick count as a 64 bit value. This will never overflow.
 *
 * @return
 *    Wallclock tick counter.
 ******************************************************************************/
uint64_t RTCDRV_GetWallClockTicks64( void )
{
  uint64_t overflows, ticks;

  /* Need to re-read data in case overflow cnt is incremented while we read. */
  do
  {
    overflows = wallClockOverflowCnt;
    ticks     = RTC_COUNTERGET();
  } while ( overflows != wallClockOverflowCnt );

  return ( overflows << RTC_COUNTER_BITS ) + ticks;
}
示例#5
0
/***************************************************************************//**
 * @brief
 *    Get wallclock time.
 *
 * @return
 *    Seconds elapsed since RTCDRV was initialized.
 ******************************************************************************/
uint32_t RTCDRV_GetWallClock( void )
{
  uint64_t tmp;
  uint32_t ticks, wallClock, wallClockStartPoint;

  INT_Disable();
  ticks               = RTC_COUNTERGET();
  wallClock           = wallClockTime;
  wallClockStartPoint = wallClockInitTime;
  INT_Enable();

  tmp = ticks - wallClockStartPoint;
  return wallClock + (uint32_t)TICKS_TO_SEC( tmp );
}
示例#6
0
/***************************************************************************//**
 * @brief
 *    Get time left before a given timer expires.
 *
 * @param[in] id The id of the timer to query.
 *
 * @param[out] timeRemaining Time left expressed in milliseconds.
 *                        Only valid if return status is ECODE_EMDRV_RTCDRV_OK.
 * @return
 *    @ref ECODE_EMDRV_RTCDRV_OK on success.@n
 *    @ref ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID if id has an illegal value. @n
 *    @ref ECODE_EMDRV_RTCDRV_TIMER_NOT_ALLOCATED if the timer is not reserved.@n
 *    @ref ECODE_EMDRV_RTCDRV_TIMER_NOT_RUNNING if the timer is not running.@n
 *    @ref ECODE_EMDRV_RTCDRV_PARAM_ERROR if an invalid timeRemaining pointer
 *         was supplied.
 ******************************************************************************/
Ecode_t RTCDRV_TimeRemaining( RTCDRV_TimerID_t id, uint32_t *timeRemaining )
{
  uint64_t tmp;
  uint32_t timeLeft, currentCnt, lastRtcStart;

  // Check if valid timer ID.
  if ( id >= EMDRV_RTCDRV_NUM_TIMERS ) {
    return ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID;
  }

  // Check pointer validity.
  if ( timeRemaining == NULL ) {
    return ECODE_EMDRV_RTCDRV_PARAM_ERROR;
  }

  INT_Disable();
  // Check if timer is reserved.
  if ( ! timer[ id ].allocated ) {
    INT_Enable();
    return ECODE_EMDRV_RTCDRV_TIMER_NOT_ALLOCATED;
  }

  // Check if timer is running.
  if ( ! timer[ id ].running ) {
    INT_Enable();
    return ECODE_EMDRV_RTCDRV_TIMER_NOT_RUNNING;
  }

  timeLeft     = timer[ id ].remaining;
  currentCnt   = RTC_COUNTERGET();
  lastRtcStart = lastStart;
  INT_Enable();

  // Get number of RTC clock ticks elapsed since last RTC reschedule.
  currentCnt = TIMEDIFF( currentCnt, lastRtcStart );

  if ( currentCnt > timeLeft ) {
    timeLeft = 0;
  } else {
    timeLeft -= currentCnt;
  }

  tmp = TICKS_TO_MSEC( timeLeft );
  *timeRemaining = tmp;

  return ECODE_EMDRV_RTCDRV_OK;
}
示例#7
0
/***************************************************************************//**
 * @brief
 *    Get wallclock tick count as a 32bit value. At 4 ticks per millisecond,
 *    overflow occurs after approximately 12.5 days
 *
 * @return
 *    Wallclock tick counter.
 ******************************************************************************/
uint32_t RTCDRV_GetWallClockTicks32( void )
{
  uint32_t overflows, ticks;

  /* Need to re-read data in case overflow cnt is incremented while we read. */
  do
  {
    overflows = wallClockOverflowCnt;
    ticks     = RTC_COUNTERGET();
  } while ( overflows != wallClockOverflowCnt );

#if ( RTC_COUNTER_BITS < 32 )
  return ( overflows << RTC_COUNTER_BITS ) + ticks;
#else
  return ticks;
#endif
}
示例#8
0
/***************************************************************************//**
 * @brief
 *    Start a timer.
 *
 * @note
 *    It is legal to start an already running timer.
 *
 * @param[in] id The id of the timer to start.
 * @param[in] type Timer type, oneshot or periodic. See @ref RTCDRV_TimerType_t.
 * @param[in] timeout Timeout expressed in milliseconds. If the timeout value
 *            is 0, the callback function will be called immediately and
 *            the timer will not be started.
 * @param[in] callback Function to call on timer expiry. See @ref
 *            RTCDRV_Callback_t. NULL is a legal value.
 * @param[in] user Extra callback function parameter for user application.
 *
 * @return
 *    @ref ECODE_EMDRV_RTCDRV_OK on success.@n
 *    @ref ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID if id has an illegal value.@n
 *    @ref ECODE_EMDRV_RTCDRV_TIMER_NOT_ALLOCATED if the timer is not reserved.
 ******************************************************************************/
Ecode_t RTCDRV_StartTimer(  RTCDRV_TimerID_t id,
                            RTCDRV_TimerType_t type,
                            uint32_t timeout,
                            RTCDRV_Callback_t callback,
                            void *user )
{
  uint32_t timeElapsed, cnt, compVal, loopCnt = 0;
  uint32_t timeToNextTimerCompletion;

  // Check if valid timer ID.
  if ( id >= EMDRV_RTCDRV_NUM_TIMERS ) {
    return ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID;
  }

  INT_Disable();
  if ( ! timer[ id ].allocated ) {
    INT_Enable();
    return ECODE_EMDRV_RTCDRV_TIMER_NOT_ALLOCATED;
  }

  if ( timeout == 0 ) {
    if ( callback != NULL ) {
      callback( id, user );
    }
    INT_Enable();
    return ECODE_EMDRV_RTCDRV_OK;
  }

  cnt = RTC_COUNTERGET();

  timer[ id ].callback  = callback;
  timer[ id ].ticks     = MSEC_TO_TICKS( timeout );
  if (rtcdrvTimerTypePeriodic == type) {
    // Calculate compensation value for periodic timers.
    timer[ id ].periodicCompensationUsec = 1000 * timeout -
      (timer[ id ].ticks * TICK_TIME_USEC);
    timer[ id ].periodicDriftUsec = TICK_TIME_USEC/2;
  }
  else
  {
    // Compensate for the fact that CNT is normally COMP0+1 after a
    // compare match event on some devices.
    timer[ id ].ticks -= RTC_ONESHOT_TICK_ADJUST;
  }
  // Add one tick in order to compensate if RTC is close to an increment event.
  timer[ id ].remaining = timer[ id ].ticks + 1;
  timer[ id ].running   = true;
  timer[ id ].timerType = type;
  timer[ id ].user      = user;

  if ( inTimerIRQ == true ) {
    // Exit now, remaining processing will be done in IRQ handler.
    INT_Enable();
    return ECODE_EMDRV_RTCDRV_OK;
  }

  // StartTimer() may recurse, keep track of recursion level.
  if ( startTimerNestingLevel < UINT32_MAX ) {
    startTimerNestingLevel++;
  }

  if ( rtcRunning == false ) {

#if defined( RTCDRV_USE_RTC )
    lastStart = ( cnt ) & RTC_COUNTER_MASK;
#elif defined( RTCDRV_USE_RTCC )
    lastStart = cnt;
#endif

    RTC_INTCLEAR( RTC_COMP_INT );

    compVal = SL_MIN( timer[ id ].remaining, RTC_CLOSE_TO_MAX_VALUE );
    RTC_COMPARESET( cnt + compVal );

    // Start the timer system by enabling the compare interrupt.
    RTC_INTENABLE( RTC_COMP_INT );

#if defined( EMODE_DYNAMIC )
    // When RTC is running, we can not allow EM3 or EM4.
    if ( sleepBlocked == false ) {
      sleepBlocked = true;
      SLEEP_SleepBlockBegin( sleepEM3 );
    }
#endif

    rtcRunning = true;

  } else {

    // The timer system is running. We must stop, update timers with the time
    // elapsed so far, find the timer with the shortest timeout and then restart.
    // As StartTimer() may be called from the callbacks we only do this
    // processing at the first nesting level.
    if ( startTimerNestingLevel == 1  ) {

      timer[ id ].running = false;
      // This loop is repeated if CNT is incremented while processing.
      do {

        RTC_INTDISABLE( RTC_COMP_INT );

        timeElapsed = TIMEDIFF( cnt, lastStart );
#if defined( RTCDRV_USE_RTC )
        // Compensate for the fact that CNT is normally COMP0+1 after a
        // compare match event.
        if ( timeElapsed == RTC_MAX_VALUE ) {
          timeElapsed = 0;
        }
#endif

        // Update all timers with elapsed time.
        checkAllTimers( timeElapsed );

        // Execute timer callbacks.
        executeTimerCallbacks();

        // Set timer to running only after checkAllTimers() is called once.
        if ( loopCnt == 0 ) {
          timer[ id ].running = true;
        }
        loopCnt++;

        // Restart RTC according to next timeout.
        rescheduleRtc( cnt );

        cnt = RTC_COUNTERGET();
        timeElapsed = TIMEDIFF( cnt, lastStart );
        timeToNextTimerCompletion = TIMEDIFF( RTC_COMPAREGET(), lastStart );

        /* If the counter has passed the COMP(ARE) register value since we
           checked the timers, then we should recheck the timers and reschedule
           again. */
      }
      while ( rtcRunning && (timeElapsed > timeToNextTimerCompletion));
    }
  }

  if ( startTimerNestingLevel > 0 ) {
    startTimerNestingLevel--;
  }

  INT_Enable();
  return ECODE_EMDRV_RTCDRV_OK;
}