SysTick ISR not firing (STM32 + CMSIS + StdPeriph library)

Hi,

I’m trying to get a ‘trivial’ SysTick demo example running based on the example code provided with the Std Periph library V3.2.0.

AFAICT, with CMSIS and V3 of Std Periph, the only code that should be required is :

/* Setup SysTick Timer for 1 msec interrupts.
   */
  if (SysTick_Config(SystemCoreClock / 1000))
  { 
    while (1);                  /* Capture error */ 
  }

and

void SysTick_Handler(void)
{
  /* ISR handler. */
}

…however this isn’t working for me. SysTick_Handler() is never called.

Could anyone show me how to hook this up please?

The full code is below. I’m using the Olimex STM32-H103 board. I turn the onboard LED on (output low) at start and then off (output high) in the ISR, but the LED stays on.

Using the same template I have made working code to handle UART interrupts, so I have some confidence the vector table is being set up although clearly something is not right.

main.c:

#include "stm32f10x.h"
#include "main.h"

void GPIO_Configuration(void);
void NVIC_Configuration(void);

int main(void)
{
  /*!< At this stage the microcontroller clock setting is already configured, 
       this is done through SystemInit() function which is called from startup
       file (startup_stm32f10x_xx.s) before to branch to application main.
       To reconfigure the default setting of SystemInit() function, refer to
       system_stm32f10x.c file
     */     

  NVIC_Configuration();   /* <--- Tried with and without this call. */

  GPIO_Configuration();

  /* Setup SysTick Timer for 1 msec interrupts.
   */
  if (SysTick_Config(SystemCoreClock / 1000))
  { 
    while (1);                  /* Capture error */ 
  }

  GPIO_ResetBits(LED_PORT, LED1_PIN); /* LED on. */

  while (1)
  {
  }
}

void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(LED_RCC_APB2Periph_GPIO | RCC_APB2Periph_AFIO, ENABLE);

  GPIO_InitStructure.GPIO_Pin =  LEDS_ALL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(LED_PORT, &GPIO_InitStructure);
}

void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  NVIC_InitStructure.NVIC_IRQChannel = SysTick_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

main.h:

#ifndef __MAIN_H
#define __MAIN_H

/* STM3210C-EVAL
 */
/* #define LED_RCC_APB2Periph_GPIO RCC_APB2Periph_GPIOD */
/* #define LED_PORT GPIOD */
/* #define LED1_PIN GPIO_Pin_7 */
/* #define LED2_PIN GPIO_Pin_13 */
/* #define LED3_PIN GPIO_Pin_3 */
/* #define LED4_PIN GPIO_Pin_4 */
/* #define LEDS_ALL (LED1_PIN | LED2_PIN | LED3_PIN | LED4_PIN) */

/* Olimex STM32-H103.
 */
#define LED_RCC_APB2Periph_GPIO RCC_APB2Periph_GPIOC
#define LED_PORT GPIOC
#define LED1_PIN GPIO_Pin_12
#define LEDS_ALL LED1_PIN

#endif /* __MAIN_H */

stm32f10x_it.c:

#include "stm32f10x.h"
#include "stm32f10x_it.h"
#include "main.h"

/**
  * @brief  This function handles NMI exception.
  * @param  None
  * @retval None
  */
void NMI_Handler(void)
{
}

/**
  * @brief  This function handles Hard Fault exception.
  * @param  None
  * @retval None
  */
