SysTick_Handler crashes when incrementing static variable using ++
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-05-21 9:57 PM - last edited on ‎2025-05-22 12:43 AM by Andrew Neil
Hi all,
I'm working on an STM32F411 project using STM32CubeIDE (bare-metal, no HAL). I'm setting up a 1ms tick using SysTick_Config() and defining my own SysTick_Handler() to keep a millisecond counter. Here's the issue:
When I increment a static volatile global counter inside the handler using '++', the system crashes and ends up in Default_Handler. But strangely, if I assign a constant (e.g. millis = 123;), it works perfectly fine. Moreover, if I increment a local temp variable and increment millis, it'll take it just fine. Here's my code snippet. I'm not using the HAL library for this. Would you know why this would be? I'm using an STM32F411CE6 black pill.
Thanks!
static volatile uint32_t millis = 0;
void SysTick_Handler(void)
{
// This works:
// millis = 123;
// This works as well:
uint32_t tmp = millis;
tmp++;
millis = tmp;
// This causes a crash into a forever loop in default handler:
millis++;
(void)(SysTick->CTRL); // Clear COUNTFLAG
}
// SysTick is initialized like this in main, got all the clocks, etc, working. Running at 75MHz PLL, 25MHZ external crystal.
SysTick_Config(SystemCoreClock / 1000); // 1ms tick
Solved! Go to Solution.
- Labels:
-
Bug-report
-
STM32F4 Series
-
SysTick
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-05-22 4:18 AM
If it's in Default_Handler, that is not a crash, but indicates an interrupt fired which you have not implemented.
The issue has to be elsewhere, no way incrementing a variable is the root cause here.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-05-22 4:28 AM
@TDK wrote:If it's in Default_Handler, that is not a crash,
Is that necessarily true in a bare-metal (not HAL) setup?
Using HAL, you get a distinct Hard Fault handler - but maybe not in the OP's case?
@drdrone you do need to determine what, exactly, is calling your "Default_Handler"
A complex system designed from scratch never works and cannot be patched up to make it work.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-05-22 7:15 AM
Here it is, seems like it's fine?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-05-22 7:17 AM
Hi Andrew, thanks for pointing that out. It's a typo; kindly ignore. It seems to happen whether I use static or not.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-05-22 7:23 AM
@drdrone wrote:It seems to happen whether I use static or not.
What about whether you use volatile or not?
And what optimisation level are you using?
A complex system designed from scratch never works and cannot be patched up to make it work.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-05-22 7:27 AM
Yup, no luck with that either
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-05-22 7:37 AM
#include "stm32f4xx.h"
volatile uint32_t millis = 0;
void SysTick_Handler(void)
{
millis++;
(void)(SysTick->CTRL);
}
int main(void) {
SystemInit();
SysTick_Config(75000); // 1 ms tick
while (1) {
}
}
In system_stm32f4xx.c:
void SystemInit(void)
{
/* FPU settings ------------------------------------------------------------*/
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
#endif
// Enable HSE
RCC->CR |= RCC_CR_HSEON;
while (!(RCC->CR & RCC_CR_HSERDY)); // Wait for HSE ready
// Configure PLL:
// PLL input = 25 MHz (HSE)
// PLLM = 8, PLLN = 336, PLLP = 4 → 84 MHz
RCC->PLLCFGR = (16 << RCC_PLLCFGR_PLLM_Pos) | // PLLM = 25 25MHz OSC/ 25
(192 << RCC_PLLCFGR_PLLN_Pos) | // PLLN = 300
(1 << RCC_PLLCFGR_PLLP_Pos) | // PLLP = 4 (01) = 300/4 = 75
(RCC_PLLCFGR_PLLSRC_HSE) | // Use HSE as PLL source
(7 << RCC_PLLCFGR_PLLQ_Pos); // PLLQ = 7 (USB, optional)
// Enable PLL
RCC->CR |= RCC_CR_PLLON;
while (!(RCC->CR & RCC_CR_PLLRDY)); // Wait for PLL lock
// Flash setup: 2 wait states for 84 MHz
FLASH->ACR |= FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_PRFTEN;
FLASH->ACR &= ~FLASH_ACR_LATENCY;
FLASH->ACR |= FLASH_ACR_LATENCY_2WS;
// Select PLL as system clock source
RCC->CFGR &= ~RCC_CFGR_SW;
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
// Update global variable
SystemCoreClock = 75000000;
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
/* Configure the Vector Table location -------------------------------------*/
#if defined(USER_VECT_TAB_ADDRESS)
SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#endif /* USER_VECT_TAB_ADDRESS */
}
In core_cm4.h
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
return (1UL); /* Reload value impossible */
}
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0UL); /* Function successful */
}
Seems like SysTick_Handler had a valid memory region:
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-05-22 8:08 AM
Have you determined yet what is causing it to enter your default handler?
Is it a Hard Fault, or not?
A complex system designed from scratch never works and cannot be patched up to make it work.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-05-22 10:28 AM
Yup, hard fault, thanks for all your help. Seems like I had an issue with my clock setup - when I ran it at 75MHz, I think I was supposed to set the power control scaling for it to be able to go that high. The system defaults to scale 2, which supports only lower clock frequencies; anything greater would need this code to be put before the PLL setup.
The reference manual doesn't really state that you have to do this for 75MHz, it says only if you run less than 100MHz, but I guess I needed it.
Enable interface clock and set the internal voltage regulator scale to scale 1
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS;
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-05-22 11:44 AM
Check RCC setting for PLL, confirm execution speed.
Check FLASH wait states.
Check VCAP capacitors and voltage. 4u7 total, 1.25V. Issues here often result in Hard Faults due to read failures.
Up vote any posts that you find helpful, it shows what's working..

- « Previous
-
- 1
- 2
- Next »