I am trying to implement a Systick exception handler that can flash an LED on the FRDM KL25Z board. The code compiles but when I go to debug it I get the following error: "Error in services launch sequence"
The code is intended to flash an LED on the FRDM board around 1 Hz. I've been able to poll the SysTick without using exceptions/interrupts, but for whatever reason I am missing something while setting this up that blocks execution. I'm trying to write code that is as CMSIS-compliant as possible, so no KDS calls.
If anyone has a hint about what I should be doing differently with setting up the SysTick exception, I'm all ears. Code below...
Thanks!
James
#Kinetis #Systick #CMSIS #frdm–kl25z #exception_handler
#include <stdio.h>
#include "board.h"
#include "peripherals.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "MKL25Z4.h"
/* TODO: insert other include files here. */
/* TODO: insert other definitions and declarations here. */
/* The system tick interrupt handler vector (and name) is defined in startup_mkl25z4.c
*
* */
void SysTick_Handler(void)
{
static int n = 0;
/* every 500 interrupts / exceptions toggle the LED */
if (n <= 500)
{
/* increment the counter. */
n= n+1;
}
else
{
/* "Port Toggle" on Port B: Toggle green LED on PTB19 */
PTB->PTOR = 0x080000;
/* reset the counter */
n=0;
}
}
/*
* @brief Application entry point.
*/
int main (void) {
/* Step 1: Turn on Port B via System Integration Module SIM's SCGC5 register.
* Keep existing state of SCGC5 & only set bit 10 to 1. */
SIM->SCGC5 |= SIM_SCGC5_PORTB_MASK; // The "mask" is 0x400
/* Step 2: Make Port B, Pin 19 a "General Purpose Input or Output" (GPIO)
* Look up section 10.3.1 in the manual. Alt1 mode is GPIO for Port B 19.
* Look up section 11.5.1 in the manual. The MUX bits are bits 10,9 and 8 of the PCR.
* key terms for searching: "alt0" and "pin control register" in the PDF (https://bit.ly/2J2751t)
*/
PORTB->PCR[19] = 0x100; // Mux @ Alt1 is GPIO: Bits 10,9,8 = 0b001
/* Step 3: Make Port B, pin 19 an output (instead of an input) */
PTB->PDDR |= 0x080000; /* Bit 19 is a binary "1" (output). A "0" would be input. */
// Interrupt / Exception with SysTick
// http://homepage.cem.itesm.mx/carbajal/Microcontrollers/SLIDES/Interrupts.pdf
// https://community.nxp.com/thread/311713
// https://mcuoneclipse.com/2016/08/14/arm-cortex-m-interrupts-and-freertos-part-1/#more-19365
__disable_irq(); /* disable all IRQs */
/* Delay = (N+1)/sysclk
* 0.001 [sec] = (N+1) / (48000000/2) ---> N = 0.001[sec]*2400000[MHz] - 1
* So N is 24000-1.
*/
SysTick->LOAD = 24000-1;
NVIC_SetPriority(SysTick_IRQn, (1UL<<__NVIC_PRIO_BITS)-1UL); /* set Priority for Systick Interrupt to lowest interrupt */
SysTick->VAL = 24000-1;
/* Enable the timer and choose processor clock as the clock source via Bits 0 and 2
* Also, enable Systick to generate Exceptions / Interrupts via Bit 1*/
SysTick->CTRL = 0b0111;
/* = 0b0111
* ^^^^
* ||||_________ Bit 0: Enable ( 0 = disable; 1 = enable)
* |||__________ Bit 1: TickInt (interrupt/exception enabling)
* ||___________ Bit 2: Clock Source (0 = ext; 1 = proc. clock)
* |____________ Bit 3: Reserved
*/
/* Enable IRQs within NVIC */
NVIC_EnableIRQ(SysTick_IRQn); /* Enable NVIC interrupt */
/* Enable IRQs globally */
__enable_irq(); /* global enable IRQs */
/* Toggle LED every 0.5 second to give 1Hz */
while (1) {
/* do nothing */
}
}
Hi James
Here is a 1ms SYSTICK interrupt and handler (works on any Kinetis part):
#define TICK_RESOLUTION 1000 // 1ms tick
#define LED_GREEN PORTB_BIT19 // output to be toggled
#define REQUIRED_US (1000000/(TICK_RESOLUTION)) // the TICK frequency we require in MHz
#define TICK_DIVIDE (((CORE_CLOCK + REQUIRED_US/2)/REQUIRED_US) - 1) // the divide ratio required (for systick)
VECTOR_TABLE *ptrVect = (VECTOR_TABLE *)VECTOR_TABLE_OFFSET_REG;
ptrVect->ptrSysTick = _RealTimeInterrupt; // enter interrupt handler
SYSTICK_RELOAD = TICK_DIVIDE; // set reload value to determine the period
SYSTICK_CURRENT = TICK_DIVIDE; // write to synchronise the Systick counter after configuration
SYSTEM_HANDLER_12_15_PRIORITY_REGISTER |= (unsigned long)(SYSTICK_PRIORITY << (24 + __NVIC_PRIORITY_SHIFT)); // enter the SYSTICK priority
SYSTICK_CSR = (SYSTICK_CORE_CLOCK | SYSTICK_ENABLE | SYSTICK_TICKINT); // enable timer and its interrupt
_CONFIG_DRIVE_PORT_OUTPUT_VALUE(B, (LED_GREEN), (LED_GREEN), (PORT_ODE | PORT_SRE_SLOW | PORT_DSE_HIGH)); // configure and drive high
Handler:
// Tick interrupt
//
static __interrupt void _RealTimeInterrupt(void)
{
static int iDiv = 0;
INT_CONT_STATE_REG = PENDSTCLR; // reset interrupt
if (++iDiv >= 500) { // every 500ms
_TOGGLE_PORT(B, LED_GREEN);
iDiv = 0;
}
}
Your problem looks to be a debugger issue - try loading a binary at these links or using the uTasker's KL25 simulator.
http://www.utasker.com/kinetis/FRDM-KL25Z.html
http://www.utasker.com/kinetis/TWR-KL25Z48M.html
However, your handler is not resetting the Systick interrupt flag which would mean that it would never stop firing.
Regards
Mark
uTasker developer and supporter (+5'000 hours experience on +60 Kinetis derivatives in +80 product developments)
Kinetis: http://www.utasker.com/kinetis.html