/**************************************************************************//**
 * @brief RTC_IRQHandler
 * Interrupt Service Routine for RTC which is used as system tick counter in EM2
 *****************************************************************************/
void RTC_IRQHandler(void)
{
  /* If using preemption, also force a context switch. */
#if (configUSE_PREEMPTION == 1)
  port_NVIC_INT_CTRL_REG = port_NVIC_PENDSVSET_BIT;
#endif /* (configUSE_PREEMPTION == 1) */
  /* Set RTC interrupt to one system tick period*/
  RTC_Enable(false);
  RTC_CompareSet(0, ulTimerReloadValueForOneTick);
  /* Restart the counter */
#if (configUSE_TICKLESS_IDLE == 1)
  /* Set flag that interrupt was made*/
  intTickFlag = true;
#endif /* (configUSE_TICKLESS_IDLE == 1) */

  /* Critical section which protect incrementing the tick*/
  ( void ) portSET_INTERRUPT_MASK_FROM_ISR();
  {
    xTaskIncrementTick();
  }
  portCLEAR_INTERRUPT_MASK_FROM_ISR(0);
  /* Clear interrupt */
  RTC_IntClear(_RTC_IFC_MASK);
  RTC_CounterReset();
}
Ejemplo n.º 2
0
/*---------------------------------------------------------------------------*/
void RTC_IRQHandler(void)
{
	// Find reason of IRQ

	if(RTC_IntGet() & RTC_IF_COMP0)
	{
      // Update second counters
      //_u32_seconds_since_epoch += DAY_VALUE_IN_SEC;
      //_u32_uptime += DAY_VALUE_IN_SEC;

      // Update alarm (alarm or second values may be updated)
	  // Get about 100us to take into account Interrupt scheduling time
      //SI32_RTC_0->ALARM0.U32 = (_u32_alarm0_secvalue * _rtc_second) - 2;

	  // Reset Counter
	  RTC_CounterReset();
	}
	else if(RTC_IntGet() & RTC_IF_COMP1)
	{
		if(alarm_callback != NULL) alarm_callback();
		// Disable handler
		alarm_callback = NULL;
	}
	else
	{
		printf("%s: unknown reason for RTC interrupt\r\n",__func__);
	}

	// Clear interrupts
	RTC_IntClear(_RTC_IF_MASK);
}
/**************************************************************************//**
 * @brief Enables LFACLK and selects LFXO as clock source for RTC
 *        Sets up the RTC to generate an interrupt every second.
 *****************************************************************************/
