Chapter 08 - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki

08. SysTick Timer

Goal

Ch02~07์—์„œ ์‚ฌ์šฉํ–ˆ๋˜ ๋‹จ์ˆœ loop delay ๋Œ€์‹  Cortex-M4 ๋‚ด๋ถ€์˜ SysTick timer๋ฅผ ์ด์šฉํ•ด millisecond ๋‹จ์œ„ delay๋ฅผ ๋งŒ๋“ ๋‹ค.

์ด๋ฒˆ ์‹ค์Šต:

System Clock = 16 MHz
        โ†“
SysTick 16000 clocks
        โ†“
1 ms
        โ†“
500ํšŒ ๋ฐ˜๋ณต
        โ†“
500 ms delay
        โ†“
LD1 Toggle

ํ•ต์‹ฌ register:

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

1. SysTick

SysTick์€ STM32 ์ „์šฉ peripheral์ด ์•„๋‹ˆ๋ผ ARM Cortex-M core ๋‚ด๋ถ€ timer๋‹ค.

Cortex-M4 Core
โ”‚
โ”œโ”€โ”€ NVIC
โ”œโ”€โ”€ SysTick
โ”œโ”€โ”€ Debug
โ””โ”€โ”€ CPU

๋”ฐ๋ผ์„œ GPIO๋‚˜ USART์ฒ˜๋Ÿผ ST๊ฐ€ ๋งŒ๋“  peripheral๊ณผ ์„ฑ๊ฒฉ์ด ๋‹ค๋ฅด๋‹ค.

SysTick
โ†’ Cortex-M ๊ณตํ†ต

TIM2, TIM3 ... โ†’ STM32 Peripheral


2. SysTick Registers

Register ์—ญํ• 
SysTick->CTRL Timer enable, clock source, status
SysTick->LOAD Reload value
SysTick->VAL ํ˜„์žฌ counter value
SysTick->CALIB Calibration information

SysTick์€ 24-bit down counter๋‹ค.

๋™์ž‘:

LOAD
 โ†“
15999
 โ†“
15998
 โ†“
...
 โ†“
1
 โ†“
0
 โ†“
COUNTFLAG = 1
 โ†“
Reload

3. CTRL Important Bits

์ด๋ฒˆ ์‹ค์Šต์—์„œ ์‚ฌ์šฉํ•˜๋Š” bit:

#define CTRL_ENABLE     (1UL << 0)
#define CTRL_CLKSRC     (1UL << 2)
#define CTRL_COUNTFLAG  (1UL << 16)

์˜๋ฏธ:

bit 0  ENABLE
       1 = SysTick counter enable

bit 1 TICKINT 1 = SysTick interrupt enable ์ด๋ฒˆ ์‹ค์Šต์—์„œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ

bit 2 CLKSOURCE 1 = Processor clock ์‚ฌ์šฉ

bit16 COUNTFLAG Counter๊ฐ€ 0๊นŒ์ง€ ๋‚ด๋ ค๊ฐ€๋ฉด 1

์ด๋ฒˆ ์‹ค์Šต์€ interrupt ๋ฐฉ์‹์ด ์•„๋‹ˆ๋ผ:

COUNTFLAG Polling

๋ฐฉ์‹์ด๋‹ค.


4. 1 ms Reload Calculation

ํ˜„์žฌ Bare-Metal project์˜ core clock์€:

16 MHz

์ด๋‹ค.

์ฆ‰:

16,000,000 clocks / second

1 ms๋Š”:

1 ms

0.001 second

๋”ฐ๋ผ์„œ:

16,000,000 ร— 0.001

16,000 clocks

SysTick์€ 0๊นŒ์ง€ ํฌํ•จํ•ด์„œ countํ•˜๋ฏ€๋กœ:

LOAD = 16000 - 1
= 15999

๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

#define ONE_MSEC_LOAD 16000UL

๊ทธ๋ฆฌ๊ณ  ์‹ค์ œ register์—๋Š”:

SysTick->LOAD = ONE_MSEC_LOAD - 1UL;

์„ ๋„ฃ๋Š”๋‹ค.


5. Why 16 MHz?

์ด Bare-Metal project์—์„œ๋Š” ๋ณ„๋„๋กœ PLL์„ ์„ค์ •ํ•˜๋Š” SystemClock_Config()๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค.

