3. 实现过程
重写 vPortSetupTimerInterrupt 函数,主要是设置与休眠时间补偿相关的变量,初始化 systick 寄
存器:void vPortSetupTimerInterrupt( void )
{
/* Calculate the constants required to configure the tick interrupt. */
#if( configUSE_TICKLESS_IDLE == 2 )
{
ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ /
configSYSTICK_CLOCK_HZ );
}
#endif /* configUSE_TICKLESS_IDLE */
/* Stop and clear the SysTick. */
portNVIC_SYSTICK_CTRL_REG = 0UL;
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Configure SysTick to interrupt at the requested rate. */
portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT |
portNVIC_SYSTICK_ENABLE_BIT );
}
重写 vPortSuppressTicksAndSleep 函数。 在进入 LPSLEEP 前,会停止 systick,在休眠完成
后,需要补偿系统 tick 值,示例中使用 LPTIM 计时来补偿系统 tick 值。 在进入 LPSLEEP 前先进
行状态检查,只要有以下情况,都不进入低功耗模式:
a) 触摸事件产生: nosleep_**
b) DMA2D busy 状态: isDMAbusy_a()
c) DSI refreshing 状态: displayRefreshing
d) 渲染完成,请求 DSI 刷新: refreshRequested
void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{
uint32_t xMaximumPossibleSuppressedTicks,ulReloadValue, ulCompleteTickPeriods,ulCount;
xMaximumPossibleSuppressedTicks=portMAX_16_BIT_NUMBER * configTICK_RATE_HZ / lptim_CLOCK_HZ;
if(nosleep_** || isDMAbusy_a() || displayRefreshing || refreshRequested) {
if(!isDMAbusy_a() && !displayRefreshing && !refreshRequested) {
if(osKernelSysTick() > nosleep_**_t0 + nosleep_time)
nosleep_** = 0;
}
return;
}
if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ) {
xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
}
portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
HAL_SuspendTick();
ulReloadValue = (lptim_CLOCK_HZ * (xExpectedIdleTime - 1UL)/configTICK_RATE_HZ);
__DSB();
__ISB();
LPTIM_ReloadMatch_flag=pdFALSE;
if( eTaskConfirmSleepModeStatus() == eAbortSleep ) {
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
portNVIC_SYSTICK_LOAD_REG = configCPU_CLOCK_HZ/configTICK_RATE_HZ - 1UL;
HAL_ResumeTick();
} else {
MX_LPTIM1_Init(LPTIM_PRESCALER_DIV2, ulReloadValue);
if( xExpectedIdleTime > 0 ) {
__DSB();
enter_lpsleep();
__ISB();
}
ulCount = HAL_LPTIM_ReadCounter(&Lptim1);
HAL_LPTIM_TimeOut_Stop_IT(&Lptim1);
HAL_ResumeTick();
if( LPTIM_ReloadMatch_flag != pdFALSE ) {
ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} else {
ulCompleteTickPeriods = (ulCount * configTICK_RATE_HZ)/ lptim_CLOCK_HZ;
}
portENTER_CRITICAL();
uwTick += ulCompleteTickPeriods;
vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
portNVIC_SYSTICK_LOAD_REG = configCPU_CLOCK_HZ/configTICK_RATE_HZ - 1UL;
portEXIT_CRITICAL();
}
}
TouchGFX 渲染过程包括两部分, CPU 渲染和 DMA2D 渲染。在 CPU 渲染过程中, TouchGFX
任务处于执行状态,系统不会主动调度 Idle 任务。而在 DMA2D 渲染过 TouchGFX 会让出
CPU,此时可能会切换到 Idle 任务执行,因此需要对 DMA2D 是否正在渲染进行判断。 对
DMA2D 是否在渲染的判断如下:
extern "C" uint8_t isDMAbusy_a()
{
return ((TouchGFXHAL*)(touchgfx::HAL::getInstance()))->isDMAbusy();
}
uint8_t TouchGFXHAL::isDMAbusy()
{
bool dma_qe = dma.isDmaQueueEmpty();
bool dma_run = dma.isDMARunning();
return (uint8_t)(!dma_qe || dma_run);
}
|