static void rtcSetup(unsigned int frequency)
{
  RTC_Init_TypeDef rtcInit = RTC_INIT_DEFAULT;

  palClockSetup(cmuClock_LFA);

  /* Set the prescaler. */
  CMU_ClockDivSet( cmuClock_RTC, cmuClkDiv_2 );
  
  /* Enable RTC clock */
  CMU_ClockEnable(cmuClock_RTC, true);

  /* Initialize RTC */
  rtcInit.enable   = false;  /* Do not start RTC after initialization is complete. */
  rtcInit.debugRun = false;  /* Halt RTC when debugging. */
  rtcInit.comp0Top = true;   /* Wrap around on COMP0 match. */

  RTC_Init(&rtcInit);

  /* Interrupt at given frequency. */
  RTC_CompareSet(0, ((CMU_ClockFreqGet(cmuClock_RTC) / frequency) - 1) & _RTC_COMP0_MASK );

#ifndef INCLUDE_PAL_GPIO_PIN_AUTO_TOGGLE_HW_ONLY
  /* Enable interrupt */
  NVIC_EnableIRQ(RTC_IRQn);
  RTC_IntEnable(RTC_IEN_COMP0);
#endif
  RTC_CounterReset();
  /* Start Counter */
  RTC_Enable(true);
}
Ejemplo n.º 4
0
// Stores the hours/mins for clock time, start time, or stop time
void set_clock_time(int index, uint16_t hours, uint16_t minutes)
{
	// Set the time clock
	if (index == 0)
	{
		// Midnight is time zero
		RTC_CounterReset();
		// 3600 seconds per hour, 60 seconds per minute
		RTC->CNT = hours * 3600 + minutes * 60;
	}
	else if (index == 1)
	{
		// Add 1 second so that RTC interrupt source is clear,
		// and not to confuse with the clock minute updates
		time_keeper.timer_start_seconds = hours * 3600 + minutes * 60 + 1;

		// Set up the RTC to trigger a start event
		RTC_CompareSet(0, time_keeper.timer_start_seconds);

		// Save for next program event
		start_hours = hours;
		start_minutes = minutes;
	}
	else if (index == 2)
	{
		// Add 1 second so that RTC interrupt source is clear,
		// and not to confuse with the clock minute updates
		time_keeper.timer_stop_seconds = hours * 3600 + minutes * 60 + 1;

		// Save for next program event
		stop_hours = hours;
		stop_minutes = minutes;
	}
}
Ejemplo n.º 5
0
void os_idle_demon(void)
{
  RTC_Init_TypeDef init;
  unsigned int sleep;

  /* The idle demon is a system thread, running when no other thread is      */
  /* ready to run.                                                           */

  /* Enable system clock for RTC */

  /* LFXO setup */
  /* Use 70% boost */
  CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_LFXOBOOST_MASK) | CMU_CTRL_LFXOBOOST_70PCENT;

  /* Ensure LE modules are accessible */
  CMU_ClockEnable(cmuClock_CORELE, true);

  /* Enable osc as LFACLK in CMU (will also enable oscillator if not enabled) */
  CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO);

  /* Use a 32 division prescaler to reduce power consumption. */
  CMU_ClockDivSet(cmuClock_RTC, cmuClkDiv_32);

  /* Enable clock to RTC module */
  CMU_ClockEnable(cmuClock_RTC, true);

  init.enable   = false;
  init.debugRun = false;
  init.comp0Top = false; /* Count to max value before wrapping */

  RTC_Init(&init);

  /* Disable interrupt generation from RTC0 */
  RTC_IntDisable(_RTC_IF_MASK);

  /* Enable interrupts */
  NVIC_ClearPendingIRQ(RTC_IRQn);
  NVIC_EnableIRQ(RTC_IRQn);

  for (;;)
  {
    /* os_suspend stops scheduler and returns time to next event in OS_TICK units */
    sleep = os_suspend();
    if (sleep)
    {
      RTC_CompareSet(0, sleep - 1);
      RTC_IntClear(RTC_IFC_COMP0);
      RTC_IntEnable(RTC_IF_COMP0);
      RTC_CounterReset();
      /* Enter EM2 low power mode - could be replaced with EM1 if required */
      EMU_EnterEM2(true);
      /* get information how long we were in sleep */
      sleep = RTC_CounterGet();
      RTC_Enable(false);
    };
    /* resume scheduler providing information how long MCU was sleeping */
    os_resume(sleep);
  }
}
error_t hw_timer_counter_reset(hwtimer_id_t timer_id)
{
	if(timer_id >= HWTIMER_NUM)
		return ESIZE;
	if(!timer_inited)
		return EOFF;

	start_atomic();
		RTC_IntDisable(RTC_IEN_COMP0 | RTC_IEN_COMP1);
		RTC_IntClear(RTC_IEN_COMP0 | RTC_IEN_COMP1);
		RTC_CounterReset();
		RTC_IntEnable(RTC_IEN_COMP0);
	end_atomic();

}
/**************************************************************************//**
 * @brief Enables LFACLK and selects LFXO as clock source for RTC.
 *        Sets up the RTC to count at 1024 Hz.
 *        The counter should not be cleared on a compare match and keep running.
 *        Interrupts should be cleared and enabled.
 *        The counter should run.
 *****************************************************************************/
error_t hw_timer_init(hwtimer_id_t timer_id, uint8_t frequency, timer_callback_t compare_callback, timer_callback_t overflow_callback)
{
    if(timer_id >= HWTIMER_NUM)
    	return ESIZE;
    if(timer_inited)
    	return EALREADY;
    if(frequency != HWTIMER_FREQ_1MS && frequency != HWTIMER_FREQ_32K)
    	return EINVAL;
	
    start_atomic();
		compare_f = compare_callback;
		overflow_f = overflow_callback;
		timer_inited = true;

		/* Configuring clocks in the Clock Management Unit (CMU) */
		startLfxoForRtc(frequency);

		RTC_Init_TypeDef rtcInit = RTC_INIT_DEFAULT;
		rtcInit.enable   = false;   /* Don't enable RTC after init has run */
		rtcInit.comp0Top = true;   /* Clear counter on compare 0 match: cmp 0 is used to limit the value of the rtc to 0xffff */
		rtcInit.debugRun = false;   /* Counter shall not keep running during debug halt. */


		/* Initialize the RTC */
		RTC_Init(&rtcInit);

		//disable all rtc interrupts while we're still configuring
		RTC_IntDisable(RTC_IEN_OF | RTC_IEN_COMP0 | RTC_IEN_COMP1);
		RTC_IntClear(RTC_IFC_OF | RTC_IFC_COMP0 | RTC_IFC_COMP1);
		//Set maximum value for the RTC
		RTC_CompareSet( 0, 0x0000FFFF );
		RTC_CounterReset();

		RTC_IntEnable(RTC_IEN_COMP0);

		NVIC_EnableIRQ(RTC_IRQn);
		RTC_Enable(true);
    end_atomic();
    return SUCCESS;
}
/**************************************************************************//**
 * @brief vPortSuppressTicksAndSleep
 * Override the default definition of vPortSuppressTicksAndSleep() that is weakly
 * defined in the FreeRTOS Cortex-M3 port layer layer
 *****************************************************************************/
