NuttX에서 CPU freq/clock 가져오는 방법

임베디드 개발에서 성능 분석을 하다 보면 반드시 마주치는 질문이 있다.

"지금 CPU가 몇 MHz로 동작하고 있는가?"

특히 LVGL, UI 렌더링, 프레임 드랍 분석을 하려면 CPU 클럭 정보는 거의 필수다.

하지만 중요한 사실 하나:

NuttX에는 CPU 클럭을 가져오는 표준 API가 없다

이 글에서는 NuttX에서 CPU 클럭을 얻는 모든 방법을 정리한다.


1. 전체 구조 이해

CPU 클럭을 얻는 방법은 다음 4단계로 나뉜다.

  1. NuttX 공통 레벨
  2. Board / BSP 레벨
  3. SoC 클럭 드라이버
  4. Hardware Register 직접 접근

2. NuttX 공통 레벨 (거의 불가능)

clock_gettime()

가능한 것: - 시간 측정

불가능한 것: - CPU 클럭 확인


3. Board / BSP 레벨

보드에서 board_cpu_frequency() 같은 API를 제공해줄 수 있다. 문제는 보드마다 다를 수 있다는거..


4. SoC 클럭 드라이버 (추천)

SoC에서도 API를 제공해줄 수 있는데, DVFS도 반영되어있어 이걸 사용하는 것이 좋아보인다.

  • clk_get_rate()
  • CLOCK_GetFreq()
  • SystemCoreClock

5. Hardware Register 직접 읽기

직접 PLL / divider 계산해서 freq를 구하는 것이다. 가장 정확하겠지만, 구현하는게 어렵다.

uint32_t pll = readl(PLL_REG);
uint32_t div = readl(DIV_REG);

freq = pll / div;

장점:

  • 가장 정확

단점:

  • 구현 어려움

6. BES 계열에서 CPU Clock 가져오기

BES 계열은 보통 CMU (Clock Management Unit) API가 있음.

uint32_t hal_sysfreq_get(void);

아래 처럼 쓸 수 있다.

#include "hal_sysfreq.h"

uint32_t freq = hal_sysfreq_get();
printf("CPU freq: %u\n", freq);

리턴 값은 아래와 같은데,

typedef enum {
    HAL_CMU_FREQ_32K,
    HAL_CMU_FREQ_26M,
    HAL_CMU_FREQ_52M,
    HAL_CMU_FREQ_104M,
    HAL_CMU_FREQ_208M,
} HAL_CMU_FREQ_T;

이런 식으로 실제 MHz로 변환이 필요하다.

uint32_t freq_to_hz(enum HAL_CMU_FREQ_T f) {
    switch (f) {
        case HAL_CMU_FREQ_26M: return 26000000;
        case HAL_CMU_FREQ_52M: return 52000000;
        case HAL_CMU_FREQ_104M: return 104000000;
        case HAL_CMU_FREQ_208M: return 208000000;
        default: return 0;
    }
}

만약 이 API도 제공하고 있다면, 이건 바로 현재의 실제 클럭을 알려준다. 리턴 값을 클럭으로 변환하지 않아도 되고, 더 정확하다고 볼 수 있다.

uint32_t hal_cmu_get_sys_clock(void);

레지스터를 읽어서 계산할 수도 있겠지만, API가 제공되면 API를 사용하자.

pll = readl(PLL_CFG);
div = readl(CPU_DIV);

freq = (XTAL * pll_mult) / div;

상위 레이어의 앱에서는 아래와 같이 하위 레이어의 API를 호출하여 freq를 계산하고 로그로 출력할 수 있다.

void log_frame_info(void)
{
    uint32_t freq = hal_sysfreq_get();
    uint32_t cycles = DWT->CYCCNT;

    printf("freq=%u, cycles=%u\n", freq, cycles);
}

또는,

start = DWT->CYCCNT;

lv_timer_handler();

end = DWT->CYCCNT;

freq = hal_sysfreq_get();

printf("freq=%u Hz, frame_cycles=%u\n", freq, end - start);

CPU 클럭은 높은데, 느린거 같다면? BUS 클럭이 낮을 수도 있다. BUS bottleneck을 의심하자.


7. 결론

  • NuttX에는 CPU 클럭 API 없음
  • SoC/보드에서 가져와야 함
  • 실전은 clk driver + cycle counter 조합