Furkan
Furkan

Reputation: 11

Systick timer interrupt doesn't work on TM4C123

I am new here and hoping to help and be helped.

My question is about systick interrupts on a tm4c123gh6pm m4 processor. When I use systick as timer (disable interrupt) it works properly, but when I enable interrupt, as the systick counter reaches the value 0, which should trigger the interrupt, it goes to IntDefaultHandler(void) which is in the startup.c file. I don't even enable global interrupt. But when I enable the global interrupt I am getting same result. I am sharing the code below, and please pay attention to the commented lines. By the way, I am using iar as my compiler.

#include <stdint.h>
#include <stdio.h>
#include "inc/tm4c123gh6pm.h"

volatile unsigned long Counts=0; 

void SysTick_Init(unsigned long period){ // priority 2
  NVIC_ST_CTRL_R = 0;         // disable SysTick during setup
  NVIC_ST_RELOAD_R = period-1;// reload value
  NVIC_ST_CURRENT_R = 0;      // any write to current clears it
  NVIC_SYS_PRI3_R = (NVIC_SYS_PRI3_R&0x00FFFFFF)|0x40000000;           
  NVIC_ST_CTRL_R = 0x05; // Main problem is here, 0x05 means disable interrupt
// 0x07 means enable interrup. but 0x07 doesnt work for me
}

void SysTick_Handler(void){
    GPIO_PORTF_DATA_R ^= 0x04;       // toggle PF2
    Counts = Counts + 1;
    printf("interrupt working\n");
}

//*****************************************************************************
//
// Blink the on-board LED.
//
//*****************************************************************************
int
main(void)
{
    volatile uint32_t ui32Loop;
    unsigned long now;
    //
    // Enable the GPIO port that is used for the on-board LED.
    //
    SYSCTL_RCGC2_R = SYSCTL_RCGC2_GPIOF;

    //
    // Do a dummy read to insert a few cycles after enabling the peripheral.
    //
    ui32Loop = SYSCTL_RCGC2_R;

    //
    // Enable the GPIO pin for the LED (PF2).  Set the direction as output, and
    // enable the GPIO pin for digital function.
    //
    GPIO_PORTF_DIR_R = 0x04;
    GPIO_PORTF_DEN_R = 0x04;

    SysTick_Init(16000);        // initialize SysTick timer, every 1ms

    //
    // Loop forever.
    //
    while(1)
    {     now = NVIC_ST_CURRENT_R;   // get systick current value

          printf("%u\n",now);


          if((NVIC_ST_CTRL_R&0x00010000)!=0){      // check Systick flag
            GPIO_PORTF_DATA_R ^= 0x04;
            printf("timer working\n");
          }
    }
}

Edit: I have tried a working exapmle wrote by valvano, and this time it goes HardFault_Handler instead of SysTick_Handler. Code is so simple I don't understand the problem. Code is below.

// PeriodicSysTickInts.c
// Runs on LM4F120 or TM4C123
// Use the SysTick timer to request interrupts at a particular period.
// Daniel Valvano
// September 14, 2013

/* This example accompanies the book
   "Embedded Systems: Introduction to ARM Cortex M Microcontrollers"
   ISBN: 978-1469998749, Jonathan Valvano, copyright (c) 2013
   Volume 1, Program 9.6

   "Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers",
   ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2013
   Volume 2, Program 5.12, section 5.7

 Copyright 2013 by Jonathan W. Valvano, [email protected]
    You may use, edit, run or distribute this file
    as long as the above copyright notice remains
 THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
 OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
 VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
 OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 For more information about my classes, my research, and my books, see
 http://users.ece.utexas.edu/~valvano/
 */

// oscilloscope or LED connected to PF2 for period measurement


#define GPIO_PORTF_DATA_R       (*((volatile unsigned long *)0x400253FC))
#define GPIO_PORTF_DIR_R        (*((volatile unsigned long *)0x40025400))
#define GPIO_PORTF_AFSEL_R      (*((volatile unsigned long *)0x40025420))
#define GPIO_PORTF_DEN_R        (*((volatile unsigned long *)0x4002551C))
#define GPIO_PORTF_AMSEL_R      (*((volatile unsigned long *)0x40025528))
#define GPIO_PORTF_PCTL_R       (*((volatile unsigned long *)0x4002552C))
#define SYSCTL_RCGC2_R          (*((volatile unsigned long *)0x400FE108))
#define NVIC_SYS_PRI3_R         (*((volatile unsigned long *)0xE000ED20))  // Sys. Handlers 12 to 15 Priority
#define NVIC_ST_CTRL_R          (*((volatile unsigned long *)0xE000E010))
#define NVIC_ST_RELOAD_R        (*((volatile unsigned long *)0xE000E014))
#define NVIC_ST_CURRENT_R       (*((volatile unsigned long *)0xE000E018))

