The SysTick interrupt not triggering on an ARM Cortex M0 microcontroller is often caused by improper configuration of the SysTick registers or failing to enable SysTick interrupts. The SysTick timer is a simple countdown timer built into the Cortex M0 that can generate periodic interrupts for operating system or task scheduling. This article will guide you through troubleshooting and solving the issue of the SysTick interrupt not firing.
Overview of the SysTick Timer
The SysTick timer is a 24-bit countdown timer that is integrated into all Cortex M0 cores. It has several key registers that control its operation:
- SYST_CSR – Control and status register
- SYST_RVR – Reload value register
- SYST_CVR – Current value register
To generate periodic interrupts, the SYST_RVR is loaded with a reload value. This value is copied to the SYST_CVR register which then counts down to 0. When it reaches 0, it triggers the SysTick interrupt and reloads the SYST_RVR value to start again.
The SYST_CSR register controls enabling the counter, interrupt, and clock source. Bits can be set to enable interrupts, use the internal processor clock, and start the timer counting down.
Steps to Enable the SysTick Timer
To properly enable SysTick interrupts, follow these steps:
- Load the SYST_RVR register with your desired reload value. This sets the period of the timer.
- Set the SYST_CVR register to the same value as SYST_RVR to initialize it.
- Set the CLKSOURCE bit in SYST_CSR to use the processor clock.
- Set the TICKINT bit in SYST_CSR to enable SysTick interrupts.
- Set the ENABLE bit in SYST_CSR to start the timer.
Once enabled, the SysTick timer will decrement the CVR register until it reaches 0, then reload the RVR value and generate a SysTick interrupt if enabled. The interrupt can call an interrupt service routine to execute periodic code.
Common Mistakes Preventing Interrupt Generation
There are a few common configuration errors that could result in the SysTick interrupt not firing properly:
- Forgetting to enable SysTick interrupts in the SYST_CSR register
- Failing to set up the interrupt handler/ISR in your code
- Setting the wrong clock source – should be processor clock, not external reference clock
- Not starting the timer by setting the ENABLE bit
- Setting a reload value of 0, which disables the timer
Always carefully check your SysTick initialization code against the steps outlined earlier. Enable interrupts in the SYST_CSR register, set up an interrupt handler, use the processor clock, and start the timer.
If the SysTick configuration registers are set up properly but you still don’t get an interrupt, the problem may be with how the interrupt handler is set up in code.
Be sure to:
- Define an ISR/handler function for the SysTick interrupt
- Specify the correct IRQ number for SysTick in the microcontroller’s NVIC
- Enable the SysTick IRQ line in the NVIC
- Set the correct priority if using priorities
On Cortex M0, the SysTick IRQ number is IRQ #15. Make sure your handler function is being linked correctly and that the interrupt line is enabled and prioritized properly in the nested vectored interrupt controller (NVIC) settings.
Scope Capture for Debugging
One good way to debug the issue is to capture the SysTick registers right when an interrupt should occur using a scope or logic analyzer. This can reveal:
- If the CVR register is counting down properly
- If the interrupt actually signals when CVR hits 0
- Any discrepancy between CVR and RVR values
Monitor the ENABLE bit to see if the timer stops prematurely. Check that it reloads CVR with RVR when the counter expires. This can help identify any incorrect behavior or register values.
Set a breakpoint at the first line of your SysTick_Handler() ISR function. If code execution never hits it, then the processor is not actually entering the ISR when SysTick expires. This indicates an issue generating the interrupt request.
You can also set a breakpoint in the startup code that enables interrupts globally to ensure it is executing. Comment out portions of your handler code to isolate any faults.
Peripheral Register Access
One other cause could be invalid access to SysTick registers from software. Make sure your code properly accesses the SysTick registers in the core peripheral memory map. Confirm it is using the correct bus, clock speeds, and any peripheral libraries provided by the vendor.
Attempting to access insecure registers without the proper bus control can fail to modify SysTick settings. Check your initialization and configuration code carefully for any invalid register writes.
OS Configuration Issues
If you are using an RTOS or operating system, make sure SysTick is not reserved for use by the OS scheduler. The OS configuration may need to be modified to allow application access to SysTick.
Look for any OS hooks into the SysTick_Handler. The OS may override application interrupt handlers or block access to system timers like SysTick that it relies on.
In summary, getting the SysTick interrupt to trigger properly requires:
- Correct configuration of the SYST_CSR, SYST_RVR, and SYST_CVR registers
- Enabling SysTick interrupts in SYST_CSR
- Defining and linking the SysTick_Handler() ISR
- Proper NVIC vector table setup
- No OS reservation of the SysTick timer
- Valid software access to SysTick registers
Carefully go through each step outlined here to identify and correct any potential issues. Double check OS and peripheral library integration. Leverage debugging techniques like register capture and breakpoints to gain visibility. With consistent configuration and integration, getting periodic SysTick interrupts running properly on Cortex M0 is usually manageable.