๋”ฐ๋ผ์„œ clock์€ reset ๊ธฐ๋ณธ HSI๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

HSI
โ†“
16 MHz
โ†“
System Clock

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ์ ์€ ๋‹ค๋ฅธ STM32 ์‹ค์Šต์—์„œ ์‚ฌ์šฉํ–ˆ๋˜:

168 MHz

์„ค์ •๊ณผ ์„ž์œผ๋ฉด ์•ˆ ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์ด Bare-Metal Wiki ๊ธฐ์ค€:

Core Clock = 16 MHz

์ด๋‹ค.


6. Practice Code

Notion ์›๋ณธ์—๋Š” systick_msec_delay()์™€ main.c ํ•ต์‹ฌ ์ฝ”๋“œ๊ฐ€ ๊ธฐ๋ก๋˜์–ด ์žˆ๋‹ค. ์•„๋ž˜๋Š” ์ด๋ฅผ ์‹ค์ œ project์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ๋„๋ก systick.h / systick.c / main.c ๊ตฌ์กฐ๋กœ ์ •๋ฆฌํ•œ ๊ฒƒ์ด๋‹ค.

Project:

Inc/
โ”œโ”€โ”€ gpio.h
โ””โ”€โ”€ systick.h

Src/ โ”œโ”€โ”€ gpio.c โ”œโ”€โ”€ systick.c โ””โ”€โ”€ main.c


systick.h

#ifndef SYSTICK_H__
#define SYSTICK_H__

#include <stdint.h>

/*

  • Delay execution for the requested number of milliseconds.
  • This implementation assumes:
  • Core Clock = 16 MHz
    
  • Example:
  • systick_msec_delay(500);
    
  • โ†’ approximately 500 ms delay
    

*/ void systick_msec_delay(uint32_t delay);

#endif


7. systick.c

#include "stm32f4xx.h"
#include "systick.h"

/*

  • ============================================================
  • SysTick CTRL Register Bit Definitions
  • ============================================================ */

/*

  • SysTick CTRL bit0 : ENABLE
  • 0 = Counter disabled
  • 1 = Counter enabled */ #define CTRL_ENABLE (1UL << 0)

/*

  • SysTick CTRL bit2 : CLKSOURCE
  • 0 = External/reference clock
  • 1 = Processor clock
  • This project uses the processor clock. */ #define CTRL_CLKSRC (1UL << 2)

/*

  • SysTick CTRL bit16 : COUNTFLAG
  • Hardware sets this flag when the SysTick counter
  • counts down to zero.
  • The delay routine polls this bit to detect
  • the completion of each 1 ms period. */ #define CTRL_COUNTFLAG (1UL << 16)

/*

  • ============================================================
  • SysTick Timing Definition
  • ============================================================ */

/*

  • Current core clock:
  • 16 MHz = 16,000,000 clocks/sec
    
  • Number of clocks in 1 ms:
  • 16,000,000 ร— 0.001
    
  • = 16,000 clocks
    
  • SysTick counts:
  • LOAD โ†’ ... โ†’ 1 โ†’ 0
    
  • Therefore the actual value written to LOAD is:
  • 16,000 - 1
    
  • = 15,999
    

*/ #define ONE_MSEC_LOAD 16000UL

/*

  • ============================================================
  • Millisecond Delay
  • ============================================================ */

