Electronic – STM32 SysTick timer – Doesn’t run the alarm event

armcortex-mstm32

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;
    SCB->ICSR = SCB->ICSR & 0xFDFFFFFF;
    ticks++;
    return;
}

/*
 * 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.

Best Answer

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.