/**************************************************************************//** * @brief vPortSetupTimerInterrupt * 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; 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. -1 is used because this code will execute part way * through one of the tick periods, and the fraction of a tick period is * accounted for later. */ ulReloadValue = (ulTimerReloadValueForOneTick * (xExpectedIdleTime )); if (ulReloadValue > ulStoppedTimerCompensation) { ulReloadValue -= ulStoppedTimerCompensation; } /* Stop the SysTick momentarily. 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. */ /* Stop the RTC clock*/ BURTC_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) { BURTC_Enable(true); /* Re-enable interrupts */ INT_Enable(); } else { /* Set the new reload value. */ ulReloadValue -= BURTC_CounterGet(); BURTC_CompareSet(0, ulReloadValue); /* Restart the counter*/ BURTC_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. */ BURTC_Enable(false); /* Re-enable interrupts - see comments above __disable_interrupt() * call above. */ INT_Enable(); if (intTickFlag != false) { /* The tick interrupt has already executed, * Reset the alarm value with whatever remains of this tick period. */ BURTC_CompareSet(0, TIMER_CAPACITY & (ulTimerReloadValueForOneTick - BURTC_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 = BURTC_CounterGet() / ulTimerReloadValueForOneTick; /* The reload value is set to whatever fraction of a single tick * period remains. */ if (ulCompleteTickPeriods == 0) { ulReloadValue = ulTimerReloadValueForOneTick - BURTC_CounterGet(); } else { ulReloadValue = BURTC_CounterGet() - (ulCompleteTickPeriods * ulTimerReloadValueForOneTick); } BURTC_CompareSet(0, ulReloadValue); } /* Restart the RTCounter*/ BURTC_CounterReset(); /* The tick forward by the number of tick periods that * remained in a low power state. */ vTaskStepTick(ulCompleteTickPeriods); } }
/**************************************************************************//** * @brief vApplicationIdleHook * Override the default definition of vApplicationIdleHook() *****************************************************************************/ void vApplicationIdleHook(void) { SLEEP_Sleep(); }
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 ); }