void DisableInterrupts(void); // Disable interrupts
void EnableInterrupts(void);  // Enable interrupts
long StartCritical (void);    // previous I bit, disable interrupts
void EndCritical(long sr);    // restore I bit to previous value
void WaitForInterrupt(void);  // low power mode
volatile unsigned long Counts = 0;
// **************SysTick_Init*********************
// Initialize SysTick periodic interrupts
// Input: interrupt period
//        Units of period are 62.5ns (assuming 16 MHz clock)
//        Maximum is 2^24-1
//        Minimum is determined by length of ISR
// Output: none
void SysTick_Init(unsigned long period){
  NVIC_ST_CTRL_R = 0;         // disable SysTick during setup
  NVIC_ST_RELOAD_R = period-1;// reload value
  NVIC_ST_CURRENT_R = 0;      // any write to current clears it
  NVIC_SYS_PRI3_R = (NVIC_SYS_PRI3_R&0x00FFFFFF)|0x40000000; // priority 2
                              // enable SysTick with core clock and interrupts
  NVIC_ST_CTRL_R = 0x07;
  EnableInterrupts();
}
// Interrupt service routine
// Executed every 62.5ns*(period)
void SysTick_Handler(void){
  GPIO_PORTF_DATA_R ^= 0x04;       // toggle PF2
  Counts = Counts + 1;
}
int main(void){
  SYSCTL_RCGC2_R |= 0x00000020; // activate port F
  Counts = 0;
  GPIO_PORTF_DIR_R |= 0x04;   // make PF2 output (PF2 built-in LED)
  GPIO_PORTF_AFSEL_R &= ~0x04;// disable alt funct on PF2
  GPIO_PORTF_DEN_R |= 0x04;   // enable digital I/O on PF2
                              // configure PF2 as GPIO
  GPIO_PORTF_PCTL_R = (GPIO_PORTF_PCTL_R&0xFFFFF0FF)+0x00000000;
  GPIO_PORTF_AMSEL_R = 0;     // disable analog functionality on PF
  SysTick_Init(16000);        // initialize SysTick timer
  EnableInterrupts();

  while(1){                   // interrupts every 1ms, 500 Hz flash
    WaitForInterrupt();
  }
}

and all project files SysTickInt

Upvotes: 1

Views: 1101

Answers (1)

joda
joda

Reputation: 405

For your first comment, that the interrupt default handler gets called, this is due to the fact that you did not declare an interrupt handler for the systick interrupt within the startup file. You can do it for example in the following way in the startup file.

extern void systick_isr(void); // somewhere you have to define this interrupt handler

Furthermore you have to add the function name of your interrupt handler to the vector table (excerpt below) in the startup file. Every line represents a certain interrupt handler, take a look at the comments, they tell you which one you have to adapt. For example you can see that the GPIOA interrupt handler will call the default interrupt handler at the moment. The same happens for you, at least for the first part of your question.

//*****************************************************************************
//
// The vector table.  Note that the proper constructs must be placed on this to
// ensure that it ends up at physical address 0x0000.0000 or at the start of
// the program if located at a start address other than 0.
//
//*****************************************************************************
#pragma DATA_SECTION(g_pfnVectors, ".intvecs")
void (* const g_pfnVectors[])(void) =
{
    (void (*)(void))((uint32_t)&__STACK_TOP),
                                            // The initial stack pointer
    ResetISR,                               // The reset handler
    NmiSR,                                  // The NMI handler
    FaultISR,                               // The hard fault handler
    IntDefaultHandler,                      // The MPU fault handler
    IntDefaultHandler,                      // The bus fault handler
    IntDefaultHandler,                      // The usage fault handler
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    IntDefaultHandler,                      // SVCall handler
    IntDefaultHandler,                      // Debug monitor handler
    0,                                      // Reserved
    IntDefaultHandler,                      // The PendSV handler
    systick_isr,                            // The SysTick handler
    IntDefaultHandler,                      // GPIO Port A
    IntDefaultHandler,                      // GPIO Port B
    IntDefaultHandler,                      // GPIO Port C
    IntDefaultHandler,                      // GPIO Port D
...

Regarding the comment in your own code, how the interrupt can be enabled or disabled please be aware that this does not seem to be right. Enabling or disabling the systick interrupt can be achieved by setting the bit number one of the STCTRL register accordingly. The picture below shows the register. To enable the interrupt you have to set the bit number one high (NVIC_ST_CTRL_R |= 0x02;) to disable the interrupt you have to clear the bit (NVIC_ST_CTRL_R &= ~0x02;)

SysTick Control and Status Register

Upvotes: 0

Related Questions