What is `SystemCoreClock` and How Does It Relate to SysTick?

While reading an embedded systems example, I came across several terms :

  • SystemCoreClock
  • CMSIS-Core
  • Cortex-M
  • SysTick
  • SysTick->LOAD
  • SysTickPeriodSet()

A useful way to see the relationship is:


What is SystemCoreClock?

In CMSIS-Core for Cortex-M processors, SystemCoreClock is a global variable that contains the system frequency, measured in Hz (1/s).

Conceptually, it may contain a value such as:

SystemCoreClock = 16000000;

which means that the current system frequency is 16 MHz.

CMSIS standardizes this variable so that software written for different Cortex-M based microcontrollers can use a common interface instead of every manufacturer inventing a different name.


What is CMSIS-Core?

CMSIS stands for:

Cortex Microcontroller Software Interface Standard

CMSIS-Core is the part of CMSIS that provides a standardized software interface for Arm Cortex-M processors.

It defines common names, data structures, functions, and interfaces that software can use to interact with Cortex-M processor features.

For example, CMSIS provides interfaces such as:

SystemCoreClock
SystemCoreClockUpdate()

SysTick->CTRL
SysTick->LOAD
SysTick->VAL

What is Cortex-M?

Cortex-M is a family of 32-bit RISC Arm processor cores designed mainly for microcontrollers and embedded systems.

They are optimized for properties such as:

  • low cost
  • low power
  • predictable interrupt behavior
  • real-time control

For example, the Cortex-M3 processor used in this exercise is based on the Armv7-M architecture.

Inside a Cortex-M processor are several hardware components. One of them is the SysTick timer.


What is SysTick?

SysTick is a hardware timer built into the Cortex-M processor. It contains a 24-bit decrementing counter.

The basic idea is:

LOAD value
    ↓
counter decreases
    ↓
...
3
2
1
0
    ↓
reload
    ↓
start counting again

If the SysTick interrupt is enabled, reaching zero can also cause the processor to execute an interrupt service routine (ISR).

So SysTick can be used to generate regular events such as:

every 1 ms
every 10 ms
every 100 ms

SysTick Registers

The SysTick hardware contains several registers.

CMSIS gives us a convenient C interface to access these registers:

SysTick->CTRL
SysTick->LOAD
SysTick->VAL

These expressions are software interfaces, but they correspond to actual registers in the SysTick hardware.

SysTick->CTRL

CTRL is the control register.

It controls how SysTick operates:

  • enable or disable the SysTick counter
  • enable the SysTick interrupt
  • select the clock source

Conceptually:

CTRL
 ├── ENABLE
 ├── TICKINT
 └── CLKSOURCE

SysTick->LOAD

LOAD stores the reload value for the SysTick counter.

The counter is 24 bits wide.

If:

SysTick->LOAD = N - 1;

then the counter counts for approximately N clock cycles.

This is because the counter includes zero when counting down.


SysTick->VAL

VAL contains the current value of the SysTick counter.

For example, if:

LOAD = 999

then during operation VAL may look like:

999
998
997
...
2
1
0

After reaching zero, the counter reloads and begins another interval.


SystemCoreClock and SysTick Are Different Things

This distinction was initially confusing to me.

  • SystemCoreClock = software variable describing the system frequency
  • SysTick = hardware timer that uses a clock to count

For example, if:

SystemCoreClock = 16000000;

the processor is operating with a system frequency of 16 MHz.

SysTick can then use that clock frequency to determine how many processor clock cycles correspond to a desired time interval.


CMSIS System Functions

CMSIS also defines functions related to the system clock configuration.

SystemCoreClockUpdate()

This function updates the value stored in SystemCoreClock

SystemInit()

This function performs low-level system initialization. It is normally called during startup before the main application begins.


Vendor Library APIs

The textbook also uses functions such as:

SysTickPeriodSet();
SysTickIntRegister();
SysTickEnable();
SysTickIntEnable();

They are library functions provided by the microcontroller vendor’s software library.

SysTickPeriodSet()

SysTickPeriodSet(SysCtlClockGet() / 1000);

Sets the number of clock cycles in one SysTick period.

SysCtlClockGet() obtains the current system clock frequency, and the result is used to calculate the desired SysTick interval.

SysTickIntRegister()

SysTickIntRegister(&countDown);

Registers the interrupt service routine by providing a function pointer.

SysTickEnable()

Enables the SysTick counter so that it begins counting.

SysTickIntEnable()

SysTickIntEnable();

Enables the SysTick interrupt.

This is different from enabling the timer itself:

SysTickEnable()
    → counter starts running

SysTickIntEnable()
    → reaching zero is allowed to generate an interrupt

Putting Everything Together

The complete picture is:

C program
│
├── SystemCoreClock
│      software variable containing system frequency
│
├── Vendor library
│      SysTickPeriodSet()
│      SysTickEnable()
│      SysTickIntEnable()
│
↓
CMSIS / register-level interface
│
│      SysTick->CTRL
│      SysTick->LOAD
│      SysTick->VAL
│
↓
Cortex-M processor
│
└── SysTick hardware
       ├── control register
       ├── reload register
       └── 24-bit counter

A Question to Think About

Create a C program for the ARM Cortex-M3 to use the SysTick timer to invoke a system-clock ISR with a jiffy interval of 10 ms that records the time since system start in a 32-bit integer. How long can this program run before the clock overflows?

This question connects all of the concepts above:

system frequency
      ↓
SysTick period
      ↓
SysTick counter
      ↓
interrupt
      ↓
ISR
      ↓
software clock

Solution:

volatile int32_t timerCount = 0;
void countSince() {
  timerCount++;
}
void main() {
  SysTickPeriodSet(SysCtlClockGet()/100);
  SysTickIntRegister(&countSince);
  SysTickEnable();
  SysTickIntEnable();
  ...
 }

The largest positive number that fits in an int32_t data type is 2^31 − 1 = 2,147,483,647. Multiplying this by 10 ms indicates that the clock will overflow after about 249 days.