__attribute__((weak)) void vPortSuppressTicksAndSleep(TickType_t xExpectedIdleTime) { unsigned long ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickIncrements; TickCounter_t tmp; /* because of how we get the current tick counter */ bool tickISRfired; /* Make sure the tick timer reload value does not overflow the counter. */ if(xExpectedIdleTime>xMaximumPossibleSuppressedTicks) { xExpectedIdleTime = xMaximumPossibleSuppressedTicks; } /* Stop the tick timer momentarily. The time the counter 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. */ DISABLE_TICK_COUNTER(); /* 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. */ GET_TICK_CURRENT_VAL(&tmp); ulReloadValue = tmp+(UL_TIMER_COUNTS_FOR_ONE_TICK*(xExpectedIdleTime-1UL)); if (ulReloadValue>ulStoppedTimerCompensation) { ulReloadValue -= ulStoppedTimerCompensation; } /* Enter a critical section but don't use the taskENTER_CRITICAL() * method as that will mask interrupts that should exit sleep mode. */ TICKLESS_DISABLE_INTERRUPTS(); /* 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) { ENABLE_TICK_COUNTER(); /* Restart SysTick. */ TICKLESS_ENABLE_INTERRUPTS(); } else { #if configUSE_LP_TIMER DisableDevice(); ClearInterruptFlag(); WriteCompareReg(xExpectedIdleTime-1); EnableDevice(); /* start timer */ #else SET_TICK_DURATION(ulReloadValue); /* Set the new reload value. */ RESET_TICK_COUNTER_VAL(); /* Reset the counter. */ ENABLE_TICK_COUNTER(); /* Restart tick timer. */ TICK_INTERRUPT_FLAG_RESET(); /* reset flag so we know later if it has fired */ #endif /* 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. */ /* CPU *HAS TO WAIT* in the sequence below for an interrupt. If vOnPreSleepProcessing() is not used, a default implementation is provided */ /* default wait/sleep code */ __asm volatile("dsb"); __asm volatile("wfi"); __asm volatile("isb"); /* ---------------------------------------------------------------------------- * Here the CPU *HAS TO BE* low power mode, waiting to wake up by an interrupt * ----------------------------------------------------------------------------*/ /* Stop tick counter. Again, the time the tick counter 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. */ tickISRfired = TICK_INTERRUPT_HAS_FIRED(); /* need to check Interrupt flag here, as might be modified below */ DISABLE_TICK_COUNTER(); TICKLESS_ENABLE_INTERRUPTS();/* Re-enable interrupts */ if (tickISRfired) { /* The tick interrupt has already executed, and the timer * count reloaded with the modulo/match value. * Reset the counter register with whatever remains of * this tick period. */ GET_TICK_CURRENT_VAL(&tmp); #if COUNTS_UP SET_TICK_DURATION((UL_TIMER_COUNTS_FOR_ONE_TICK-1UL)-tmp); #else SET_TICK_DURATION((UL_TIMER_COUNTS_FOR_ONE_TICK-1UL)-(ulReloadValue-tmp)); #endif /* 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 { /* Something other than the tick interrupt ended the sleep. * Work out how long the sleep lasted rounded to complete tick * periods (not the ulReload value which accounted for part ticks). */ GET_TICK_CURRENT_VAL(&tmp); ulCompletedSysTickIncrements = (xExpectedIdleTime*UL_TIMER_COUNTS_FOR_ONE_TICK)-tmp; /* How many complete tick periods passed while the processor was waiting? */ ulCompleteTickPeriods = ulCompletedSysTickIncrements/UL_TIMER_COUNTS_FOR_ONE_TICK; /* The reload value is set to whatever fraction of a single tick period remains. */ SET_TICK_DURATION(((ulCompleteTickPeriods+1)*UL_TIMER_COUNTS_FOR_ONE_TICK)-ulCompletedSysTickIncrements); } /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG again, then set portNVIC_SYSTICK_LOAD_REG back to its standard value. The critical section is used to ensure the tick interrupt can only execute once in the case that the reload register is near zero. */ RESET_TICK_COUNTER_VAL(); portENTER_CRITICAL(); { ENABLE_TICK_COUNTER(); vTaskStepTick(ulCompleteTickPeriods); SET_TICK_DURATION(UL_TIMER_COUNTS_FOR_ONE_TICK-1UL); } portEXIT_CRITICAL(); } }
/* return the tick raw counter value. It is assumed that the counter register has been reset at the last tick time */ portLONG uxGetTickCounterValue(void) { portLONG val; GET_TICK_CURRENT_VAL(&val); return val; }
uint32_t SEGGER_uxGetTickCounterValue(void) { uint32_t val; GET_TICK_CURRENT_VAL(&val); return val; }