void systick_msec_delay(uint32_t delay) { /* * -------------------------------------------------------- * Step 1. Set reload value * -------------------------------------------------------- * * ONE_MSEC_LOAD = 16000 * * LOAD = 15999 * * With a 16 MHz processor clock, * this produces one 1 ms counting period. */ SysTick->LOAD = ONE_MSEC_LOAD - 1UL;

/*
 * --------------------------------------------------------
 * Step 2. Clear current counter value
 * --------------------------------------------------------
 *
 * Writing to VAL clears the current SysTick counter.
 *
 * This ensures that the delay starts from
 * a known counter state.
 */
SysTick-&gt;VAL = 0UL;


/*
 * --------------------------------------------------------
 * Step 3. Select SysTick clock source
 * --------------------------------------------------------
 *
 * CTRL_CLKSRC = bit2 = 1
 *
 * Use processor clock as the SysTick source.
 *
 * Note:
 * TICKINT(bit1) is NOT enabled.
 *
 * Therefore this implementation does not use
 * SysTick interrupts.
 */
SysTick-&gt;CTRL = CTRL_CLKSRC;


/*
 * --------------------------------------------------------
 * Step 4. Enable SysTick
 * --------------------------------------------------------
 *
 * Set CTRL bit0.
 *
 * SysTick now starts counting down.
 */
SysTick-&gt;CTRL |= CTRL_ENABLE;


/*
 * --------------------------------------------------------
 * Step 5. Repeat 1 ms delay
 * --------------------------------------------------------
 *
 * Example:
 *
 *     delay = 500
 *
 * The outer for-loop repeats 500 times.
 *
 * Each iteration waits for one SysTick period:
 *
 *     1 ms ร— 500
 *     = 500 ms
 */
for (uint32_t i = 0; i &lt; delay; i++)
{
    /*
     * Wait until COUNTFLAG becomes 1.
     *
     * While counter has NOT yet reached zero:
     *
     *     COUNTFLAG = 0
     *
     * so CPU remains in this while-loop.
     *
     * Once counter reaches zero:
     *
     *     COUNTFLAG = 1
     *
     * and the while-loop terminates.
     *
     * This is polling.
     */
    while ((SysTick-&gt;CTRL &amp; CTRL_COUNTFLAG) == 0UL)
    {
        /*
         * Busy wait.
         *
         * CPU performs no other useful work here.
         */
    }
}


/*
 * --------------------------------------------------------
 * Step 6. Stop SysTick
 * --------------------------------------------------------
 *
 * Clear CTRL register.
 *
 * ENABLE = 0
 * CLKSOURCE = 0
 * TICKINT = 0
 *
 * SysTick stops after the requested delay.
 */
SysTick-&gt;CTRL = 0UL;

}


8. main.c

#include "gpio.h"
#include "systick.h"

int main(void) { /* * Initialize LD1 GPIO. * * NUCLEO-F439ZI: * * LD1 โ†’ PB0 * * gpio.c configures PB0 as output. */ led_init();

while (1)
{
    /*
     * Wait 500 ms using the Cortex-M4 SysTick timer.
     *
     * Internally:
     *
     *     1 ms period
     *     ร—
     *     500 iterations
     *     =
     *     500 ms
     */
    systick_msec_delay(500);


    /*
     * Toggle PB0.
     *
     * GPIOB-&gt;ODR bit0:
     *
     *     0 โ†’ 1
     *     1 โ†’ 0
     *
     * Therefore LD1 changes state every 500 ms.
     */
    led_toggle();
}

}


9. Important Code Flow

systick_msec_delay(500):

LOAD = 15999
โ†“
VAL = 0
โ†“
CLKSOURCE = Core Clock
โ†“
ENABLE = 1
โ†“
Counter Starts
โ†“
15999 โ†’ ... โ†’ 0
โ†“
COUNTFLAG = 1
โ†“
1 ms complete
โ†“
Repeat 500 times
โ†“
500 ms complete
โ†“
CTRL = 0

Main:

led_init()
โ†“
500 ms delay
โ†“
LED toggle
โ†“
500 ms delay
โ†“
LED toggle
โ†“
...

10. Why for + while?

ํ•ต์‹ฌ ์ฝ”๋“œ:

for (uint32_t i = 0; i < delay; i++)
{
while ((SysTick->CTRL & CTRL_COUNTFLAG) == 0UL)
{
}
}

๋‘ loop์˜ ์—ญํ• ์ด ๋‹ค๋ฅด๋‹ค.

while

1 ms๊ฐ€ ๋๋‚ฌ๋Š”๊ฐ€?

๋ฅผ ํ™•์ธํ•œ๋‹ค.

for

1 ms๋ฅผ ๋ช‡ ๋ฒˆ ๊ธฐ๋‹ค๋ฆด ๊ฒƒ์ธ๊ฐ€?

๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค.

์˜ˆ:

systick_msec_delay(500);

์ด๋ฉด:

1 ms ์™„๋ฃŒ ํ™•์ธ
ร—
500ํšŒ

500 ms

๊ฐ€ ๋œ๋‹ค.


