void lp_ticker_set_interrupt(timestamp_t timestamp) { uint64_t timestamp_ticks; uint64_t current_ticks = RTCC_CounterGet(); timestamp_t current_time = ((uint64_t)(current_ticks * 1000000) / (LOW_ENERGY_CLOCK_FREQUENCY / RTC_CLOCKDIV_INT)); /* Initialize RTC */ lp_ticker_init(); /* calculate offset value */ timestamp_t offset = timestamp - current_time; if(offset > 0xEFFFFFFF) offset = 100; /* map offset to RTC value */ // ticks = offset * RTC frequency div 1000000 timestamp_ticks = ((uint64_t)offset * (LOW_ENERGY_CLOCK_FREQUENCY / RTC_CLOCKDIV_INT)) / 1000000; // checking the rounding. If timeout is wanted between RTCC ticks, irq should be configured to // trigger in the latter RTCC-tick. Otherwise ticker-api fails to send timer event to its client if(((timestamp_ticks * 1000000) / (LOW_ENERGY_CLOCK_FREQUENCY / RTC_CLOCKDIV_INT)) < offset){ timestamp_ticks++; } timestamp_ticks += current_ticks; /* RTCC has 32 bit resolution */ timestamp_ticks &= 0xFFFFFFFF; /* check for RTCC limitation */ if((timestamp_ticks - RTCC_CounterGet()) >= 0x80000000) timestamp_ticks = RTCC_CounterGet() + 2; /* init channel */ RTCC_CCChConf_TypeDef ccchConf = RTCC_CH_INIT_COMPARE_DEFAULT; RTCC_ChannelInit(0,&ccchConf); /* Set callback */ RTCC_ChannelCCVSet(0, (uint32_t)timestamp_ticks); RTCC_IntEnable(RTCC_IF_CC0); }
timestamp_t lp_ticker_read() { lp_ticker_init(); uint64_t ticks_temp; uint64_t ticks = RTCC_CounterGet(); /* ticks = counter tick value * timestamp = value in microseconds * timestamp = ticks * 1.000.000 / RTC frequency */ ticks_temp = (ticks * 1000000) / (LOW_ENERGY_CLOCK_FREQUENCY / RTC_CLOCKDIV_INT); return (timestamp_t) (ticks_temp & 0xFFFFFFFF); }
void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) { uint32_t ulReloadValue, ulCompleteTickPeriods, ulCountAfterSleep; eSleepModeStatus eSleepAction; TickType_t xModifiableIdleTime; /* THIS FUNCTION IS CALLED WITH THE SCHEDULER SUSPENDED. */ /* Make sure the RTC reload value does not overflow the counter. */ if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ) { xExpectedIdleTime = xMaximumPossibleSuppressedTicks; } /* Calculate the reload value required to wait xExpectedIdleTime tick periods. */ ulReloadValue = ulReloadValueForOneTick * xExpectedIdleTime; if( ulReloadValue > ulStoppedTimerCompensation ) { /* Compensate for the fact that the RTC is going to be stopped momentarily. */ ulReloadValue -= ulStoppedTimerCompensation; } /* Stop the RTC momentarily. The time the RTC 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. */ RTCC_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(); __asm volatile( "dsb" ); __asm volatile( "isb" ); /* 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. */ ulTickFlag = pdFALSE; /* If a context switch is pending then abandon the low power entry as the context switch might have been pended by an external interrupt that requires processing. */ eSleepAction = eTaskConfirmSleepModeStatus(); if( eSleepAction == eAbortSleep ) { /* Restart tick and continue counting to complete the current time slice. */ RTCC_Enable( true ); /* Re-enable interrupts - see comments above the RTCC_Enable() call above. */ INT_Enable(); } else { RTCC_ChannelCCVSet( lpRTCC_CHANNEL, ulReloadValue ); /* Restart the RTC. */ RTCC_Enable( true ); /* Allow the application to define some pre-sleep processing. */ xModifiableIdleTime = xExpectedIdleTime; configPRE_SLEEP_PROCESSING( xModifiableIdleTime ); /* xExpectedIdleTime being set to 0 by configPRE_SLEEP_PROCESSING() means the application defined code has already executed the WAIT instruction. */ if( xModifiableIdleTime > 0 ) { __asm volatile( "dsb" ); SLEEP_Sleep(); __asm volatile( "isb" ); } /* Allow the application to define some post sleep processing. */ configPOST_SLEEP_PROCESSING( xModifiableIdleTime ); /* Stop RTC. 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. */ RTCC_Enable( false ); ulCountAfterSleep = RTCC_CounterGet(); /* Re-enable interrupts - see comments above the INT_Enable() call above. */ INT_Enable(); __asm volatile( "dsb" ); __asm volatile( "isb" ); if( ulTickFlag != pdFALSE ) { /* The tick interrupt has already executed, although because this function is called with the scheduler suspended the actual tick processing will not occur until after this function has exited. 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 sleeping. The actual stepping of the tick appears later in this function. */ ulCompleteTickPeriods = xExpectedIdleTime - 1UL; /* The interrupt should have reset the CCV value. */ configASSERT( RTCC_ChannelCCVGet( lpRTCC_CHANNEL ) == ulReloadValueForOneTick ); } else { /* Something other than the tick interrupt ended the sleep. How many complete tick periods passed while the processor was sleeping? */ ulCompleteTickPeriods = ulCountAfterSleep / ulReloadValueForOneTick; /* The next interrupt is configured to occur at whatever fraction of the current tick period remains by setting the reload value back to that required for one tick, and truncating the count to remove the counts that are greater than the reload value. */ RTCC_ChannelCCVSet( lpRTCC_CHANNEL, ulReloadValueForOneTick ); ulCountAfterSleep %= ulReloadValueForOneTick; RTCC_CounterSet( ulCountAfterSleep ); } /* Restart the RTC so it runs up to the alarm value. The alarm value will get set to the value required to generate exactly one tick period the next time the RTC interrupt executes. */ RTCC_Enable( true ); /* Wind the tick forward by the number of tick periods that the CPU remained in a low power state. */ vTaskStepTick( ulCompleteTickPeriods ); }