Random Double Firing of SysTick_Handler on STM32H7
Hello together,
my Problem ist that I can find randomly (a few times per hour) timestamps which are delayed by 1ms, after that the delays consist and kind of add up. The cause for this is probably the SysTick_Handler firing 2x in a row and increasing my Uptime_ms timestamp. But here the extended information:
I have a STM32H7 connected to a ADC via SAI. As I want precise time measurements my Code for capturing the time in the SAI_IRQ is the following:
{
uint32_t primask = __get_PRIMASK();
__disable_irq();
SAI_isr_systick = SYSTICK_VALUE;
SAI_isr_uptime_ms = hfwtmr_Uptime;
__set_PRIMASK(primask); // restore PRIMASK state
}
with:
#define SYSTICK_VALUE (SysTick->VAL)
volatile int64_t hfwtmr_Uptime = 0;
volatile int64_t SAI_isr_uptime_ms = 0;
volatile uint32_t SAI_isr_systick = 0;
For setting up the Systick HAL_InitTick() is used. As the STM32H7 is running with 480MHz the systick gets loaded to 480000 every time. A screenshot auf the call hierarchy is added after the code segment.
__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
/* Check uwTickFreq for MisraC 2012 (even if uwTickFreq is a enum type that don't take the value zero)*/
if((uint32_t)uwTickFreq == 0UL)
{
return HAL_ERROR;
}
/* Configure the SysTick to have interrupt in 1ms time basis*/
if (HAL_SYSTICK_Config(SystemCoreClock / (1000UL / (uint32_t)uwTickFreq)) > 0U)
{
return HAL_ERROR;
}
/* Configure the SysTick IRQ priority */
if (TickPriority < (1UL << __NVIC_PRIO_BITS))
{
HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
uwTickPrio = TickPriority;
}
else
{
return HAL_ERROR;
}
/* Return function status */
return HAL_OK;
}
The Systick runs on Priority 0 and these are the following are the only other enabled Priority 0 NVICs. Furthermore __disable_irq() is never used again in the whole project.

My SysTick_Handler() is pretty short, as it contains only the following functions, which are only used 1 time in the Code. Setting Counters into SysTick_Handler and SysTick_Interrupt_Handler show that they are called the same amount.
void SysTick_Handler(void)
{
SysTick_Interrupt_Handler();
HAL_IncTick();
}
with
void SysTick_Interrupt_Handler()
{
hfwtmr_Uptime++; //increase every milli-second
for (uint16_t idx = 0; idx < HFWTMR_NUM; idx++)
{
if(g_hfwtmr[idx] != 0)
{
--g_hfwtmr[idx];
}
}
}
My Problem ist that I can find randomly (a few times per hour) timestamps which are delayed by 1ms.
By logging the SysTick_Handler via DWT->CYCNT I was able to figure out, that in these cases the Systick is firing 2x. In the following table you can see that there are only 874 (15227113-1252270259) ticks in the DWT->CYCCNT between the end of the first SysTick_Handler and the start of the next SysTick_Handler. The number of ticks for the error case of double firing vary between 500 and 1000. Before and after that the SysTick_Handler triggers correctly for roughly an hour. It is not time dependend, as it runs sometime for 20mins without a problem and sometimes for 2h. However it seems like the likelihood of these double firing of the SysTick_Handler is increasing with the computational load on the µC. But as the Systick is the King, no one is allowed to interrupt him (except during the time capturing of the SAI where __disableIRQ is set, so that Systick->Val and Uptime are consistent).
| DWT-Ticks | hfwtmrUptime | Event | info8 | info16 |
| ||
| 1252269511 | 45863 | EVENT_SysTick_Interrupt_Handler_Start | 39 | 28581 | |||
| 1252270259 | 45864 | EVENT_SysTick_Interrupt_Handler_End | 39 | 28581 | |||
| 1252271133 | 45864 | EVENT_SysTick_Interrupt_Handler_Start | 39 | 28581 | |||
| 1252271419 | 45864 | EVENT_SysTick_Interrupt_Handler_Bug2xSystick | 39 | 28581 | |||
After the red line EVENT_SysTick_Interrupt_Handler_Bug2xSystick the Uptime is incremented again, so it jumps from 45863ms to 45865ms in a timespan of ~1000 ticks.
Things I have tried so far:
- Logging the SCB->ICSR (0xE000ED04UL) at the end of every SysTick_Interrupt_Handler, but there was never a pending Systick in SCB->ICSR Bit26.
- Adding __DSB() at the end of the SysTick_Interrupt_Handler did not make any difference.
- Using __enableIRQ() instead of __set_PRIMASK(primask) did not make any difference
So my question is, how can I solve the problem that the SysTick_Handler is firing 2x inside of ~1000 ticks.
Please tell my if additional information is missing.
Kind regards
Heiko
