개요
본 문서는 Microchip의 AVR128DA64/48/32/28 시리즈 마이크로컨트롤러의 클럭 컨트롤러(CLKCTRL)를 분석하고, 이를 활용한 범용 클럭 드라이버를 설계 및 구현한 내용을 다룹니다. AVR128DA 시리즈는 내부 고주파 오실레이터(OSCHF, 최대 24 MHz), 외부 클럭(EXTCLK, 최대 24 MHz), 32.768 kHz 오실레이터(OSC32K/XOSC32K), PLL(최대 48 MHz)을 제공하여 고성능, 저전력, 고속 PWM 등 다양한 애플리케이션 요구사항을 충족합니다. 본 드라이버는 시스템 클럭(CLK_MAIN), 주변 장치 클럭(CLK_PER), Timer Counter D 클럭(CLK_TCD), 실시간 클럭(CLK_RTC)을 유연하게 설정하며, _PROTECTED_WRITE를 사용한 Configuration Change Protection(CCP) 준수, 클럭 안정성 확인, 전력 최적화, 오토 튜닝 기능을 포함합니다. AVR128DA 전 제품군(64/48/32/28)에 호환되도록 설계되었으며, Microchip Studio 및 AVR-GCC 환경에서 쉽게 통합 가능합니다.
클럭 드라이버는 다음과 같은 기능을 제공합니다:
- 다양한 클럭 소스 지원: OSCHF(1~24 MHz), EXTCLK(최대 24 MHz), OSC32K/XOSC32K(32.768 kHz), PLL(최대 48 MHz).
- 프리스케일러: CLK_PER를 2~64배로 분주하여 전력과 성능 균형 조정.
- PLL: TCD 전용 48 MHz 클럭 생성으로 고속 PWM 및 타이밍 크리티컬 애플리케이션 지원.
- 오토 튜닝: XOSC32K를 기준으로 OSCHF 주파수 정확도 향상.
- CCP 보호: _PROTECTED_WRITE로 안전한 레지스터 수정.
- 전력 최적화: 불필요한 클럭 소스 비활성화 및 저전력 모드 지원.
- 안정성 확인: MCLKSTATUS로 클럭 소스 안정화 모니터링.
사양
AVR128DA 시리즈의 클럭 시스템 사양은 다음과 같습니다:
- 클럭 소스:
- OSCHF: 내부 고주파 오실레이터 (1, 2, 3, 4, 8, 12, 16, 20, 24 MHz).
- EXTCLK: 외부 클럭 입력 (최대 24 MHz, PF5 핀).
- OSC32K: 내부 32.768 kHz 오실레이터.
- XOSC32K: 외부 32.768 kHz 크리스털/클럭 (TOSC1/TOSC2, PF6/PF7).
- PLL: OSCHF 또는 EXTCLK를 기반으로 2x/3x 배율 (최대 48 MHz, TCD 전용).
- 클럭 도메인:
- CLK_MAIN: CPU, NVM, SRAM (최대 24 MHz).
- CLK_PER: 주변 장치 (최대 24 MHz, 프리스케일러로 조정).
- CLK_TCD: Timer Counter D (최대 48 MHz, PLL 기반).
- CLK_RTC: Real-Time Counter (32.768 kHz, OSC32K/XOSC32K).
- 프리스케일러: CLK_PER를 2X, 4X, 6X, 8X, 12X, 16X, 24X, 32X, 48X, 64X로 분주.
- 오토 튜닝: XOSC32K를 기준으로 OSCHF 주파수 자동 조정.
- 전력 최적화:
- Active, Idle, Standby, Power-Down 모드에서 클럭 소스 선택적 활성화/비활성화.
- RUNSTDBY 비트로 Standby 모드 동작 제어.
- CCP 보호: CLKCTRL 레지스터(MCLKCTRLA, MCLKCTRLB, OSCHFCTRLA, PLLCTRLA, XOSC32KCTRLA)는 _PROTECTED_WRITE로 수정.
- 안정성 확인: CLKCTRL.MCLKSTATUS로 OSCHF, EXTCLK, XOSC32K, PLL 안정화 상태 확인.
- 전압 범위: 1.8V ~ 5.5V (VDD).
- 리셋 상태:
- CLK_MAIN = OSCHF 4 MHz.
- 프리스케일러 비활성화 (PEN=0).
- PLL 비활성화 (MULFAC=0x0).
- XOSC32K, OSC32K 비활성화 (ENABLE=0).
48 MHz PLL의 중요성
PLL은 OSCHF(최대 24 MHz) 또는 EXTCLK를 입력으로 받아 최대 48 MHz 클럭을 생성하며, 주로 TCD에 사용됩니다. 이는 다음과 같은 이유로 중요합니다:
- 고속 PWM: 48 MHz는 24 MHz보다 2배 높은 타이밍 해상도(20.83 ns vs 41.67 ns)를 제공, 모터 제어 및 LED 디밍에 적합.
- 비동기 동작: TCD는 CLK_MAIN과 독립적으로 CLK_TCD(48 MHz)를 사용하여 CPU 부담 없이 고속 작업 수행.
- 비용 효율성: 외부 48 MHz 크리스털 없이 PLL로 고주파 생성, BOM(Bill of Materials) 비용 절감.
- 활용 사례:
- BLDC 모터 제어: 고속 PWM으로 정밀 속도 조절.
- 고속 통신: SPI/UART 데이터 전송 속도 향상.
- LED 디밍: 깜박임 없는 고주파 PWM.
레지스터 설정 상세
클럭 시스템은 CLKCTRL 모듈의 레지스터를 통해 제어됩니다. 데이터시트(DS40002183A)의 Register Summary에 따라 주요 레지스터와 비트필드는 다음과 같습니다.
- CLKCTRL.MCLKCTRLA (0x00):
- 비트 [7]: CLKOUT (CLK_PER를 PA7 핀으로 출력, 0=비활성, 1=활성).
- 비트 [1:0]: CLKSEL[1:0] (클럭 소스: 0x0=OSCHF, 0x1=OSC32K, 0x2=XOSC32K, 0x3=EXTCLK).
- 리셋: 0x00, 읽기/쓰기(R/W), CCP 보호.
- CLKCTRL.MCLKCTRLB (0x01):
- 비트 [4]: PEN (프리스케일러 활성화, 0=비활성, 1=활성).
- 비트 [3:0]: PDIV[3:0] (분주비: 0x0=2X, 0x1=4X, 0x2=6X, …, 0xF=64X).
- 리셋: 0x00, R/W, CCP 보호.
- CLKCTRL.MCLKLOCK (0x02):
- 비트 [0]: LOCKEN (클럭 설정 잠금, 0=비활성, 1=활성, 해제 불가).
- 리셋: 0x00, R/W, CCP 보호.
- CLKCTRL.MCLKSTATUS (0x03):
- 비트 [7]: SOSC (클럭 소스 전환 진행 중, 1=진행 중).
- 비트 [4]: EXTS (EXTCLK 안정화 상태, 1=안정).
- 비트 [3]: XOSC32KS (XOSC32K 안정화 상태, 1=안정).
- 비트 [2]: OSC32KS (OSC32K 안정화 상태, 1=안정).
- 비트 [1]: OSCHFS (OSCHF 안정화 상태, 1=안정).
- 비트 [0]: PLLS (PLL 안정화 상태, 1=안정).
- 리셋: 0x00, 읽기 전용(R).
- CLKCTRL.OSCHFCTRLA (0x08):
- 비트 [7]: RUNSTDBY (Standby 모드에서 OSCHF 동작, 0=비활성, 1=활성).
- 비트 [6]: AUTOTUNE (XOSC32K 기반 오토 튜닝, 0=비활성, 1=활성).
- 비트 [4:0]: FRQSEL[4:0] (주파수: 0x1=1 MHz, 0x5=8 MHz, 0x7=16 MHz, 0x8=20 MHz, 0x9=24 MHz).
- 리셋: 0x02 (4 MHz), R/W, CCP 보호.
- CLKCTRL.PLLCTRLA (0x0C):
- 비트 [7]: RUNSTDBY (Standby 모드에서 PLL 동작, 0=비활성, 1=활성).
- 비트 [6:4]: MULFAC[2:0] (배율: 0x0=비활성, 0x2=2x, 0x3=3x).
- 비트 [1:0]: SOURCE[1:0] (소스: 0x0=OSCHF, 0x1=EXTCLK).
- 리셋: 0x00, R/W, CCP 보호.
- CLKCTRL.XOSC32KCTRLA (0x18):
- 비트 [7]: RUNSTDBY (Standby 모드에서 XOSC32K 동작, 0=비활성, 1=활성).
- 비트 [3]: SEL (소스: 0=외부 크리스털, 1=외부 클럭).
- 비트 [2:1]: CSUT[1:0] (시작 시간: 0x0=1k, 0x1=16k, 0x2=32k, 0x3=64k 사이클).
- 비트 [0]: ENABLE (활성화, 0=비활성, 1=활성).
- 리셋: 0x00, R/W, CCP 보호.
클럭 설정 절차
클럭 설정은 다음 순서로 진행합니다:
- 클럭 소스 선택: 애플리케이션 요구사항에 따라 OSCHF, EXTCLK, OSC32K, XOSC32K 중 하나를 선택.
- 클럭 주파수 설정: OSCHFCTRLA로 OSCHF 주파수(1~24 MHz) 설정 또는 XOSC32K 활성화.
- 오토 튜닝 (옵션): XOSC32K를 기준으로 OSCHF 주파수 정확도 향상.
- 프리스케일러 설정: MCLKCTRLB로 CLK_PER 분주 설정(예: 24 MHz → 12 MHz).
- PLL 설정 (옵션): PLLCTRLA로 TCD용 48 MHz 클럭 생성.
- CCP 보호: _PROTECTED_WRITE를 사용하여 보호된 레지스터(MCLKCTRLA, MCLKCTRLB, OSCHFCTRLA, PLLCTRLA, XOSC32KCTRLA) 수정.
- 안정성 확인: MCLKSTATUS 레지스터의 OSCHFS, EXTS, XOSC32KS, PLLS 비트로 클럭 소스 안정화 확인.
- 클럭 잠금 (옵션): MCLKLOCK으로 설정 잠금(소프트웨어 수정 방지).
- 테스트: CLK_PER, CLK_TCD, CLK_RTC 동작 확인(예: UART 보드레이트, TCD PWM, RTC 타이밍).
클럭 설정 고려사항
- CCP 보호: _PROTECTED_WRITE를 사용하여 CLKCTRL 레지스터를 수정해야 함. 미사용 시 쓰기 작업 무시.
- 클럭 안정성: MCLKSTATUS로 각 클럭 소스(OSCHFS, EXTS, XOSC32KS, PLLS)의 안정화 상태 확인.
- 프리스케일러: CLK_PER는 데이터시트의 Electrical Characteristics에 명시된 최대 주파수(24 MHz) 이하로 설정.
- PLL 제한: PLL은 입력 클럭이 16 MHz 이상이어야 하며, 출력은 TCD 전용(최대 48 MHz).
- 전력 최적화:
- 사용하지 않는 클럭 소스는 ENABLE=0, RUNSTDBY=0으로 비활성화.
- 저전력 모드(Power-Down)에서는 OSC32K/XOSC32K 사용.
- 오토 튜닝: XOSC32K 연결 시 TOSC1/TOSC2(PF6/PF7) 핀에 32.768 kHz 크리스털 필수.
- 애플리케이션별 최적화:
- 고성능: 24 MHz OSCHF/EXTCLK (예: 데이터 처리, 고속 통신).
- 저전력: 32.768 kHz OSC32K/XOSC32K (예: RTC, IoT 디바이스).
- 고속 PWM: 48 MHz PLL for TCD (예: 모터 제어, LED 디밍).
- 핀 설정: XOSC32K 사용 시 TOSC1/TOSC2(PF6/PF7) 설정 확인, EXTCLK는 PF5 사용.
- 전력 소모 분석:
- 24 MHz OSCHF: ~5 mA (VDD=5V, Active 모드).
- 8 MHz OSCHF: ~2 mA.
- 32.768 kHz XOSC32K: ~1 µA (Power-Down 모드).
- PLL(48 MHz): ~1 mA 추가 소모.
드라이버 구현 내용
클럭 드라이버는 AVR128DA64/48/32/28 호환으로 설계되었으며, 클럭 설정을 추상화합니다. 주요 구현은 다음과 같습니다:
- 클럭 소스 설정: OSCHF(1~24 MHz), EXTCLK(최대 24 MHz), OSC32K/XOSC32K(32.768 kHz) 설정 함수.
- 프리스케일러: CLK_PER 분주 설정(2X~64X)으로 전력과 성능 균형 조정.
- PLL: TCD용 48 MHz 클럭 생성, 2x/3x 배율 지원.
- 오토 튜닝: XOSC32K 기반 OSCHF 주파수 정확도 향상.
- CCP 보호: _PROTECTED_WRITE로 보호된 레지스터 안전 수정.
- 안정성 확인: MCLKSTATUS로 클럭 소스 및 PLL 안정화 모니터링.
- 전력 최적화: 클럭 소스 및 PLL 비활성화 함수.
- 호환성: <avr/io.h>로 모델별 클럭 정의 지원.
- 상태 조회: 현재 클럭 소스 및 주파수 확인 함수.
사용방법
클럭 드라이버를 효과적으로 사용하기 위해 아래의 상세한 가이드를 따르세요. 이 섹션은 초보자와 숙련자 모두를 위해 단계별 설정 절차, 프로젝트 통합 방법, 디버깅 및 테스트 방법, 그리고 일반적인 문제 해결 팁을 포함합니다.
1. 프로젝트 설정
- 필수 헤더 파일 포함:
- 프로젝트에 clock_driver.h, <avr/io.h>, <avr/cpufunc.h>를 포함하세요.
- <avr/io.h>는 AVR128DA 시리즈의 레지스터 정의를 제공합니다.
- <avr/cpufunc.h>는 _PROTECTED_WRITE 매크로를 제공하여 CCP 보호 레지스터 수정 가능.
- 예시:
#include <avr/io.h> #include <avr/cpufunc.h> #include "clock_driver.h"
- Microchip Studio 설정:
- Microchip Studio에서 새 AVR 프로젝트를 생성하세요 (File → New → Project → GCC C Executable Project).
- 대상 디바이스를 AVR128DA64/48/32/28 중 선택 (예: AVR128DA64).
- Toolchain으로 AVR-GCC 선택, 디버거로 SimAVR 또는 실제 하드웨어 (예: AVR-ISP mkII) 설정.
- clock_driver.h와 clock_driver.c를 프로젝트에 추가 (Solution Explorer → Add → Existing Item).
- F_CPU 정의:
- 클럭 주파수에 맞게 F_CPU를 정의하세요 (예: 24 MHz → #define F_CPU 24000000UL).
- F_CPU는 <util/delay.h>와 같은 라이브러리에서 지연 계산에 사용.
- main.c 상단에 추가:
#ifndef F_CPU #define F_CPU 24000000UL #endif
2. 클럭 설정 선택
애플리케이션 요구사항에 따라 적합한 클럭 설정 함수를 선택하세요. 드라이버는 다양한 시나리오를 지원합니다:
- 고성능 (24 MHz OSCHF):
- 함수: clock_init_24mhz()
- 사용 사례: 고속 데이터 처리, SPI/UART 고속 통신, 실시간 연산.
- 전력 소모: ~5 mA (VDD=5V).
- 호출 예시:
clock_init_24mhz(); // 24 MHz OSCHF, XOSC32K 기반 오토 튜닝
- 저전력 (8 MHz OSCHF):
- 함수: clock_init_8mhz()
- 사용 사례: 배터리 구동 디바이스, 일반적인 GPIO 제어.
- 전력 소모: ~2 mA.
- 호출 예시:
clock_init_8mhz(); // 8 MHz OSCHF, 프리스케일러 비활성
- 초저전력 (32.768 kHz XOSC32K):
- 함수: clock_init_xosc32k()
- 사용 사례: RTC 기반 IoT 디바이스, 스마트 워치.
- 전력 소모: ~1 µA (Power-Down 모드).
- 호출 예시:
clock_init_xosc32k(); // 32.768 kHz XOSC32K, 초저전력
- 고속 PWM (12 MHz CLK_PER, 48 MHz PLL):
- 함수: clock_init_mixed()
- 사용 사례: BLDC 모터 제어, LED 디밍.
- 전력 소모: ~3 mA (CLK_PER) + ~1 mA (PLL).
- 호출 예시:
clock_init_mixed(); // 12 MHz CLK_PER, 48 MHz PLL for TCD
- 커스텀 설정 (20 MHz OSCHF, 4 MHz CLK_PER):
- 함수: clock_init_4mhz_prescaled()
- 사용 사례: 전력과 성능 균형, 중간 속도 통신.
- 전력 소모: ~4 mA.
- 호출 예시:
clock_init_4mhz_prescaled(); // 20 MHz OSCHF, 4 MHz CLK_PER
3. 하드웨어 준비
- XOSC32K 설정:
- 32.768 kHz 크리스털을 TOSC1(PF6)와 TOSC2(PF7)에 연결.
- 외부 커패시터(12~22 pF)로 크리스털 안정화.
- clock_init_24mhz() 또는 clock_init_xosc32k() 호출 시 확인.
- EXTCLK 설정:
- 외부 클럭 소스를 PF5 핀에 연결 (최대 24 MHz).
- clock_init_extclk_24mhz() 호출 시 확인.
- 핀 설정:
- CLKOUT 활성화 시 PA7 핀을 출력으로 설정 (CLKCTRL.MCLKCTRLA CLKOUT=1).
- TCD PWM 사용 시 PF0~PF3 핀을 출력으로 설정.
- 예시:
PORTA.DIRSET = PIN7_bm; // CLKOUT용 PA7 출력 설정 PORTF.DIRSET = PIN0_bm; // TCD PWM용 PF0 출력 설정
4. 클럭 안정성 확인
- 클럭 소스 전환 및 안정화 상태를 확인하세요:
- CLKCTRL.MCLKSTATUS 레지스터의 OSCHFS, EXTS, XOSC32KS, PLLS 비트를 확인.
- SOSC 비트가 0이 될 때까지 대기 (클럭 전환 완료).
- 드라이버 함수는 내부적으로 이를 처리하지만, 디버깅 시 수동 확인 가능:
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_OSCHFS_bm)); // OSCHF 안정화 대기 while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm); // 전환 완료 대기
- 드라이버의 clock_get_status() 함수로 현재 클럭 상태 확인:
ClockStatus status; clock_get_status(&status); printf("Source=%d, Freq=%d MHz, PLL=%d (%d MHz)\r\n", status.source, status.freq, status.pll_active, status.pll_freq);
5. 테스트 및 디버깅
- UART 출력:
- UART로 클럭 상태 및 동작 확인 (예: uart_driver.h 사용).
- PuTTY 또는 Tera Term에서 9600bps로 연결 (PA0: TXD, PA1: RXD).
- 예시:
UART_Instance usart0_instance; uart_init(&usart0_instance, &USART0, UART_BAUD_9600, UART_DATA_8BIT, UART_STOP_1BIT, UART_PARITY_NONE, UART_MODE_ASYNC, UART_PORTMUX_DEFAULT); uart_enable_tx(&usart0_instance); uart_enable_rx(&usart0_instance); uart_setup_stdio(&usart0_instance); printf("Clock Test: Running at 24 MHz\r\n");
- TCD PWM 출력:
- TCD PWM을 PF0~PF3 핀으로 출력하여 오실로스코프로 확인.
- 예: 10 kHz PWM, 50% 듀티 사이클 (clock_pwm_example.c 참조).
- RTC 테스트:
- RTC를 설정하여 1초 주기 인터럽트 확인 (clock_rtc_example.c 참조).
- XOSC32K로 정확한 타이밍 확인.
- Microchip Studio 디버거:
- SimAVR로 클럭 레지스터(MCLKCTRLA, MCLKSTATUS 등) 모니터링.
- 실제 하드웨어에서는 AVR-ISP mkII 또는 Atmel-ICE로 레지스터 값 확인.
- CLKOUT 핀:
- CLKCTRL.MCLKCTRLA의 CLKOUT 비트를 설정하여 PA7 핀으로 CLK_PER 출력.
- 오실로스코프 또는 주파수 카운터로 주파수 측정.
- 예시:
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc | CLKCTRL_CLKOUT_bm);
6. 프로젝트 통합
- 드라이버 파일 추가:
- clock_driver.h와 clock_driver.c를 프로젝트에 추가.
- main.c에서 초기화 함수 호출:
int main(void) { clock_init_24mhz(); // 24 MHz OSCHF 설정 while (1) { // 애플리케이션 코드 } return 0; }
- 다른 모듈과의 통합:
- UART, SPI, TCD, RTC 등 주변 장치 설정 시 클럭 주파수 고려.
- 예: UART 보드레이트는 CLK_PER에 의존 (9600bps 계산: CLK_PER / (16 * Baud)).
- TCD PWM 주기는 CLK_TCD(48 MHz PLL) 또는 CLK_PER 기반.
- F_CPU 동기화:
- 클럭 변경 시 F_CPU를 업데이트:
#undef F_CPU #define F_CPU 8000000UL // 8 MHz로 변경 clock_init_8mhz();
- 클럭 변경 시 F_CPU를 업데이트:
7. 문제 해결 팁
- 클럭이 동작하지 않음:
- MCLKSTATUS 레지스터 확인: OSCHFS, EXTS, XOSC32KS, PLLS 비트 점검.
- _PROTECTED_WRITE 사용 확인: CCP 보호 레지스터는 반드시 _PROTECTED_WRITE로 수정.
- 하드웨어 연결 확인: XOSC32K(TOSC1/TOSC2), EXTCLK(PF5) 핀 연결 점검.
- UART 출력 이상:
- CLK_PER 주파수와 보드레이트 불일치 확인.
- 예: CLK_PER=24 MHz에서 9600bps 설정 확인.
- uart_driver.h의 보드레이트 계산 공식 확인.
- PWM 주파수 오류:
- TCD CLKSEL 확인: TCD0.CTRLA에서 CLKSEL_PLL 또는 CLKSEL_20M 선택.
- PLL 안정화 확인: CLKCTRL.MCLKSTATUS의 PLLS 비트.
- RTC 타이밍 오류:
- XOSC32K 연결 확인: 32.768 kHz 크리스털 및 커패시터 점검.
- RTC.CLKSEL 설정 확인: RTC_CLKSEL_XOSC32K_gc 사용.
- 전력 소모 과다:
- 불필요한 클럭 소스 비활성화: clock_disable() 호출.
- RUNSTDBY 비트 비활성화: CLKCTRL.OSCHFCTRLA, PLLCTRLA, XOSC32KCTRLA 점검.
- 디버깅 로그:
- clock_get_status()로 현재 클럭 상태 출력.
- Microchip Studio의 I/O View로 CLKCTRL 레지스터 모니터링.
8. 예제 프로젝트 워크플로우
- 고성능 데이터 로깅:
- clock_init_24mhz() 호출.
- UART 초기화 및 센서 데이터 로깅.
- CLKOUT(PA7)으로 클럭 확인.
- 예시: clock_high_perf_example.c.
- 저전력 IoT 디바이스:
- clock_init_xosc32k() 호출.
- RTC 설정 및 주기적 웨이크업.
- Power-Down 모드로 전환.
- 예시: clock_rtc_example.c.
- 모터 제어:
- clock_init_mixed() 호출.
- TCD PWM 설정 (10 kHz, PF0).
- 오실로스코프로 PWM 출력 확인.
- 예시: clock_pwm_example.c.
9. 추가 리소스
- 데이터시트: Microchip AVR128DA64/48/32/28 데이터시트(DS40002183A)에서 CLKCTRL 상세 정보 확인.
- Microchip Studio 튜토리얼: Microchip 웹사이트의 AVR-GCC 및 SimAVR 가이드 참조.
- 하드웨어 툴: AVR-ISP mkII, Atmel-ICE, 또는 Curiosity Nano AVR128DA48 보드 사용.
- 커뮤니티: AVR Freaks 포럼 또는 Microchip 기술 지원 포털에서 문제 해결.
코드 구현
- 클럭 드라이버 코드: clock_driver.h, clock_driver.c, main.c
- 드라이버를 이용한 예시 코드: clock_high_perf_example.c, clock_low_power_example.c, clock_pwm_example.c, clock_rtc_example.c
/**
* @file clock_driver.h
* @brief AVR128DA64/48/32/28 클럭 드라이버 헤더 파일
* @details 모든 AVR128DA 시리즈 호환. OSCHF, EXTCLK, OSC32K, XOSC32K, PLL 설정,
* 프리스케일러, 오토 튜닝, 전력 최적화, CCP 보호, 상태 조회.
* @author linuxgo
* @date 2025-09-05
*/
#ifndef CLOCK_DRIVER_H
#define CLOCK_DRIVER_H
#include <avr/io.h>
#include <avr/cpufunc.h>
/**
* @brief 클럭 주파수 정의
* @details OSCHF 주파수 선택 상수 (FRQSEL 값)
*/
#define CLOCK_FREQ_1MHZ 0x1 // 1 MHz
#define CLOCK_FREQ_8MHZ 0x5 // 8 MHz
#define CLOCK_FREQ_12MHZ 0x6 // 12 MHz
#define CLOCK_FREQ_16MHZ 0x7 // 16 MHz
#define CLOCK_FREQ_20MHZ 0x8 // 20 MHz
#define CLOCK_FREQ_24MHZ 0x9 // 24 MHz
/**
* @brief 클럭 소스 정의
* @details MCLKCTRLA의 CLKSEL 값
*/
#define CLOCK_SRC_OSCHF 0x0 // 내부 고주파 오실레이터
#define CLOCK_SRC_OSC32K 0x1 // 내부 32.768 kHz 오실레이터
#define CLOCK_SRC_XOSC32K 0x2 // 외부 32.768 kHz 크리스털/클럭
#define CLOCK_SRC_EXTCLK 0x3 // 외부 클럭 (PF5)
/**
* @brief 프리스케일러 분주 정의
* @details MCLKCTRLB의 PDIV 값
*/
#define CLOCK_PDIV_2X 0x0 // 2배 분주
#define CLOCK_PDIV_4X 0x1 // 4배 분주
#define CLOCK_PDIV_12X 0x3 // 12배 분주
#define CLOCK_PDIV_64X 0xF // 64배 분주
/**
* @brief PLL 배율 정의
* @details PLLCTRLA의 MULFAC 값
*/
#define CLOCK_PLL_2X 0x2 // 2배 배율
#define CLOCK_PLL_3X 0x3 // 3배 배율
/**
* @brief 클럭 상태 구조체
* @details 현재 클럭 소스, 주파수, PLL 상태 저장
*/
typedef struct {
uint8_t source; // 클럭 소스 (CLOCK_SRC_*)
uint8_t freq; // OSCHF 주파수 (CLOCK_FREQ_*)
uint8_t pll_active; // PLL 활성화 여부 (0=비활성, 1=활성)
uint8_t pll_freq; // PLL 주파수 (MHz)
} ClockStatus;
/**
* @brief 클럭 초기화: 24 MHz OSCHF, 오토 튜닝
* @details XOSC32K를 기준으로 24 MHz OSCHF 설정
*/
void clock_init_24mhz(void);
/**
* @brief 클럭 초기화: 8 MHz OSCHF, 저전력
* @details 8 MHz OSCHF 설정, 프리스케일러 비활성
*/
void clock_init_8mhz(void);
/**
* @brief 클럭 초기화: 32.768 kHz XOSC32K, 초저전력
* @details XOSC32K 설정, CLK_MAIN으로 사용
*/
void clock_init_xosc32k(void);
/**
* @brief 클럭 초기화: 24 MHz EXTCLK
* @details 외부 24 MHz 클럭 설정
*/
void clock_init_extclk_24mhz(void);
/**
* @brief 클럭 초기화: 12 MHz CLK_PER, 48 MHz PLL for TCD
* @details 16 MHz OSCHF를 12 MHz로 분주, PLL로 48 MHz 생성
*/
void clock_init_mixed(void);
/**
* @brief 클럭 초기화: 20 MHz OSCHF, 오토 튜닝, 4 MHz CLK_PER
* @details 20 MHz OSCHF, 프리스케일러로 4 MHz 설정
*/
void clock_init_4mhz_prescaled(void);
/**
* @brief 클럭 비활성화
* @details PLL 및 클럭 소스 비활성화
*/
void clock_disable(void);
/**
* @brief 클럭 상태 조회
* @param status 클럭 상태 구조체 포인터
* @details 현재 클럭 소스, 주파수, PLL 상태 반환
*/
void clock_get_status(ClockStatus *status);
#endif // CLOCK_DRIVER_H
/**
* @file clock_driver.c
* @brief AVR128DA64/48/32/28 클럭 드라이버 구현
* @details CLKCTRL 레지스터로 클럭 소스, 프리스케일러, PLL 설정.
* 오토 튜닝, 전력 최적화, CCP 보호, 상태 조회.
* @author linuxgo
* @date 2025-09-05
*/
#include "clock_driver.h"
/**
* @brief 클럭 초기화: 24 MHz OSCHF, 오토 튜닝
* @details XOSC32K를 기준으로 24 MHz OSCHF 설정, 프리스케일러 비활성
*/
void clock_init_24mhz(void) {
// XOSC32K 활성화: 16k 사이클 시작 시간, 외부 크리스털 (TOSC1/TOSC2, PF6/PF7)
_PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_CSUT_16K_gc | CLKCTRL_ENABLE_bm);
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm)); // XOSC32K 안정화 대기
// OSCHF 설정: 24 MHz, XOSC32K 기반 오토 튜닝 활성화
_PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_24M_gc | CLKCTRL_AUTOTUNE_bm);
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_OSCHFS_bm)); // OSCHF 안정화 대기
// CLK_MAIN 설정: OSCHF 선택
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm); // 클럭 전환 완료 대기
// 프리스케일러 비활성화: CLK_PER = CLK_MAIN = 24 MHz
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0);
}
/**
* @brief 클럭 초기화: 8 MHz OSCHF, 저전력
* @details 8 MHz OSCHF 설정, 프리스케일러 비활성
*/
void clock_init_8mhz(void) {
// OSCHF 설정: 8 MHz, 오토 튜닝 비활성 (저전력 우선)
_PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_8M_gc);
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_OSCHFS_bm)); // OSCHF 안정화 대기
// CLK_MAIN 설정: OSCHF 선택
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm); // 클럭 전환 완료 대기
// 프리스케일러 비활성화: CLK_PER = CLK_MAIN = 8 MHz
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0);
}
/**
* @brief 클럭 초기화: 32.768 kHz XOSC32K, 초저전력
* @details XOSC32K 설정, CLK_MAIN으로 사용
*/
void clock_init_xosc32k(void) {
// XOSC32K 활성화: 16k 사이클 시작 시간, 외부 크리스털
_PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_CSUT_16K_gc | CLKCTRL_ENABLE_bm);
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm)); // XOSC32K 안정화 대기
// CLK_MAIN 설정: XOSC32K 선택
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_XOSC32K_gc);
while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm); // 클럭 전환 완료 대기
// 프리스케일러 비활성화: CLK_PER = CLK_MAIN = 32.768 kHz
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0);
}
/**
* @brief 클럭 초기화: 24 MHz EXTCLK
* @details 외부 24 MHz 클럭 (PF5) 설정
*/
void clock_init_extclk_24mhz(void) {
// CLK_MAIN 설정: EXTCLK 선택 (PF5 핀)
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_EXTCLK_gc);
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_EXTS_bm)); // EXTCLK 안정화 대기
while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm); // 클럭 전환 완료 대기
// 프리스케일러 비활성화: CLK_PER = CLK_MAIN = 24 MHz
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0);
}
/**
* @brief 클럭 초기화: 12 MHz CLK_PER, 48 MHz PLL for TCD
* @details 16 MHz OSCHF를 12 MHz로 분주, PLL로 48 MHz 생성
*/
void clock_init_mixed(void) {
// OSCHF 설정: 16 MHz
_PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_16M_gc);
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_OSCHFS_bm)); // OSCHF 안정화 대기
// CLK_MAIN 설정: OSCHF 선택
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm); // 클럭 전환 완료 대기
// 프리스케일러 설정: CLK_PER = 16 MHz / 12 = 1.333 MHz ≈ 12 MHz
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_12X_gc | CLKCTRL_PEN_bm);
// PLL 설정: OSCHF 소스, 3x 배율 (16 MHz * 3 = 48 MHz)
_PROTECTED_WRITE(CLKCTRL.PLLCTRLA, CLKCTRL_SOURCE_OSCHF_gc | CLKCTRL_MULFAC_3x_gc);
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_PLLS_bm)); // PLL 안정화 대기
// TCD에 48 MHz 적용
TCD0.CTRLA = TCD_CLKSEL_PLL_gc | TCD_ENABLE_bm;
}
/**
* @brief 클럭 초기화: 20 MHz OSCHF, 오토 튜닝, 4 MHz CLK_PER
* @details 20 MHz OSCHF, 프리스케일러로 4 MHz 설정
*/
void clock_init_4mhz_prescaled(void) {
// XOSC32K 활성화: 16k 사이클 시작 시간
_PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_CSUT_16K_gc | CLKCTRL_ENABLE_bm);
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm)); // XOSC32K 안정화 대기
// OSCHF 설정: 20 MHz, 오토 튜닝 활성화
_PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_20M_gc | CLKCTRL_AUTOTUNE_bm);
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_OSCHFS_bm)); // OSCHF 안정화 대기
// CLK_MAIN 설정: OSCHF 선택
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm); // 클럭 전환 완료 대기
// 프리스케일러 설정: CLK_PER = 20 MHz / 5 ≈ 4 MHz
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm);
}
/**
* @brief 클럭 비활성화
* @details PLL, XOSC32K, OSCHF 비활성화
*/
void clock_disable(void) {
// PLL 비활성화
_PROTECTED_WRITE(CLKCTRL.PLLCTRLA, 0);
// XOSC32K 비활성화
_PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, 0);
// OSCHF 비활성화 (최소 1 MHz 유지)
_PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_1M_gc);
}
/**
* @brief 클럭 상태 조회
* @param status 클럭 상태 구조체 포인터
* @details 현재 클럭 소스, 주파수, PLL 상태 반환
*/
void clock_get_status(ClockStatus *status) {
// 클럭 소스 확인
status->source = CLKCTRL.MCLKCTRLA & 0x03; // CLKSEL[1:0]
// OSCHF 주파수 확인
uint8_t frqsel = (CLKCTRL.OSCHFCTRLA & CLKCTRL_FRQSEL_gm) >> CLKCTRL_FRQSEL_gp;
switch (frqsel) {
case CLOCK_FREQ_1MHZ: status->freq = 1; break;
case CLOCK_FREQ_8MHZ: status->freq = 8; break;
case CLOCK_FREQ_12MHZ: status->freq = 12; break;
case CLOCK_FREQ_16MHZ: status->freq = 16; break;
case CLOCK_FREQ_20MHZ: status->freq = 20; break;
case CLOCK_FREQ_24MHZ: status->freq = 24; break;
default: status->freq = 4; break; // 리셋 기본값
}
// PLL 상태 확인
status->pll_active = (CLKCTRL.PLLCTRLA & CLKCTRL_MULFAC_gm) ? 1 : 0;
if (status->pll_active) {
uint8_t mulfac = (CLKCTRL.PLLCTRLA & CLKCTRL_MULFAC_gm) >> CLKCTRL_MULFAC_gp;
status->pll_freq = (mulfac == CLOCK_PLL_2X) ? (status->freq * 2) : (status->freq * 3);
} else {
status->pll_freq = 0;
}
}
/**
* @file main.c
* @brief AVR128DA64/48/32/28 클럭 드라이버 테스트 프로그램
* @details 다양한 클럭 설정(24 MHz OSCHF, 8 MHz OSCHF, 32.768 kHz XOSC32K,
* 48 MHz PLL, 4 MHz CLK_PER) 테스트, UART로 상태 출력
* @author linuxgo
* @date 2025-09-05
*/
#ifndef F_CPU
#define F_CPU 24000000UL // 기본 클럭 주파수 24 MHz
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <string.h>
#include "clock_driver.h"
#include "uart_driver.h"
int main(void) {
// UART 초기화: printf용, USART0, 9600bps, 8-N-1, 비동기, DEFAULT
UART_Instance usart0_instance;
uart_init(&usart0_instance, &USART0, UART_BAUD_9600, UART_DATA_8BIT, UART_STOP_1BIT, UART_PARITY_NONE, UART_MODE_ASYNC, UART_PORTMUX_DEFAULT);
uart_enable_tx(&usart0_instance);
uart_enable_rx(&usart0_instance);
uart_setup_stdio(&usart0_instance);
// 테스트 시작 메시지
printf("Clock Driver Test Start\r\n");
_delay_ms(1000);
// 클럭 상태 구조체
ClockStatus status;
// 테스트 1: 24 MHz OSCHF, 오토 튜닝
clock_init_24mhz();
clock_get_status(&status);
printf("Test 1: 24 MHz OSCHF, Source=%d, Freq=%d MHz, PLL=%d (%d MHz)\r\n",
status.source, status.freq, status.pll_active, status.pll_freq);
_delay_ms(1000);
// 테스트 2: 8 MHz OSCHF, 저전력
clock_init_8mhz();
clock_get_status(&status);
printf("Test 2: 8 MHz OSCHF, Source=%d, Freq=%d MHz, PLL=%d (%d MHz)\r\n",
status.source, status.freq, status.pll_active, status.pll_freq);
_delay_ms(1000);
// 테스트 3: 32.768 kHz XOSC32K, 초저전력
clock_init_xosc32k();
clock_get_status(&status);
printf("Test 3: 32.768 kHz XOSC32K, Source=%d, Freq=%d MHz, PLL=%d (%d MHz)\r\n",
status.source, status.freq, status.pll_active, status.pll_freq);
_delay_ms(1000);
// 테스트 4: 12 MHz CLK_PER, 48 MHz PLL for TCD
clock_init_mixed();
clock_get_status(&status);
printf("Test 4: 12 MHz CLK_PER, 48 MHz PLL, Source=%d, Freq=%d MHz, PLL=%d (%d MHz)\r\n",
status.source, status.freq, status.pll_active, status.pll_freq);
_delay_ms(1000);
// 테스트 5: 20 MHz OSCHF, 4 MHz CLK_PER
clock_init_4mhz_prescaled();
clock_get_status(&status);
printf("Test 5: 4 MHz CLK_PER, Source=%d, Freq=%d MHz, PLL=%d (%d MHz)\r\n",
status.source, status.freq, status.pll_active, status.pll_freq);
_delay_ms(1000);
// 테스트 6: 클럭 비활성화
clock_disable();
clock_get_status(&status);
printf("Test 6: Clocks disabled, Source=%d, Freq=%d MHz, PLL=%d (%d MHz)\r\n",
status.source, status.freq, status.pll_active, status.pll_freq);
_delay_ms(1000);
// 24 MHz로 복원
clock_init_24mhz();
printf("Restored to 24 MHz OSCHF\r\n");
while (1) {
_delay_ms(1000);
}
return 0;
}
/**
* @file clock_high_perf_example.c
* @brief AVR128DA 클럭 드라이버 고성능 예제
* @details 24 MHz OSCHF 설정, UART로 동작 확인
* @author linuxgo
* @date 2025-09-05
*/
#ifndef F_CPU
#define F_CPU 24000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include "clock_driver.h"
#include "uart_driver.h"
int main(void) {
// 24 MHz OSCHF 설정: 고성능 데이터 처리
clock_init_24mhz();
// UART 초기화: 상태 출력용
UART_Instance usart0_instance;
uart_init(&usart0_instance, &USART0, UART_BAUD_9600, UART_DATA_8BIT, UART_STOP_1BIT, UART_PARITY_NONE, UART_MODE_ASYNC, UART_PORTMUX_DEFAULT);
uart_enable_tx(&usart0_instance);
uart_enable_rx(&usart0_instance);
uart_setup_stdio(&usart0_instance);
// 클럭 상태 확인
ClockStatus status;
clock_get_status(&status);
printf("High Performance Clock Test: Source=%d, Freq=%d MHz, PLL=%d (%d MHz)\r\n",
status.source, status.freq, status.pll_active, status.pll_freq);
while (1) {
printf("Running at 24 MHz OSCHF\r\n");
_delay_ms(1000);
}
return 0;
}
/**
* @file clock_low_power_example.c
* @brief AVR128DA 클럭 드라이버 저전력 예제
* @details 32.768 kHz XOSC32K 설정, UART로 동작 확인
* @author linuxgo
* @date 2025-09-05
*/
#ifndef F_CPU
#define F_CPU 32768UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include "clock_driver.h"
#include "uart_driver.h"
int main(void) {
// 32.768 kHz XOSC32K 설정: 초저전력 RTC 애플리케이션
clock_init_xosc32k();
// UART 초기화: 상태 출력용
UART_Instance usart0_instance;
uart_init(&usart0_instance, &USART0, UART_BAUD_9600, UART_DATA_8BIT, UART_STOP_1BIT, UART_PARITY_NONE, UART_MODE_ASYNC, UART_PORTMUX_DEFAULT);
uart_enable_tx(&usart0_instance);
uart_enable_rx(&usart0_instance);
uart_setup_stdio(&usart0_instance);
// 클럭 상태 확인
ClockStatus status;
clock_get_status(&status);
printf("Low Power Clock Test: Source=%d, Freq=%d MHz, PLL=%d (%d MHz)\r\n",
status.source, status.freq, status.pll_active, status.pll_freq);
while (1) {
printf("Running at 32.768 kHz XOSC32K\r\n");
_delay_ms(1000);
}
return 0;
}
/**
* @file clock_pwm_example.c
* @brief AVR128DA 클럭 드라이버 고속 PWM 예제
* @details 12 MHz CLK_PER, 48 MHz PLL로 TCD PWM 설정
* @author linuxgo
* @date 2025-09-05
*/
#ifndef F_CPU
#define F_CPU 12000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include "clock_driver.h"
#include "uart_driver.h"
int main(void) {
// 12 MHz CLK_PER, 48 MHz PLL 설정
clock_init_mixed();
// UART 초기화: 상태 출력용
UART_Instance usart0_instance;
uart_init(&usart0_instance, &USART0, UART_BAUD_9600, UART_DATA_8BIT, UART_STOP_1BIT, UART_PARITY_NONE, UART_MODE_ASYNC, UART_PORTMUX_DEFAULT);
uart_enable_tx(&usart0_instance);
uart_enable_rx(&usart0_instance);
uart_setup_stdio(&usart0_instance);
// TCD PWM 설정: 10 kHz, 50% 듀티 사이클
TCD0.CMPBCLR = 4799; // 주기: 48 MHz / 10 kHz = 4800 사이클
TCD0.CMPASET = 2400; // 50% 듀티 사이클
TCD0.CTRLB = TCD_WGMODE_ONERAMP_gc; // One Ramp 모드
PORTF.DIRSET = PIN0_bm; // PF0 출력 (TCD PWM 핀)
// 클럭 상태 확인
ClockStatus status;
clock_get_status(&status);
printf("PWM Clock Test: Source=%d, Freq=%d MHz, PLL=%d (%d MHz)\r\n",
status.source, status.freq, status.pll_active, status.pll_freq);
while (1) {
printf("Running TCD PWM at 48 MHz\r\n");
_delay_ms(1000);
}
return 0;
}
/**
* @file clock_rtc_example.c
* @brief AVR128DA 클럭 드라이버 RTC 예제
* @details 32.768 kHz XOSC32K로 RTC 설정
* @author linuxgo
* @date 2025-09-05
*/
#ifndef F_CPU
#define F_CPU 32768UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include "clock_driver.h"
#include "uart_driver.h"
volatile uint32_t rtc_ticks = 0; // RTC 틱 카운터
/**
* @brief RTC 오버플로우 인터럽트 핸들러
*/
ISR(RTC_CNT_vect) {
RTC.INTFLAGS = RTC_OVF_bm; // 오버플로우 플래그 클리어
rtc_ticks++; // 틱 카운트 증가
}
int main(void) {
// 32.768 kHz XOSC32K 설정
clock_init_xosc32k();
// UART 초기화: 상태 출력용
UART_Instance usart0_instance;
uart_init(&usart0_instance, &USART0, UART_BAUD_9600, UART_DATA_8BIT, UART_STOP_1BIT, UART_PARITY_NONE, UART_MODE_ASYNC, UART_PORTMUX_DEFAULT);
uart_enable_tx(&usart0_instance);
uart_enable_rx(&usart0_instance);
uart_setup_stdio(&usart0_instance);
// RTC 설정: 1초 주기 오버플로우
RTC.CLKSEL = RTC_CLKSEL_XOSC32K_gc; // XOSC32K 선택
RTC.PER = 32767; // 1초 (32.768 kHz / 32768)
RTC.INTCTRL = RTC_OVF_bm; // 오버플로우 인터럽트 활성화
RTC.CTRLA = RTC_PRESCALER_DIV1_gc | RTC_RTCEN_bm; // RTC 활성화
// 전역 인터럽트 활성화
sei();
// 클럭 상태 확인
ClockStatus status;
clock_get_status(&status);
printf("RTC Clock Test: Source=%d, Freq=%d MHz, PLL=%d (%d MHz)\r\n",
status.source, status.freq, status.pll_active, status.pll_freq);
while (1) {
printf("RTC Ticks: %ld seconds\r\n", rtc_ticks);
_delay_ms(1000);
}
return 0;
}
추가 팁
- 48 MHz PLL 최적화:
- PLL은 입력 클럭이 16 MHz 이상이어야 안정적(예: 16 MHz * 3 = 48 MHz).
- TCD PWM 주기를 계산할 때, 48 MHz는 20.83 ns 해상도를 제공(예: 10 kHz PWM → 4800 사이클).
- 전력 절감:
- Power-Down 모드에서 OSC32K/XOSC32K만 활성화하여 ~1 µA 소모.
- PLL 및 OSCHF는 RUNSTDBY=0으로 비활성화.
- 오토 튜닝:
- XOSC32K 연결 시 TOSC1/TOSC2(PF6/PF7) 핀에 32.768 kHz 크리스털 필수.
- 오토 튜닝은 UART 보드레이트 정확도 향상에 유용.
- CCP 준수:
- _PROTECTED_WRITE는 <avr/cpufunc.h>에 정의.
- CCP 보호 레지스터 수정 시 4 CPU 사이클 내 완료.
- 프리스케일러 활용:
- CLK_PER를 낮추어 전력 절감(예: 24 MHz → 4 MHz).
- 프리스케일러는 UART, SPI 등 주변 장치 동작에 영향.
- 클럭 안정성:
- MCLKSTATUS의 SOSC 비트로 클럭 전환 완료 확인.
- PLLS 비트로 PLL 안정화 확인.
- 테스트 환경:
- Microchip Studio 시뮬레이터로 클럭 동작 확인.
- UART 출력(PuTTY) 또는 오실로스코프로 TCD PWM 확인.
- 애플리케이션 시나리오:
- 고성능: 24 MHz OSCHF로 고속 데이터 처리(예: 센서 데이터 로깅).
- 저전력: 32.768 kHz XOSC32K로 배터리 구동 IoT 디바이스.
- 모터 제어: 48 MHz PLL로 TCD PWM(예: BLDC 모터).
- RTC: XOSC32K로 정확한 시간 유지(예: 스마트 워치).
결론
본 클럭 드라이버는 AVR128DA64/48/32/28 시리즈의 CLKCTRL 기능을 완벽히 활용하도록 설계되었습니다. OSCHF, EXTCLK, OSC32K, XOSC32K, PLL을 지원하며, 프리스케일러, 오토 튜닝, 전력 최적화, 상태 조회 기능을 제공합니다. _PROTECTED_WRITE로 CCP를 준수하여 안정성을 보장하며, 고성능(24 MHz), 저전력(32.768 kHz), 고속 PWM(48 MHz PLL), RTC 애플리케이션 등 다양한 시나리오에 유연하게 적용 가능합니다. 제공된 예제 코드는 고성능, 저전력, PWM, RTC 테스트를 포함하며, Microchip Studio에서 쉽게 검증할 수 있습니다.
'MCU > AVR' 카테고리의 다른 글
AVR32DA/64DA/128DA NVMCTRL 드라이버 설계 및 구현 (0) | 2025.09.05 |
---|---|
AVR128DA64/48/32/28 Sleep Controller 드라이버 설계 및 구현 (0) | 2025.09.05 |
AVR128DA64/48/32/28 RTC 드라이버 설계 및 구현 (0) | 2025.09.05 |
AVR128DA64/48/32/28 TCD 드라이버 설계 및 구현 (0) | 2025.09.05 |
AVR128DA64/48/32/28 TCB 드라이버 설계 및 구현 (0) | 2025.09.04 |
AVR128DA64/48/32/28 AC 드라이버 설계 및 구현 (0) | 2025.09.04 |
AVR128DA64/48/32/28 DAC 드라이버 설계 및 구현 (0) | 2025.09.04 |
AVR128DA64/48/32/28 ADC 드라이버 설계 및 구현 (0) | 2025.09.04 |