void HardFault_Handler(void)
{
  /* Go to infinite loop when Hard Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles Memory Manage exception.
  * @param  None
  * @retval None
  */
void MemManage_Handler(void)
{
  /* Go to infinite loop when Memory Manage exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles Bus Fault exception.
  * @param  None
  * @retval None
  */
void BusFault_Handler(void)
{
  /* Go to infinite loop when Bus Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles Usage Fault exception.
  * @param  None
  * @retval None
  */
void UsageFault_Handler(void)
{
  /* Go to infinite loop when Usage Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles SVCall exception.
  * @param  None
  * @retval None
  */
void SVC_Handler(void)
{
}

/**
  * @brief  This function handles Debug Monitor exception.
  * @param  None
  * @retval None
  */
void DebugMon_Handler(void)
{
}

/**
  * @brief  This function handles PendSV_Handler exception.
  * @param  None
  * @retval None
  */
void PendSV_Handler(void)
{
}

/**
  * @brief  This function handles SysTick Handler.
  * @param  None
  * @retval None
  */
void SysTick_Handler(void)
{
  GPIO_SetBits(LED_PORT, LED1_PIN); /* LED off. */
}

stm32f10x_it.h:

#ifndef __STM32F10x_IT_H
#define __STM32F10x_IT_H

void NMI_Handler(void);
void HardFault_Handler(void);
void MemManage_Handler(void);
void BusFault_Handler(void);
void UsageFault_Handler(void);
void SVC_Handler(void);
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);

#endif /* __STM32F10x_IT_H */

Hey there…

You did not mention the compiler environment you where using…the following example that I have uses Crossworks

#include "stdint.h"
#include "targets/STM32F10x.h"

// LED1 is on PC12
// The button is on PA0

volatile uint32_t flag=1;

// callback handler for systick callback
void SysTickHandler(void)
{
    if(flag==1)
    {
        GPIOC_BSRR  = (1<<12);   // turn on LED
        flag=0;
    }
    else
    {
        GPIOC_BRR = (1<<12);    // turn off LED
        flag=1;
    }

} 

// configure LED on RA12
void board_init(void)
{
    // configure LED ports
    RCC_APB2ENR |= RCC_APB2ENR_IOPCEN;
    uint32_t pin = 4;
    uint32_t mode = (uint32_t)0x05 << (pin * 4);
    uint32_t mask = (uint32_t)0x0f << (pin * 4);
    uint32_t temp = GPIOC_CRH & ~mask;
    GPIOC_CRH = temp | mode;
}

// starts 1 second callback to the systickhandler above
void MySysInit()
{
    RCC_CR |=RCC_CR_HSEON;
    while(!(RCC_CR & RCC_CR_HSERDY)); // wait until external crystal osc is ready

    FLASH_ACR = FLASH_ACR_PRFTBE | 2<<FLASH_ACR_LATENCY_BIT; // 2 wait states

    RCC_CFGR = 7<<RCC_CFGR_PLLMUL_BIT;      // set PLL to x9. Clock is at 8mhz, 72mhz = 8mhz x 9
    RCC_CFGR |= 1<<RCC_CFGR_PLLSRC_BIT;     // set hse as clock input
    RCC_CR |= RCC_CR_PLLON;                 // turn on PLL

    while((RCC_CR & RCC_CR_PLLRDY)==0);     // wait for clock to settle

    RCC_CFGR |= 2;                          // set PLL used as system clock
    RCC_CFGR |= 3<<RCC_CFGR_ADCPRE_BIT;     // ADC clock source is 72/8 MHz

    while((RCC_CFGR & (2<<RCC_CFGR_SWS_BIT))==0); // switch to pll

    SysTick_Reload_Value = 9000000;         // 1 second = 72,000,000 / 8,000,000 = 9,000,000
    SysTick_Control_And_Status |= SysTick_Control_And_Status_ENABLE;
    SysTick_Control_And_Status |= SysTick_Control_And_Status_TICKINT;
}
 
void main(void)
{
    board_init();
    MySysInit();

    while(1)
    {
    }
}

I don’t have time to go thru your code (meetings), but this code DOES work under Crossworks…

~Kam (^8*

I use RIDE7 and generate all my delays using SysTick. Try moving the handler to main.c - that is where I have mine.

Silly question, but are you actually linking in the “_it.c” file? :?:

As rmteo1 mentioned, include the “handler” method in the main.c file, that will prove that the handler is indeed linked in…

~Kam (^8*

A couple thoughts:

  1. Instead of just turning off the LED, toggle it inside the interrupt handler. Then you remove any race conditions that may occur between setting up the systick and that sole GPIO_Reset_bits. Make the SysTick slow enough to see the changes in the LED, maybe SystemFrequency/10.

  2. I had troubles as well, you might review my earlier thread dealing with SysTick interrupts: [STM32 SysTick Interrupts

  3. I had one additional statement that may or may not help (NVIC_SetPriority):

	if (SysTick_Config(SystemFrequency / 500))
		{
		/* Capture error */
		while (1);
		}
    NVIC_SetPriority(SysTick_IRQn, 14);
	}

Good luck,

Jim](http://forum.sparkfun.com/viewtopic.php?f=11&t=19688)

Well I finally tracked this down. After several hours of banging ones head against the keyboard this turned out to be one of those bugs that when finally cracked makes you want to scream. :evil:

Thanks for all the suggestions they are much appreciated. I’m using Crossworks - sorry, should have mentioned that already as it turns out to be key. Let this post be a heads up to anyone using Std Periph lib under Crossworks (or any vendor environment for that matter).

Std Periph lib V3.2.0 provides the following code in file startup_stm32f10x_cl.s:

g_pfnVectors:
  .word  _estack
  .word  Reset_Handler
  .word  NMI_Handler
  .word  HardFault_Handler
  .word  MemManage_Handler
  .word  BusFault_Handler
  .word  UsageFault_Handler
  .word  0
  .word  0
  .word  0
  .word  0
  .word  SVC_Handler
  .word  DebugMon_Handler
  .word  0
  .word  PendSV_Handler
  .word  SysTick_Handler
  .word  WWDG_IRQHandler
  .word  PVD_IRQHandler
  .word  TAMPER_IRQHandler
  .word  RTC_IRQHandler
  .word  FLASH_IRQHandler
  .word  RCC_IRQHandler
  .word  EXTI0_IRQHandler
  .word  EXTI1_IRQHandler
  .word  EXTI2_IRQHandler
  .word  EXTI3_IRQHandler
  .word  EXTI4_IRQHandler

etc...

Crossworks provides it’s own startup file, STM32F10x_Startup.s:

_vectors:
  .word __stack_end__
#ifdef STARTUP_FROM_RESET
  .word reset_handler
#else
  .word reset_wait
#endif /* STARTUP_FROM_RESET */
  .word NMIException
  .word HardFaultException
  .word MemManageException 
  .word BusFaultException
  .word UsageFaultException
  .word 0 // Reserved
  .word 0 // Reserved
  .word 0 // Reserved
  .word 0 // Reserved
  .word SVCHandler
  .word DebugMonitor
  .word 0 // Reserved
  .word PendSV
  .word SysTickHandler 
  .word WWDG_IRQHandler
  .word PVD_IRQHandler
  .word TAMPER_IRQHandler
  .word RTC_IRQHandler
  .word FLASH_IRQHandler
  .word RCC_IRQHandler
  .word EXTI0_IRQHandler
  .word EXTI1_IRQHandler
  .word EXTI2_IRQHandler
  .word EXTI3_IRQHandler
  .word EXTI4_IRQHandler

etc...

Ignore the distraction of STARTUP_FROM_RESET macro (that’s just another minor annoyance to catch out the unaware), did you spot the difference yet?

ok, put another way, here’s the fix implemented in stm32f10x_it.c:

/* void SysTick_Handler(void) */
void SysTickHandler(void)
{
  /* ... */
}

scream

The realisation finally dawned as I was counting down the vector table elements to be sure that SysTick was in the right place and I spotted the obvious difference between PendSV_Handler and PendSV, then of course focusing on SysTick_Handler the bug is clear.

Apart from that the code works fine as is (no messing with NVIC required for SysTick it seems, Jim). Another small gotcha to point out though, SystemInit() is called implicitly when linking with startup_stm32f10x_cl.s, but not with STM32F10x_Startup.s, so in the former case you don’t want a call to SystemInit() in your code (or it’ll be called twice) but in the later case it needs to be called at the start of main() {…}.

So beware… any demo code provided with the Std Periph library probably ain’t gonna work right out of the box unless either stm32f10x_it.c is modified or the vendor supplied environment is tailored to fit. :roll:

Thanks once again for all the suggestions.

My bad…I should have mentioned the mthod names where different!..