Bare metal C Ch08 SysTick - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki
목표
빈 loop delay 대신 Cortex-M4 core의 SysTick timer를 사용해 millisecond 단위 delay를 구현한다.
SysTick은 STM32 vendor peripheral이 아니라 ARM Cortex-M core에 포함된 system timer다.
CMSIS | 역할 -- | -- SysTick->CTRL | Enable / Clock source / Count flag SysTick->LOAD | Reload value SysTick->VAL | Current counter SysTick->CALIB | Calibration
SysTick은 24-bit down counter다.
bit 0 ENABLE
bit 1 TICKINT
bit 2 CLKSOURCE
bit 16 COUNTFLAG
이번 실습은 polling 방식이므로 TICKINT는 사용하지 않는다.
Project 기록의 system clock은 16 MHz다.
16,000,000 × 0.001
= 16,000 cycles
따라서:
LOAD = 16000 - 1
= 15999
while ((SysTick->CTRL & CTRL_COUNTFLAG) == 0UL)
{
}
Notion에서는 COUNTFLAG를 읽으면 clear되는 SysTick 특성을 핵심 포인트로 정리했다.
Ch08_systick/
├── Inc/
│ ├── gpio.h
│ └── systick.h
└── Src/
├── gpio.c
├── systick.c
└── main.c
#ifndef GPIO_H
#define GPIO_H
#include <stdbool.h>
/* ---- LED (PB0, LD1 녹색) ---- */
void led_init(void);
void led_on(void);
void led_off(void);
/* ---- Push Button (PC13, B1) ---- */
void button_init(void);
bool get_btn_state(void);
void led_toggle(void); /* Ch08에서 추가 */
#endif /* GPIO_H */
#include "stm32f4xx.h"
#include "gpio.h"
#define LED_PIN 0U /* PB0 = LD1 (녹색) /
#define BTN_PIN 13U / PC13 = B1 */
void led_init(void)
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
GPIOB->MODER &= ~(0x3UL << (LED_PIN * 2));
GPIOB->MODER |= (0x1UL << (LED_PIN * 2));
}
void led_on(void)
{
GPIOB->BSRR = (1UL << LED_PIN); /* Set */
}
void led_off(void)
{
GPIOB->BSRR = (1UL << (LED_PIN + 16)); /* Reset */
}
void button_init(void)
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
GPIOC->MODER &= ~(0x3UL << (BTN_PIN * 2)); /* Input */
GPIOC->PUPDR &= ~(0x3UL << (BTN_PIN * 2)); /* No pull (보드가 자체 처리) */
}
bool get_btn_state(void)
{
return (GPIOC->IDR & (1UL << BTN_PIN)) != 0U; /* active-HIGH */
}
void led_toggle(void)
{
GPIOB->ODR ^= (1UL << 0); /* PB0 = LD1 */
}
#ifndef SYSTICK_H_
#define SYSTICK_H_
#include <stdint.h>
#include "stm32f4xx.h"
void systick_msec_delay(uint32_t delay);
#endif /* SYSTICK_H_ */
#include "systick.h"
#define CTRL_ENABLE (1UL << 0)
#define CTRL_CLKSRC (1UL << 2)
#define CTRL_COUNTFLAG (1UL << 16)
/* 코어클럭 16MHz(기본 HSI) 기준 1ms당 클럭 사이클 수 */
#define ONE_MSEC_LOAD 16000UL
void systick_msec_delay(uint32_t delay)
{
SysTick->LOAD = ONE_MSEC_LOAD - 1UL;
SysTick->VAL = 0UL;
SysTick->CTRL = CTRL_CLKSRC;
SysTick->CTRL |= CTRL_ENABLE;
for (uint32_t i = 0; i < delay; i++)
{
while ((SysTick->CTRL & CTRL_COUNTFLAG) == 0UL) { }
}
SysTick->CTRL = 0UL;
}
#include "gpio.h"
#include "systick.h"
int main(void)
{
led_init();
while (1)
{
systick_msec_delay(500);
led_toggle();
}
}
LOAD = 15999
│
▼
VAL = 0
│
▼
CLKSOURCE 설정
│
▼
ENABLE
│
▼
COUNTFLAG polling
│
├─ 1 ms 완료
│
└─ delay 횟수만큼 반복
│
▼
SysTick disable
systick_msec_delay(500);
은 1 ms 완료를 500번 반복해서 500 ms delay를 만든다.
BSRR에는 toggle 기능이 없으므로:
GPIOB->ODR ^= (1UL << 0);
으로 PB0 bit를 XOR toggle한다.
Cortex-M4 Core
│
▼
SysTick 24-bit Counter
│
▼
1 ms COUNTFLAG
│
▼
500회 반복
│
▼
led_toggle()
│
▼
GPIOB ODR bit0
│
▼
LD1 Toggle
Notion 기록:
text = 764 bytes
data = 0 bytes
bss = 2560 bytes
warning 없음
SysTick은 Cortex-M core peripheral이다.
16 MHz에서 1 ms는 16,000 cycle이다.
Reload value는
16000 - 1을 사용한다.COUNTFLAG polling으로 delay를 구현한다.
GPIO/TIM 같은 STM32 peripheral과 달리 SysTick은 ARM core 공통 기능이다.