我的平台是H743, 这个应该是通用的:
这个bug跟复位级别、Systick使用TIM有关,如果只复位了内核而没有复位外设,则会触发这个bug,先关注由
//------HERE------HERE------HERE------///
框住的两段区域:
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
RCC_ClkInitTypeDef clkconfig;
uint32_t uwTimclock;
uint32_t uwPrescalerValue;
uint32_t pFLatency;
/*Configure the TIM16 IRQ priority */
if (TickPriority < (1UL << __NVIC_PRIO_BITS))
{
HAL_NVIC_SetPriority(TIM16_IRQn, TickPriority ,0U);
/* Enable the TIM16 global Interrupt */
//------HERE------HERE------HERE------///
HAL_NVIC_EnableIRQ(TIM16_IRQn);
//------HERE------HERE------HERE------///
uwTickPrio = TickPriority;
}
else
{
return HAL_ERROR;
}
/* Enable TIM16 clock */
__HAL_RCC_TIM16_CLK_ENABLE();
/* Get clock configuration */
HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);
/* Compute TIM16 clock */
uwTimclock = 2*HAL_RCC_GetPCLK2Freq();
/* Compute the prescaler value to have TIM16 counter clock equal to 1MHz */
uwPrescalerValue = (uint32_t) ((uwTimclock / 1000000U) - 1U);
/* Initialize TIM16 */
//------HERE------HERE------HERE------///
htim16.Instance = TIM16;
//------HERE------HERE------HERE------///
/* Initialize TIMx peripheral as follow:
+ Period = [(TIM16CLK/1000) - 1]. to have a (1/1000) s time base.
+ Prescaler = (uwTimclock/1000000 - 1) to have a 1MHz counter clock.
+ ClockDivision = 0
+ Counter direction = Up
*/
htim16.Init.Period = (1000000U / 1000U) - 1U;
htim16.Init.Prescaler = uwPrescalerValue;
htim16.Init.ClockDivision = 0;
htim16.Init.CounterMode = TIM_COUNTERMODE_UP;
if(HAL_TIM_Base_Init(&htim16) == HAL_OK)
{
/* Start the TIM time Base generation in interrupt mode */
return HAL_TIM_Base_Start_IT(&htim16);
}
/* Return function status */
return HAL_ERROR;
}
假设系统仅复位内核后,运行到这里:
外设中断使能中(这里是溢出中断),则在NVIC_ENABLE的地方会立即进入TIM_IRQ,而此时htim并没有指向TIM16 Instance,从而导致itflag、itsource读取失败,从而触发bug。
修复的方法也很简单,使用ARM Compiler提供的Sub、Super给InitTick打补丁就好,或者注释掉重新写。
我选择在InitTick前手动清掉TIM的中断使能,这样最简单。