void vPortSuppressTicksAndSleep(portTickType xExpectedIdleTime)
{
  unsigned long ulReloadValue, ulCompleteTickPeriods;
  unsigned int ulRemainingCounter;

  portTickType  xModifiableIdleTime;
  /* Make sure the SysTick reload value does not overflow the counter. */
  if (xExpectedIdleTime > xMaximumPossibleSuppressedTicks)
  {
    xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
  }

  /* Calculate the reload value required to wait xExpectedIdleTime
   * tick periods.
  */
  ulReloadValue = (ulTimerReloadValueForOneTick * (xExpectedIdleTime ));
  if (ulReloadValue > ulStoppedTimerCompensation)
  {
    ulReloadValue -= ulStoppedTimerCompensation;
  }

  /* Stop the System Tick momentarily.  The time the System Tick is stopped for
   * is accounted for as best it can be, but using the tickless mode will
   * inevitably result in some tiny drift of the time maintained by the
   * kernel with respect to calendar time. */

  /* Stop the RTC clock*/
  RTC_Enable(false);
/* Enter a critical section but don't use the taskENTER_CRITICAL()
 * method as that will mask interrupts that should exit sleep mode. */
  INT_Disable();

  /* The tick flag is set to false before sleeping.  If it is true when sleep
   * mode is exited then sleep mode was probably exited because the tick was
   * suppressed for the entire xExpectedIdleTime period. */
  intTickFlag = false;
  /* If a context switch is pending or a task is waiting for the scheduler
   * to be unsuspended then abandon the low power entry. */
  if (eTaskConfirmSleepModeStatus() == eAbortSleep)
  {
    RTC_Enable(true);
    /* Re-enable interrupts - see comments above __disable_interrupt()
     * call above. */
    INT_Enable();
  }
  else
  {
    /* Set the new reload value. */
    ulReloadValue -= RTC_CounterGet();
    RTC_CompareSet(0, ulReloadValue);
    /* Restart the counter*/
    RTC_CounterReset();
    /* Sleep until something happens.  configPRE_SLEEP_PROCESSING() can
     * set its parameter to 0 to indicate that its implementation contains
     * its own wait for interrupt or wait for event instruction, and so wfi
     * should not be executed again.  However, the original expected idle
     * time variable must remain unmodified, so a copy is taken. */
    xModifiableIdleTime = xExpectedIdleTime;
    configPRE_SLEEP_PROCESSING(xModifiableIdleTime);
    if (xModifiableIdleTime > 0)
    {
      SLEEP_Sleep();
      __DSB();
      __ISB();
    }
    configPOST_SLEEP_PROCESSING(xExpectedIdleTime);
    /* Stop SysTick.  Again, the time the SysTick is stopped for is
     * accounted for as best it can be, but using the tickless mode will
     * inevitably result in some tiny drift of the time maintained by the
     * kernel with respect to calendar time. */

    /* Store current counter value */
    ulRemainingCounter = RTC_CounterGet();
    /* Stop the RTC clock*/
    RTC_Enable(false);
    /* Re-enable interrupts */
    INT_Enable();
    if (intTickFlag != false)
    {
      /* The tick interrupt has already executed,
       * Reset the alarm value with whatever remains of this tick period. */
      RTC_CompareSet(0, TIMER_CAPACITY & (ulTimerReloadValueForOneTick - RTC_CounterGet()));

      /* The tick interrupt handler will already have pended the tick
       * processing in the kernel.  As the pending tick will be
       * processed as soon as this function exits, the tick value
       * maintained by the tick is stepped forward by one less than the
       * time spent waiting. */
      ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
    }
    else
    {
      /* Some other interrupt than system tick ended the sleep.
       * Calculate how many tick periods passed while the processor
       * was waiting */
      ulCompleteTickPeriods = ulRemainingCounter / ulTimerReloadValueForOneTick;

      /* The reload value is set to whatever fraction of a single tick
       * period remains. */
      if (ulCompleteTickPeriods == 0)
      {
        ulReloadValue = ulTimerReloadValueForOneTick - ulRemainingCounter;
      }
      else
      {
        ulReloadValue = ulRemainingCounter - (ulCompleteTickPeriods * ulTimerReloadValueForOneTick);
      }
      RTC_CompareSet(0, ulReloadValue);
    }
    /* Restart the RTCounter */
    RTC_CounterReset();
    /* The tick forward by the number of tick periods that
     * remained in a low power state. */
    vTaskStepTick(ulCompleteTickPeriods);
  }
}
const hwtimer_info_t* hw_timer_get_info(hwtimer_id_t timer_id)
{
    if(timer_id >= HWTIMER_NUM)
      return NULL;

    static const hwtimer_info_t timer_info = {
      .min_delay_ticks = 0,
    };

    return &timer_info;
}

