Reputation: 11
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
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;
)
Upvotes: 0