I'm attempting to write an interrupt to keep basic time measured in ticks on an STM32F407VGT (Discovery Board.)

My interrupt appears to run once (though I cannot be sure), but it then crashes/locks up the processor completely. All UART output stops...

The code is essentially the same as in "The Definitive Guide to the ARM Cortex-M3, 2nd ed." (Joseph Yiu, Newnes.) Could the fact that the STM32F4xx is an ARM Cortex-M4 be a problem? If so, how do I fix this? I initially tried using TMR2, with similar issues, which makes me think it's something I'm missing. I've also tried using SysTickConfig, with the same problems.

uint32_t ticks;

void SysTickAlarm(void)
    SysTick->CTRL = 0;

 * Initialise system timer
void tick_init(void)
    ticks = 0;
    *((volatile unsigned int*)(SCB->VTOR + (15 << 2))) = (unsigned int) SysTickAlarm;

    SysTick->CTRL = 0;                  // Disable SysTick
    SysTick->LOAD = TICK_DELAY;         // Delay for 10 ms
    SysTick->VAL = 0;                   // Clear current value to 0
    SysTick->CTRL = 0x7;                // Enable SysTick+exception and use processor clock

 * get_ticks: Get the number of ticks since processor initialisation.
uint32_t get_ticks()
    return ticks;

main() calls tick_init() then starts spitting out printf("ticks=%d\n", get_ticks()); in a loop. But it stops fairly quickly, I get around 10 lines before it crashes.

I'm very new to ARM processors, so it's probably something very simple, but I can't see it.

  • \$\begingroup\$ Do you have a toolchain with debug? I'd also recommend using ST's Standard Peripheral Library for your device, it makes it much simpler to configure the device than poking stuff into registers. \$\endgroup\$
    – Al Bennett
    Jun 28, 2012 at 10:19
  • \$\begingroup\$ I'll have to check on whether I have a debugger available. I am working in an internship and we aren't allowed to use ST's peripheral library, because it's incompatible with a lot of things. (I didn't choose this.) \$\endgroup\$
    – Thomas O
    Jun 28, 2012 at 10:22
  • \$\begingroup\$ Is your SysTickAlarm() actually a systick handler? Double-check your vector table. \$\endgroup\$
    – Thorn
    Jun 28, 2012 at 10:27
  • \$\begingroup\$ I believe that's what the *((volatile unsigned int*)(SCB->VTOR + (15 << 2))) = (unsigned int) SysTickAlarm; is for, but I'm not certain. \$\endgroup\$
    – Thomas O
    Jun 28, 2012 at 10:34
  • \$\begingroup\$ Where is your code, is it in RAM? Have you remapped RAM to address 0x0? By default this kind of assignment will attempt to modify flash which is not allowed. If your code is in RAM but you haven't remapped RAM to address 0x0, you need to set vector table offset before doing anything with interrupts. Please post a complete minimal example with linker script (preferably also minimal but working) and startup code. \$\endgroup\$
    – Thorn
    Jun 28, 2012 at 10:52

1 Answer 1


You have created quite a problem for yourself by ditching the standard peripherals library (SPL). This microcontroller is hard enough to learn with it, let alone without. The library may be horribly designed but it has an advantage of actually working. I suggest you first get a simple test program working using SPL, then gradually reimplement its functionality if you really can't use it (I'm yet to see a technical reason for that however).

In order to use an interrupt in a Cortex-M3/M4, you need the following:

  • a stack. The core automatically saves several registers on the stack when an interrupt fires. Initial stack pointer value is read from address 0x0 the first thing when the core starts up. That value should normally equal to the end of RAM + 1.
  • correct vector table offset in the SCB->VTOR register. By default it's 0, which (again by default) is the start of flash. If your startup code / linker script combination sets up the vector table correctly, great. The SPL does that. You don't seem to (unless it's in the code you didn't post). Look how it's done in the standard peripherals library (startup_stm32f4xx.s and corresponding linker script for a gcc-based toolchain).
  • a handler. you have that.
  • address of that handler + 1 needs to be in the correct position in the vector table. The way you're assigning a value to a location in the (assumed) vector table isn't going to work by default, since it's in flash. It makes me think you have remapped your RAM to start at address 0, but there's nothing in your question that would indicate that.
  • the interrupt needs to be enabled in the NVIC and its priority set. I don't see that in your code at all. This uses NVIC->ISER[x] and NVIC->IPR[x] registers. See implementation of NVIC_Init() in the SPL and PM00214 section 4.3.
  • finally, the peripheral needs to be configured to generate actual interrupt requests. Seems like you're doing that.

If after checking all that you still can't get it to work, posting a complete (but minimal) project to analyze would be best.

  • \$\begingroup\$ I've found the SPL more of a hindrance than a help, perhaps because I haven't found the right documentation for it. Using the STM data sheet and the supplied headers, I can know that the way to set the I/O port B0 to normal I/O is to set bit 0 and clear bit 1 of GPIOB_MODER, and the C code for that is rmw_mask32(&GPIOB->MODER, 3, 1); (using my rmw_mask32 routine to perform GPIOB->MODER = (GPIOB->MODER & ~3) | 1, but using LDREX/STREX to be interrupt-safe). Is there any nice easily-searchable documentation which would say how to use the SPL for such a purpose? \$\endgroup\$
    – supercat
    Jun 28, 2012 at 15:55
  • \$\begingroup\$ It's not my decision to not use the SPL. My employer requires it. I have found out the problem with my original timer solution - I had not set up the clock properly - now that works fine. \$\endgroup\$
    – Thomas O
    Jun 28, 2012 at 17:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.