Chapter 08 - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki
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->CALIBSysTick์ 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
| 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์ด๋ฒ ์ค์ต์์ ์ฌ์ฉํ๋ 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๋ฐฉ์์ด๋ค.
ํ์ฌ Bare-Metal project์ core clock์:
16 MHz์ด๋ค.
์ฆ:
16,000,000 clocks / second1 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;์ ๋ฃ๋๋ค.
์ด Bare-Metal project์์๋ ๋ณ๋๋ก PLL์ ์ค์ ํ๋ SystemClock_Config()๋ฅผ ํธ์ถํ์ง ์๋๋ค.
๋ฐ๋ผ์ clock์ reset ๊ธฐ๋ณธ HSI๋ฅผ ์ฌ์ฉํ๋ค.
HSI
โ
16 MHz
โ
System Clock์ฌ๊ธฐ์ ์ค์ํ ์ ์ ๋ค๋ฅธ STM32 ์ค์ต์์ ์ฌ์ฉํ๋:
168 MHz์ค์ ๊ณผ ์์ผ๋ฉด ์ ๋๋ค๋ ๊ฒ์ด๋ค.
์ด Bare-Metal Wiki ๊ธฐ์ค:
Core Clock = 16 MHz์ด๋ค.
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
#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
#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->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->CTRL = CTRL_CLKSRC;
/*
* --------------------------------------------------------
* Step 4. Enable SysTick
* --------------------------------------------------------
*
* Set CTRL bit0.
*
* SysTick now starts counting down.
*/
SysTick->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 < 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->CTRL & 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->CTRL = 0UL;
}
#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->ODR bit0:
*
* 0 โ 1
* 1 โ 0
*
* Therefore LD1 changes state every 500 ms.
*/
led_toggle();
}
}
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 = 0Main:
led_init()
โ
500 ms delay
โ
LED toggle
โ
500 ms delay
โ
LED toggle
โ
...ํต์ฌ ์ฝ๋:
for (uint32_t i = 0; i < delay; i++)
{
while ((SysTick->CTRL & CTRL_COUNTFLAG) == 0UL)
{
}
}๋ loop์ ์ญํ ์ด ๋ค๋ฅด๋ค.
1 ms๊ฐ ๋๋ฌ๋๊ฐ?๋ฅผ ํ์ธํ๋ค.
1 ms๋ฅผ ๋ช ๋ฒ ๊ธฐ๋ค๋ฆด ๊ฒ์ธ๊ฐ?๋ฅผ ๊ฒฐ์ ํ๋ค.
์:
systick_msec_delay(500);์ด๋ฉด:
1 ms ์๋ฃ ํ์ธ
ร
500ํ
500 ms
๊ฐ ๋๋ค.
Counter๊ฐ zero์ ๋๋ฌํ๋ฉด:
CTRL[16] = 1์ฆ:
COUNTFLAG = 1์ด ๋๋ค.
์ฝ๋๋:
while ((SysTick->CTRL & CTRL_COUNTFLAG) == 0UL)
{
}๋ก ์ด๋ฅผ pollingํ๋ค.
Notion ์ค์ต ๊ธฐ๋ก์์๋ COUNTFLAG๋ฅผ ์ฝ์ผ๋ฉด ๋ค์ ์ฃผ๊ธฐ ํ์ธ์ ์ํด flag๊ฐ clear๋๋ ๋์์ ์ด์ฉํ๋ค.
SysTick->VAL = 0UL;์ ๋จ์ํ C variable์ 0์ ์ ์ฅํ๋ ๊ฐ๋ ๊ณผ ์กฐ๊ธ ๋ค๋ฅด๋ค.
SysTick์ VAL์ writeํ๋ฉด current counter๊ฐ clear๋๋ค.
์ฆ:
Previous Counter State
โ
VAL Write
โ
Counter Clear
โ
Known Starting State๋ฅผ ๋ง๋ ๋ค.
๋ฐ๋ผ์ ์ด์ SysTick ์ฌ์ฉ ์ํ์ ์ํฅ์ ๋ฐ์ง ์๊ณ ์๋ก์ด delay๋ฅผ ์์ํ ์ ์๋ค.
CTRL bit1์:
TICKINT์ด๋ค.
์ด๋ฅผ enableํ๋ฉด counter๊ฐ zero๊ฐ ๋์์ ๋ SysTick exception์ ๋ฐ์์ํฌ ์ ์๋ค.
ํ์ง๋ง ํ์ฌ ์ฝ๋๋:
while ((SysTick->CTRL & CTRL_COUNTFLAG) == 0UL)๋ก ์ง์ ๊ธฐ๋ค๋ฆฐ๋ค.
๋ฐ๋ผ์:
SysTick Interrupt
X
SysTick Polling
O
์ด๋ค.
ํ์ฌ 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๋ฑ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์๋ค.
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 ๊ธฐ์ค์ด ํจ์ฌ ๋ช ํํ๋ค.
SysTick:
ARM Cortex-M Core
1๊ฐ
๊ธฐ๋ณธ์ ์ธ system tick/delay ์ฉ๋
24-bit down counterGeneral Purpose Timer:
STM32 Peripheral
์ฌ๋ฌ ๊ฐ ์กด์ฌ
Prescaler
Auto Reload
PWM
Input Capture
Output Compare
Interrupt
...๋ค์ Ch09์์๋:
TIM2๋ฅผ ์ง์ ์ฌ์ฉํ๋ค.
๊ธฐ์กด ์ค์ต์์ ๊ธฐ๋กํ ๊ฒฐ๊ณผ:
text = 764 bytes
data = 0 bytes
bss = 2560 bytesWarning ์์ด build๊ฐ ์๋ฃ๋์๋ค.
make clean
makeํ์ธ:
Build PASS๊ธฐ๋ก๋ size:
text = 764
data = 0
bss = 2560systick_msec_delay()์ breakpoint๋ฅผ ๊ฑธ๊ณ :
SysTick->LOAD = ONE_MSEC_LOAD - 1UL;์คํ ํ:
SysTick->LOAD
15999
์ธ์ง ํ์ธํ๋ค.
timer ์คํ ์ค:
SysTick->VAL์ ํ์ธํ๋ค.
๊ฐ์ด:
15999
โ
...
โ
0๋ฐฉํฅ์ผ๋ก ๊ฐ์ํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
SysTick์ down counter์ด๊ธฐ ๋๋ฌธ์ด๋ค.
ํ์ธํ bit:
CTRL bit0
ENABLE
CTRL bit2
CLKSOURCE
CTRL bit16
COUNTFLAG
Timer ์คํ ์ค:
ENABLE = 1
CLKSOURCE = 1์ด์ด์ผ ํ๋ค.
Expected:
LD1 state change
every 500 ms์ฆ LED ์ ์ฒด ON/OFF cycle์:
ON 500 ms
OFF 500 ms
Total period
โ 1 second
์ด๋ค.
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 Toggle16 MHz
โ
16000 clocks
โ
1 ms
โ
COUNTFLAG
โ
500 repetitions
โ
500 msSysTick์ 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๋ค.