hwtimer_tick_t hw_timer_getvalue(hwtimer_id_t timer_id)
{
	if(timer_id >= HWTIMER_NUM || (!timer_inited))
		return 0;
	else
	{
		uint32_t value =(uint16_t)(RTC->CNT & 0xFFFF);
		return value;
	}
}

error_t hw_timer_schedule(hwtimer_id_t timer_id, hwtimer_tick_t tick )
{
	if(timer_id >= HWTIMER_NUM)
		return ESIZE;
	if(!timer_inited)
		return EOFF;

	start_atomic();
	   RTC_IntDisable(RTC_IEN_COMP1);
	   RTC_CompareSet( 1, tick );
	   RTC_IntClear(RTC_IEN_COMP1);
	   RTC_IntEnable(RTC_IEN_COMP1);
	end_atomic();
}

error_t hw_timer_cancel(hwtimer_id_t timer_id)
{
	if(timer_id >= HWTIMER_NUM)
		return ESIZE;
	if(!timer_inited)
		return EOFF;

	start_atomic();
	   RTC_IntDisable(RTC_IEN_COMP1);
	   RTC_IntClear(RTC_IEN_COMP1);
	end_atomic();
}

error_t hw_timer_counter_reset(hwtimer_id_t timer_id)
{
	if(timer_id >= HWTIMER_NUM)
		return ESIZE;
	if(!timer_inited)
		return EOFF;

	start_atomic();
		RTC_IntDisable(RTC_IEN_COMP0 | RTC_IEN_COMP1);
		RTC_IntClear(RTC_IEN_COMP0 | RTC_IEN_COMP1);
		RTC_CounterReset();
		RTC_IntEnable(RTC_IEN_COMP0);
	end_atomic();

}

bool hw_timer_is_overflow_pending(hwtimer_id_t timer_id)
{
    if(timer_id >= HWTIMER_NUM)
	return false;
    start_atomic();
	//COMP0 is used to limit thc RTC to 16 bits -> use this one to check
	bool is_pending = !!((RTC_IntGet() & RTC->IEN) & RTC_IFS_COMP0);
    end_atomic();
    return is_pending;	
}
bool hw_timer_is_interrupt_pending(hwtimer_id_t timer_id)
{
    if(timer_id >= HWTIMER_NUM)
	return false;

    start_atomic();
	bool is_pending = !!((RTC_IntGet() & RTC->IEN) & RTC_IFS_COMP1);
    end_atomic();
    return is_pending;	
}



INT_HANDLER(RTC_IRQHandler)
{
	//retrieve flags. We 'OR' this with the enabled interrupts
	//since the COMP1 flag may be set if it wasn't used before (compare register == 0 -> ifs flag set regardless of whether interrupt is enabled)
	//by AND ing with the IEN we make sure we only consider the flags of the ENABLED interrupts
	uint32_t flags = (RTC_IntGet() & RTC->IEN);
	RTC_IntClear(RTC_IFC_OF | RTC_IFC_COMP0 | RTC_IFC_COMP1);

	//evaluate flags to see which one(s) fired:
	if((flags & RTC_IFS_COMP0) && (overflow_f != 0x0))
		overflow_f();
	if((flags & RTC_IFS_COMP1))
	{
		RTC_IntDisable(RTC_IEN_COMP1);
		if(compare_f != 0x0)
			compare_f();
	}
}