기술 가이드

RP2040 PWM 주파수 계산: 분주·TOP·듀티 1 kHz와 20 kHz 예제

RP2040의 8:4 분주와 TOP+1 카운트를 공식 문서·C 계산 예제로 확인합니다.

목차

RP2040에서 PWM 주파수를 맞출 때 TOP=주파수로 나눈 값으로만 계산하면 한 카운트가 어긋납니다. 카운터는 0부터 TOP까지 세므로 한 주기는 TOP+1 카운트입니다. Raspberry Pi의 RP2040 데이터시트와 공식 Pico SDK PWM 헤더를 기준으로, 125 MHz 클록에서 1 kHz·20 kHz를 만드는 값을 계산해 봅니다.

1. 주파수 식과 적용 조건

기본적인 free-running, trailing-edge PWM에서 f_PWM = f_clk_sys / (DIV × (TOP+1))입니다. DIV는 8비트 정수부와 4비트 소수부를 가진 분주 값으로, 2 + 0/16은 정확히 2입니다. TOP은 16비트 wrap 값이므로 0부터 65535까지 설정할 수 있습니다. 분주가 1일 때 PWM 카운터는 시스템 클록마다 증가합니다.

이 식은 phase-correct 모드를 끈 상태에 적용합니다. SDK는 phase-correct 모드가 PWM 주파수를 절반으로 낮춘다고 설명합니다. B 핀 입력으로 카운트를 제어하는 모드에도 같은 계산을 그대로 적용할 수 없습니다. 실제 clk_sys는 프로젝트의 클록 설정에 따라 다를 수 있으니 보드에서는 clock_get_hz(clk_sys)로 확인하세요.

2. 1 kHz와 20 kHz 계산

예시의 clk_sys=125,000,000 Hz에서 1 kHz를 원한다면 DIV=2, TOP+1=62,500이므로 TOP=62,499입니다. 같은 클록에서 20 kHz는 DIV=1, TOP+1=6,250이므로 TOP=6,249입니다.

목표 DIV TOP 계산 주파수
1 kHz 2 62499 1000 Hz
20 kHz 1 6249 20000 Hz

1 kHz 설정에서 채널의 compare level을 31,250으로 주면 31,250 / 62,500 = 50%입니다. 두 출력 채널 A·B는 같은 PWM 슬라이스의 분주와 TOP을 공유하므로 주파수를 따로 정할 수 없습니다. 듀티는 각 채널의 level로 조절합니다. 설정값을 바꾼 직후의 첫 주기는 기존 카운터 상태의 영향을 받을 수 있으므로, 파형을 측정할 때는 안정된 연속 주기를 확인하세요.

3. PC에서 계산 검증

다음 표준 C 예제는 레지스터를 건드리지 않는 계산 테스트입니다. pwm_frequency.c로 저장하고 gcc -std=c11 -Wall -Wextra -Werror pwm_frequency.c -o pwm_frequency로 빌드한 뒤 실행하세요. div16은 실제 분주 값의 16배입니다.

#include <assert.h>
#include <stdint.h>
#include <stdio.h>

static double pwm_hz(uint32_t clk_hz, uint32_t div16, uint32_t top) {
/* RP2040 free-running PWM: divider is an 8:4 fixed-point value. */
return (double)clk_hz * 16.0 / ((double)div16 * (top + 1.0));
}

int main(void) {
const uint32_t clk_hz = 125000000;
const uint32_t div16_1k = 32; /* 2 + 0/16 */
const uint32_t top_1k = 62499;
const uint32_t level_1k = 31250;
const uint32_t div16_20k = 16; /* 1 + 0/16 */
const uint32_t top_20k = 6249;

assert(top_1k <= UINT16_MAX && top_20k <= UINT16_MAX);
assert(level_1k <= top_1k + 1);
assert(pwm_hz(clk_hz, div16_1k, top_1k) == 1000.0);
assert(pwm_hz(clk_hz, div16_20k, top_20k) == 20000.0);
assert((double)level_1k / (top_1k + 1) == 0.5);

printf("1 kHz: divider=2, TOP=%u, level=%u, duty=50%%\n",
top_1k, level_1k);
printf("20 kHz: divider=1, TOP=%u\n", top_20k);
puts("PASS: frequency and duty calculations");
return 0;
}

예상 출력:

1 kHz: divider=2, TOP=62499, level=31250, duty=50%
20 kHz: divider=1, TOP=6249
PASS: frequency and duty calculations

예제의 PASS는 식과 두 설정값만 검증합니다. 보드의 실제 클록, 핀 다중화, 배선 및 오실로스코프 파형까지 검증한 결과는 아닙니다.

4. Pico SDK에 적용하고 실측하기

SDK에서는 PWM 핀을 설정한 뒤 pwm_config_set_clkdiv_int_frac4(&amp;config, 2, 0)와 pwm_config_set_wrap(&amp;config, 62499)로 1 kHz 조건을 구성할 수 있습니다. pwm_init(slice, &amp;config, true)로 시작하고 pwm_set_chan_level(slice, channel, 31250)으로 50% compare 값을 설정합니다. 공식 Pico SDK PWM 헤더에서 각 함수의 인자와 해당 보드 SDK 버전을 확인하세요.

  1. clock_get_hz(clk_sys)가 예시의 125 MHz인지 확인하고 다르면 식으로 TOP을 다시 계산합니다.
  2. TOP이 16비트 범위인지, level이 의도한 듀티인지 확인합니다. 주파수가 높아질수록 사용할 수 있는 카운트 수가 줄어 듀티 분해능도 낮아집니다.
  3. 오실로스코프로 핀의 연속 주기와 HIGH 시간을 측정합니다. 모터·LED 드라이버 입력이라면 부하 회로의 전기적 제한도 별도로 확인합니다.

공식 참고: RP2040 데이터시트, Raspberry Pi Pico SDK hardware_pwm 헤더.

관련 글

댓글

첫 댓글을 남겨 보세요.

관리자 확인 후 게시됩니다.

처리 중입니다...

잠시만 기다려주세요.