11. COUNTFLAG

Counter๊ฐ€ zero์— ๋„๋‹ฌํ•˜๋ฉด:

CTRL[16] = 1

์ฆ‰:

COUNTFLAG = 1

์ด ๋œ๋‹ค.

์ฝ”๋“œ๋Š”:

while ((SysTick->CTRL & CTRL_COUNTFLAG) == 0UL)
{
}

๋กœ ์ด๋ฅผ pollingํ•œ๋‹ค.

Notion ์‹ค์Šต ๊ธฐ๋ก์—์„œ๋Š” COUNTFLAG๋ฅผ ์ฝ์œผ๋ฉด ๋‹ค์Œ ์ฃผ๊ธฐ ํ™•์ธ์„ ์œ„ํ•ด flag๊ฐ€ clear๋˜๋Š” ๋™์ž‘์„ ์ด์šฉํ–ˆ๋‹ค.


12. Why VAL = 0?

SysTick->VAL = 0UL;

์€ ๋‹จ์ˆœํžˆ C variable์— 0์„ ์ €์žฅํ•˜๋Š” ๊ฐœ๋…๊ณผ ์กฐ๊ธˆ ๋‹ค๋ฅด๋‹ค.

SysTick์˜ VAL์— writeํ•˜๋ฉด current counter๊ฐ€ clear๋œ๋‹ค.

์ฆ‰:

Previous Counter State
โ†“
VAL Write
โ†“
Counter Clear
โ†“
Known Starting State

๋ฅผ ๋งŒ๋“ ๋‹ค.

๋”ฐ๋ผ์„œ ์ด์ „ SysTick ์‚ฌ์šฉ ์ƒํƒœ์— ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๊ณ  ์ƒˆ๋กœ์šด delay๋ฅผ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.


13. Why No TICKINT?

CTRL bit1์€:

TICKINT

์ด๋‹ค.

์ด๋ฅผ enableํ•˜๋ฉด counter๊ฐ€ zero๊ฐ€ ๋˜์—ˆ์„ ๋•Œ SysTick exception์„ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ํ˜„์žฌ ์ฝ”๋“œ๋Š”:

while ((SysTick->CTRL & CTRL_COUNTFLAG) == 0UL)

๋กœ ์ง์ ‘ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.

๋”ฐ๋ผ์„œ:

SysTick Interrupt
X

SysTick Polling O

์ด๋‹ค.


14. Busy Waiting

ํ˜„์žฌ delay์—์„œ๋Š” CPU๊ฐ€:

while ((SysTick->CTRL & CTRL_COUNTFLAG) == 0UL)
{
}

์•ˆ์—์„œ ๊ณ„์† ๊ธฐ๋‹ค๋ฆฐ๋‹ค.

์ฆ‰ 500ms ๋™์•ˆ CPU๋Š” ๋‹ค๋ฅธ application ์ž‘์—…์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค.

CPU
โ†“
Wait
โ†“
Wait
โ†“
Wait
โ†“
Timer Complete

์ด๋ฅผ:

Busy Waiting

์ด๋ผ๊ณ  ํ•œ๋‹ค.

๊ฐ„๋‹จํ•œ ์‹ค์Šต์—๋Š” ์ ํ•ฉํ•˜์ง€๋งŒ ๋ณต์žกํ•œ embedded system์—์„œ๋Š”:

Interrupt
RTOS Tick
State Machine
Non-blocking Timer

๋“ฑ์˜ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.


15. SysTick vs Software Delay

Ch02์—์„œ ์‚ฌ์šฉํ•œ delay:

while (count--)
{
asm("nop");
}

๋Š” ์ •ํ™•๋„๊ฐ€ compiler์™€ instruction execution์— ์˜ํ–ฅ์„ ๋ฐ›๋Š”๋‹ค.

Software Loop Delay

Compiler Optimization CPU Instruction Source Code โ†“ Delay ๋ณ€ํ™” ๊ฐ€๋Šฅ

SysTick:

Hardware Counter
โ†“
Clock ๊ธฐ์ค€์œผ๋กœ Count

์ด๋ฏ€๋กœ timing ๊ธฐ์ค€์ด ํ›จ์”ฌ ๋ช…ํ™•ํ•˜๋‹ค.


