Systick
systick timer
Systick timer (System Tick timer) is a 24-bit timer that counts from a given value N-1 (reload value) down to zero. It is nothing more than a counter that triggers some event when it reaches a given value.
SysTick is part of the “System Control Block”, SCB (page 221 PM0214 Programming manual) and is integrated into the Cortex-M core.
SysTick is a core peripheral, as are Nested Vectored Interrupt Controller (NVIC) and System Control Block (SCB).
SysTick information can be found, not in the reference manual, but in the programming manual PM0214, from page 246.
Belonging to the Cortex core, the SysTick timer does not need a clock enable control bit.
Three registers are used to control Systick:
address |
name |
register |
|---|---|---|
e000 e010 |
control and status register CSR |
CTRL |
e000 e014 |
reload value register RVR |
LOAD |
e000 e018 |
current value register CVR |
VAL |
e000 e01c |
calibration value register |
CALIB |
SysTick->VAL = 0x00000000U; // set current value to 0
SysTick->LOAD = 4 000 000U - 1U; // 4 MHz → 4 000 000 pulses 1 s
SysTick->CTRL |= 0x0007; // set processor clock as source, enable timer + interrupt
The SysTick timer counts down from a set value to zero. This set value is stored in the reload value register (RVR or LOAD) in Cortex Microcontroller Software Interface Standard (CMSIS).
Then, the current value register (CVR or VAL) must be reset. The timer is started by setting ENABLE in the control and status register (CSR or CTRL).
When the CTRL_COUNTFLAG bit is set, it means that the timer has counted down to 0.
Finally, the CTRL register is set to zero to disable the timer.
bits 23:0 RELOAD value
The RELOAD value can be any value in the range 0x00000001-0x00FFFFFF (24 bits).
SysTick current value register (STK_VAL)
Reads return the current value of the SysTick counter.
Blinking code
ldr r1, =GPIOB_BASE // 4800 0400
ldr r6, =GPIO_BSRR_BR_6
ldr r7, =GPIO_BSRR_BS_6
1:
str r6, [r1,#GPIO_BSRR]
push {r1}
ldr r0, = 500000
bl delay
pop {r1}
str r7, [r1,#GPIO_BSRR]
push {r1}
ldr r0, = 100000
bl delay
pop {r1}
b 1b
The delay subroutine is so implemented:
.global delay
.type delay, %function
delay:
ldr r1, =SysTick_BASE
str r0, [r1, #LOAD] // SysTick reload value register RVR
ldr r0, =0
str r0, [r1, #VAL] // SysTick Current Value Register CVR
// ldr r0, =SysTick_CTRL_CLKSOURCE_Msk|SysTick_CTRL_ENABLE_Msk // rapid blink
ldr r0, =SysTick_CTRL_ENABLE_Msk // slow blink (AHB clock/8)
str r0, [r1, #CTRL] // SysTick Control and Status Register CSR
a: ldr r0, [r1, #CTRL]
tst r0, #SysTick_CTRL_COUNTFLAG_Msk // wait until the countflag is set
beq a
ldr r0, =0
str r0, [r1, #CTRL]
bx lr
SYSCLK with interrupt
Interrupt belongs is a type of exception. An exception can be seen as a software interruption, created for example by a division by zero operation or a memory access violation. An interrupt is triggered by an hardware event, such as the push of a button.
Exceptions and interrupts interrupt normal program flow, and branch into an exception handler or Interrupt Service Routine (ISR).
Without interrupt, the microcontroller had to poll periodically the CTRL register bit 16 COUNTFLAG:
a: ldr r0, [r1, #CTRL]
tst r0, #SysTick_CTRL_COUNTFLAG_Msk
beq a
In the interrupt scheme, there is no such a waste of time.
You can enable the SysTick interrupt by setting the bit 1 TICKINT (SysTick exception request enable) of the CTRL register.
With STM MPU, exception handlers are implemented as regular functions, like Reset_Handler:
.type SysTick_Handler, %function
.global SysTick_Handler
SysTick_Handler:
...
bx lr
Until now, the vector table was defined as:
.word 0x20000400 // stack end
.word Reset_Handler
.space 0xf8
The first word contains the initial stack pointer address and the second word contains the address of the first instruction of the program (defined via ‘.word Reset_Handler’).
We now need to tell the MCU the address of the SysTick handler.
The first elements of the vector table in chapter 13.3 “Interrupt and exception vectors” of the reference manual shows this adddress:
The SysTick handler address is at location 0x3c.
The code becomes:
.word 0x20000400 // stack end
.word Reset_Handler // address 0x0004
.space 0x34
.word Systick_Handler // address 0x003c
.space 0xc0
After compilation and linking, with arm-none-eabi-objdump -d gpio.elf:
Disassembly of section .text:
08000000 <Reset_Handler-0x100>:
8000000: 20000400 andcs r0, r0, r0, lsl #8
8000004: 08000101 stmdaeq r0, {r0, r8}
...
800003c: 08000135 .word 0x08000135
The last line shows that we have indeed the correct address 800 003c (SysTick vector), with the Systick Handler beginning at address 800 0135.
ldr r0, =TimerValue
bl StartSysTick
SleepLoop:
wfi
b SleepLoop