16. SysTick vs TIM

SysTick:

ARM Cortex-M Core
1๊ฐœ
๊ธฐ๋ณธ์ ์ธ system tick/delay ์šฉ๋„
24-bit down counter

General Purpose Timer:

STM32 Peripheral
์—ฌ๋Ÿฌ ๊ฐœ ์กด์žฌ
Prescaler
Auto Reload
PWM
Input Capture
Output Compare
Interrupt
...

๋‹ค์Œ Ch09์—์„œ๋Š”:

TIM2

๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•œ๋‹ค.


17. Build Result

๊ธฐ์กด ์‹ค์Šต์—์„œ ๊ธฐ๋กํ•œ ๊ฒฐ๊ณผ:

text = 764 bytes
data = 0 bytes
bss  = 2560 bytes

Warning ์—†์ด build๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ๋‹ค.


18. Verification

1. Build

make clean
make

ํ™•์ธ:

Build PASS

๊ธฐ๋ก๋œ size:

text = 764
data = 0
bss  = 2560

2. Debugger โ€” LOAD

systick_msec_delay()์— breakpoint๋ฅผ ๊ฑธ๊ณ :

SysTick->LOAD = ONE_MSEC_LOAD - 1UL;

์‹คํ–‰ ํ›„:

SysTick->LOAD

15999

์ธ์ง€ ํ™•์ธํ•œ๋‹ค.


3. Debugger โ€” VAL

timer ์‹คํ–‰ ์ค‘:

SysTick->VAL

์„ ํ™•์ธํ•œ๋‹ค.

๊ฐ’์ด:

15999
โ†“
...
โ†“
0

๋ฐฉํ–ฅ์œผ๋กœ ๊ฐ์†Œํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

SysTick์€ down counter์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.


4. Debugger โ€” CTRL

ํ™•์ธํ•  bit:

CTRL bit0
ENABLE

CTRL bit2 CLKSOURCE

CTRL bit16 COUNTFLAG

Timer ์‹คํ–‰ ์ค‘:

ENABLE    = 1
CLKSOURCE = 1

์ด์–ด์•ผ ํ•œ๋‹ค.


5. Board

Expected:

LD1 state change
every 500 ms

์ฆ‰ LED ์ „์ฒด ON/OFF cycle์€:

ON  500 ms
OFF 500 ms

Total period โ‰ˆ 1 second

์ด๋‹ค.


19. Screenshots to Add

images/ch08_build.png
images/ch08_systick_load.png
images/ch08_systick_val.png
images/ch08_systick_ctrl.png
images/ch08_led.gif

๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ฆ๊ฑฐ:

LOAD = 15999
+
VAL Down Counting
+
LD1 500 ms Toggle

20. Key Points

16 MHz
โ†“
16000 clocks
โ†“
1 ms
โ†“
COUNTFLAG
โ†“
500 repetitions
โ†“
500 ms
  • SysTick์€ STM32 peripheral์ด ์•„๋‹ˆ๋ผ Cortex-M core timer๋‹ค.

  • SysTick์€ 24-bit down counter๋‹ค.

  • LOAD๋Š” reload value๋ฅผ ์„ค์ •ํ•œ๋‹ค.

  • VAL์€ current counter์™€ ๊ด€๋ จ๋œ๋‹ค.

  • CTRL์—์„œ clock source์™€ counter enable์„ ์ œ์–ดํ•œ๋‹ค.

  • COUNTFLAG๋กœ counter๊ฐ€ zero์— ๋„๋‹ฌํ–ˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

  • 16MHz์—์„œ 1ms๋Š” 16,000 clock์ด๋‹ค.

  • ๋”ฐ๋ผ์„œ LOAD = 15999๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

  • ํ˜„์žฌ ๊ตฌํ˜„์€ interrupt๊ฐ€ ์•„๋‹Œ polling ๋ฐฉ์‹์ด๋‹ค.

  • systick_msec_delay(500)์€ 1ms period๋ฅผ 500ํšŒ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.

  • ์ด Bare-Metal project์˜ clock ๊ธฐ์ค€์€ 168MHz๊ฐ€ ์•„๋‹ˆ๋ผ 16MHz๋‹ค.

โš ๏ธ **GitHub.com Fallback** โš ๏ธ