개요
본 문서는 Microchip의 AVR128DA64/48/32/28 시리즈 마이크로컨트롤러의 **Sleep Controller (SLPCTRL)**를 분석하고, 이를 활용한 범용 슬립 컨트롤러 드라이버를 설계 및 구현한 내용을 다룹니다. AVR128DA 시리즈는 세 가지 슬립 모드(Idle, Standby, Power-Down)를 제공하여 저전력 애플리케이션 요구사항을 충족하며, 전력 소모와 성능을 최적화합니다. 본 드라이버는 SLPCTRL의 슬립 모드 설정, 전압 레귤레이터 제어, 인터럽트 기반 웨이크업, Configuration Change Protection(CCP) 준수, 전력 최적화, 그리고 슬립 모드에서 정상 모드(Active 모드)로의 복귀를 지원합니다. AVR128DA 전 제품군(64/48/32/28)에 호환되도록 설계되었으며, Microchip Studio 및 AVR-GCC 환경에서 쉽게 통합 가능합니다.
SLPCTRL 블록 다이어그램

드라이버는 다음과 같은 기능을 제공합니다:
- 슬립 모드 지원: Idle, Standby, Power-Down 모드 설정.
- 전압 레귤레이터 제어: Normal(AUTO) 및 Performance(FULL) 모드, 고온 저누설(HTLLEN) 설정.
- 인터럽트 웨이크업: PORT, BOD, RTC 등 웨이크업 소스 설정 및 처리.
- 정상 모드 복귀: 인터럽트 서비스 루틴(ISR) 실행 후 Active 모드로 복귀.
- CCP 보호: _PROTECTED_WRITE로 안전한 레지스터 수정.
- 전력 최적화: 불필요한 주변 장치 및 클럭 비활성화, Standby 모드에서 RUNSTDBY 제어.
- 상태 확인: 현재 슬립 모드 및 전압 레귤레이터 상태 조회.
사양
AVR128DA 시리즈의 SLPCTRL 사양은 다음과 같습니다:
- 슬립 모드:
- Idle: CPU 정지, 모든 주변 장치 동작, 모든 인터럽트로 웨이크업.
- Standby: 고주파 클럭 정지, RUNSTDBY로 주변 장치 선택적 동작, 제한된 인터럽트 웨이크업.
- Power-Down: 고주파 클럭 정지, 제한된 주변 장치(RTC, WDT, BOD 등) 동작, 고온 저누설(HTLLEN) 옵션.
- 전압 레귤레이터 모드:
- Normal (AUTO): Active/Idle에서 최대 성능, 32.768 kHz 오실레이터 사용 시 저전력.
- Performance (FULL): 모든 모드에서 최대 성능, 빠른 웨이크업.
- HTLLEN: 70°C 이상에서 누설 전류 감소 (Power-Down 전용, TWI/CCL 비활성화 필요).
- 웨이크업 소스:
- Idle: 모든 인터럽트 (PORT, BOD, RTC, TWI, CCL, USART, TCAn, TCBn, ACn, ADCn, PTC, ZCD).
- Standby: PORT, BOD, RTC, TWI, CCL, USART Start-Of-Frame, TCAn.
- Power-Down (HTLLEN=0): PORT, BOD, RTC, TWI, CCL.
- Power-Down (HTLLEN=1): PORT, BOD, RTC.
- 웨이크업 시간:
- Idle: 6 클럭 사이클.
- Standby/Power-Down: 6 클럭 사이클 + 오실레이터/레귤레이터 시작 시간.
- BOD 대기: FUSE.BODCFG의 ACTIVE 비트로 BOD 준비까지 대기 가능.
- CCP 보호: SLPCTRL.VREGCTRL 레지스터는 _PROTECTED_WRITE로 수정.
- 전압 범위: 1.8V ~ 5.5V (VDD).
- 리셋 상태:
- SLPCTRL.CTRLA: 0x00 (슬립 모드 비활성, SEN=0).
- SLPCTRL.VREGCTRL: 0x00 (HTLLEN=0, PMODE=AUTO).
Power-Down 모드의 중요성
Power-Down 모드는 가장 낮은 전력 소모를 제공하며, IoT 디바이스, 배터리 구동 애플리케이션에 적합합니다. 주요 특징은 다음과 같습니다:
- 초저전력: 고주파 클럭 정지, ~1 µA 소모 (VDD=5V, OSC32K 사용).
- 고온 최적화: HTLLEN=1로 70°C 이상에서 누설 전류 감소.
- 제한된 웨이크업: PORT, BOD, RTC 인터럽트로 깨어남.
- 활용 사례:
- 스마트 워치: RTC로 주기적 웨이크업.
- 센서 노드: 배터리 수명 연장.
- 원격 모니터링: 초저전력 대기.
슬립 모드 진입 및 웨이크업 메커니즘
- 슬립 모드 진입:
- SLPCTRL.CTRLA의 **SMODE[2:0]**로 모드 설정 (Idle, Standby, Power-Down).
- SEN 비트를 1로 설정하여 슬립 활성화.
- SLEEP 명령(asm("SLEEP")) 실행으로 CPU가 슬립 상태로 전환.
- 웨이크업 메커니즘:
- 인터럽트: 설정된 웨이크업 소스(PORT, RTC, BOD 등)에 의해 인터럽트 발생 시 장치가 깨어남.
- 리셋: 외부 리셋, Brown-out 리셋 등으로 깨어남.
- 웨이크업 시, 인터럽트 서비스 루틴(ISR)이 실행되고, ISR 종료 후 SLEEP 명령 직후의 명령부터 정상 실행 재개.
- 정상 모드(Active 모드) 복귀:
- 슬립 모드에서 깨어난 후, CPU는 자동으로 Active 모드로 전환.
- SLPCTRL.CTRLA의 SEN 비트는 자동으로 0으로 리셋되지 않으므로, 필요 시 애플리케이션에서 SEN=0으로 설정하여 슬립 모드 비활성화.
- 클럭 소스와 전압 레귤레이터는 슬립 모드 설정에 따라 복원 (예: Standby/Power-Down에서는 오실레이터 시작 시간 필요).
- 애플리케이션은 웨이크업 후 상태를 확인하고 필요한 초기화를 수행 (예: UART 재설정, LED 상태 업데이트).
레지스터 설정 상세
SLPCTRL은 두 개의 주요 레지스터로 제어됩니다. 데이터시트(DS40002183E)에 따라 레지스터와 비트필드는 다음과 같습니다:

- SLPCTRL.CTRLA (0x00):
- 비트 [3:1]: SMODE[2:0] (슬립 모드: 0x0=IDLE, 0x1=STANDBY, 0x2=PDOWN).
- 비트 [0]: SEN (슬립 활성화: 0=비활성, 1=활성).
- 리셋: 0x00, 읽기/쓰기(R/W).
- SLPCTRL.VREGCTRL (0x01):
- 비트 [4]: HTLLEN (고온 저누설: 0=비활성, 1=활성).
- 비트 [2:0]: PMODE[2:0] (전원 모드: 0x0=AUTO, 0x1=FULL).
- 리셋: 0x00, R/W, CCP 보호.
슬립 모드 설정 및 웨이크업 절차
슬립 모드 진입, 웨이크업, 그리고 정상 모드로의 복귀는 다음 순서로 진행합니다:
- 인터럽트 설정:
- 웨이크업 소스(예: PORT, RTC)와 전역 인터럽트 활성화.
- 슬립 모드별 사용 가능한 인터럽트 확인 (예: Power-Down에서 TWI/CCL 제한).
- 슬립 모드 선택:
- SLPCTRL.CTRLA의 SMODE[2:0]로 IDLE/STANDBY/PDOWN 설정.
- 슬립 활성화:
- SLPCTRL.CTRLA의 SEN=1로 슬립 모드 활성화.
- 전압 레귤레이터 설정:
- SLPCTRL.VREGCTRL로 PMODE 및 HTLLEN 설정 (CCP 준수).
- SLEEP 명령:
- asm("SLEEP")로 슬립 모드 진입.
- 웨이크업 처리:
- 인터럽트 발생 시 ISR 실행.
- ISR에서 웨이크업 플래그 처리 및 상태 업데이트.
- 정상 모드 복귀:
- ISR 종료 후 SLEEP 명령 다음 명령부터 실행.
- 필요 시 SEN=0으로 슬립 비활성화 또는 재설정.
- 테스트:
- UART 출력 또는 LED로 슬립/웨이크업/정상 모드 동작 확인.
슬립 모드 설정 고려사항
- CCP 보호: SLPCTRL.VREGCTRL은 _PROTECTED_WRITE로 수정. 미사용 시 쓰기 무시.
- 웨이크업 소스:
- Standby/Power-Down에서는 제한된 인터럽트 소스만 사용 가능.
- HTLLEN=1일 때 TWI/CCL 비활성화 필수.
- 전력 최적화:
- 불필요한 주변 장치 비활성화 (예: RUNSTDBY=0).
- Power-Down에서 OSC32K/XOSC32K로 ~1 µA 소모.
- 웨이크업 시간:
- Idle: ~6 클럭 사이클 (빠름).
- Standby/Power-Down: 오실레이터 및 레귤레이터 시작 시간 추가.
- 애플리케이션별 최적화:
- 고성능: Idle 모드로 빠른 웨이크업 (예: 실시간 제어).
- 저전력: Power-Down 모드, RTC 웨이크업 (예: IoT 디바이스).
- 고온 환경: HTLLEN=1로 누설 전류 감소.
- 인터럽트 관리:
- 슬립 진입 전 인터럽트 활성화 필수 (미활성화 시 리셋으로만 복구).
- PORT 핀은 완전 비동기 인터럽트 지원.
- 정상 모드 복귀:
- 웨이크업 후 클럭 소스 및 레지스터 상태 확인.
- 애플리케이션에서 필요한 초기화 수행 (예: UART, 타이머).
- 전력 소모 분석:
- Idle: ~2 mA (VDD=5V, 8 MHz).
- Standby: ~10 µA (RUNSTDBY=0).
- Power-Down: ~1 µA (HTLLEN=1, OSC32K).
드라이버 구현 내용
슬립 컨트롤러 드라이버는 AVR128DA64/48/32/28 호환으로 설계되었으며, 슬립 모드 설정과 웨이크업 처리를 추상화합니다. 주요 구현은 다음과 같습니다:
- 슬립 모드 설정: Idle, Standby, Power-Down 모드 초기화 함수.
- 전압 레귤레이터 제어: AUTO/FULL 모드, HTLLEN 설정.
- 인터럽트 웨이크업: PORT, RTC 기반 웨이크업 설정 및 ISR 처리.
- 정상 모드 복귀: 웨이크업 후 Active 모드 전환 및 상태 복원.
- CCP 보호: _PROTECTED_WRITE로 VREGCTRL 안전 수정.
- 전력 최적화: 불필요한 주변 장치 및 클럭 비활성화.
- 상태 조회: 현재 슬립 모드 및 전압 레귤레이터 상태 반환.
- 호환성: <avr/io.h>로 모델별 정의 지원.
사용방법
슬립 컨트롤러 드라이버를 효과적으로 사용하기 위한 단계별 가이드를 제공합니다.
1. 프로젝트 설정
- 필수 헤더 파일 포함:
- sleep_driver.h, <avr/io.h>, <avr/cpufunc.h> 포함.
- <avr/io.h>: 레지스터 정의 제공.
- <avr/cpufunc.h>: _PROTECTED_WRITE 매크로 제공.
#include <avr/io.h> #include <avr/cpufunc.h> #include "sleep_driver.h" - Microchip Studio 설정:
- 새 AVR 프로젝트 생성 (GCC C Executable Project).
- 대상 디바이스: AVR128DA64/48/32/28.
- Toolchain: AVR-GCC, 디버거: SimAVR 또는 AVR-ISP mkII.
- sleep_driver.h, sleep_driver.c 추가.
- F_CPU 정의:
- 클럭 주파수에 맞게 정의 (예: #define F_CPU 8000000UL).
2. 슬립 모드 선택
애플리케이션 요구사항에 따라 적합한 슬립 모드 함수 선택:
- Idle 모드:
- 함수: sleep_init_idle()
- 사용 사례: 빠른 웨이크업, 실시간 제어.
- 전력 소모: ~2 mA (8 MHz).
sleep_init_idle(); sleep_enter(); - Standby 모드:
- 함수: sleep_init_standby()
- 사용 사례: 주기적 작업, 센서 모니터링.
- 전력 소모: ~10 µA (RUNSTDBY=0).
sleep_init_standby(); sleep_enter(); - Power-Down 모드:
- 함수: sleep_init_powerdown()
- 사용 사례: 배터리 구동 IoT 디바이스.
- 전력 소모: ~1 µA (HTLLEN=1).
sleep_init_powerdown(true); sleep_enter(); - 커스텀 설정:
- 함수: sleep_init_custom()
- 사용 사례: 특정 전압 레귤레이터 모드(AUTO/FULL) 설정.
sleep_init_custom(SLEEP_MODE_STANDBY, SLEEP_PMODE_FULL); sleep_enter();
3. 하드웨어 준비
- PORT 인터럽트:
- 웨이크업용 핀 (예: PC0) 설정, 완전 비동기 지원 확인.
PORTC.PIN0CTRL = PORT_ISC_BOTHEDGES_gc; PORTC.INTFLAGS = PORT_INT0_bm; - RTC 설정:
- XOSC32K(TOSC1/TOSC2, PF6/PF7)에 32.768 kHz 크리스털 연결.
- RTC 인터럽트로 주기적 웨이크업.
RTC.CLKSEL = RTC_CLKSEL_XOSC32K_gc; RTC.PER = 32767; RTC.INTCTRL = RTC_OVF_bm; RTC.CTRLA = RTC_PRESCALER_DIV1_gc | RTC_RTCEN_bm;
4. 웨이크업 및 정상 모드 복귀
- 웨이크업 처리:
- 인터럽트 발생 시 ISR에서 플래그 처리 및 상태 업데이트.
- 예: RTC 인터럽트로 웨이크업 후 카운터 증가.
ISR(RTC_CNT_vect) { RTC.INTFLAGS = RTC_OVF_bm; rtc_ticks++; } - 정상 모드 복귀:
- ISR 종료 후 SLEEP 명령 다음 명령부터 실행.
- 필요 시 SEN=0으로 슬립 비활성화.
SLPCTRL.CTRLA &= ~SLPCTRL_SEN_bm; // 슬립 비활성화 - 상태 조회:
- sleep_get_status()로 현재 상태 확인.
SleepStatus status; sleep_get_status(&status); printf("Mode=%d, PMODE=%d, HTLLEN=%d\r\n", status.mode, status.pmode, status.htllen);
5. 테스트 및 디버깅
- UART 출력:
- USART0(PA0: TXD, PA1: RXD)로 상태 출력, 9600bps.
uart_init(&usart0_instance, &USART0, UART_BAUD_9600, UART_DATA_8BIT, UART_STOP_1BIT, UART_PARITY_NONE, UART_MODE_ASYNC, UART_PORTMUX_DEFAULT); printf("Sleep Test: Power-Down Mode\r\n"); - RTC 웨이크업:
- 1초 주기 RTC 인터럽트로 슬립/웨이크업 테스트.
- LED 토글:
- 웨이크업 시 LED(예: PA7) 토글로 정상 모드 확인.
PORTA.DIRSET = PIN7_bm; PORTA.OUTTGL = PIN7_bm; - Microchip Studio 디버거:
- I/O View로 SLPCTRL.CTRLA, VREGCTRL 모니터링.
- SimAVR 또는 Atmel-ICE 사용.
6. 프로젝트 통합
- 드라이버 파일 추가:
- sleep_driver.h, sleep_driver.c를 프로젝트에 추가.
- main.c에서 초기화 및 웨이크업 처리:
int main(void) { sleep_init_powerdown(true); sei(); while (1) { sleep_enter(); // 웨이크업 후 처리 PORTA.OUTTGL = PIN7_bm; // LED 토글 } return 0; } - 다른 모듈 통합:
- RTC, PORT 인터럽트와 함께 사용.
- CLKCTRL 설정(F_CPU)에 맞게 동기화.
7. 문제 해결 팁
- 슬립 모드 진입 실패:
- SEN 비트 확인: SLPCTRL.CTRLA의 SEN=1 설정.
- SLEEP 명령 확인: asm("SLEEP") 사용.
- 웨이크업 실패:
- 인터럽트 활성화 확인: 전역 인터럽트(sei()) 및 소스별 인터럽트.
- MCLKSTATUS로 클럭 안정화 확인.
- 정상 모드 복귀 문제:
- ISR에서 플래그 클리어 확인.
- SEN 비트 비활성화 여부 점검.
- 전력 소모 과다:
- RUNSTDBY 비활성화: RTC, WDT 외 주변 장치 끄기.
- HTLLEN=1로 Power-Down에서 누설 전류 감소.
- TWI/CCL 문제:
- HTLLEN=1 시 TWI/CCL 비활성화 확인.
- 디버깅 로그:
- sleep_get_status()로 상태 출력.
- Microchip Studio로 SLPCTRL 레지스터 확인.
8. 예제 프로젝트 워크플로우
- 저전력 IoT 디바이스:
- sleep_init_powerdown(true) 호출.
- RTC로 1초 주기 웨이크업 설정.
- 웨이크업 후 LED 토글 및 UART 출력.
- 예시: sleep_low_power_example.c.
- 실시간 제어:
- sleep_init_idle() 호출.
- PORT 인터럽트로 즉시 웨이크업.
- 정상 모드에서 상태 처리.
- 예시: sleep_idle_example.c.
- 고온 애플리케이션:
- sleep_init_powerdown(true) 호출, HTLLEN 활성화.
- RTC 웨이크업 및 정상 모드 복귀 테스트.
- 예시: sleep_high_temp_example.c.
9. 추가 리소스
- 데이터시트: AVR128DA64/48/32/28 데이터시트(DS40002183E).
- Microchip Studio: AVR-GCC 및 SimAVR 가이드.
- 하드웨어 툴: AVR-ISP mkII, Atmel-ICE, Curiosity Nano AVR128DA48.
- 커뮤니티: AVR Freaks, Microchip 기술 지원 포털.
코드 구현
sleep_driver.h
/**
* @file sleep_driver.h
* @brief AVR128DA64/48/32/28 슬립 컨트롤러 드라이버 헤더 파일
* @details 모든 AVR128DA 시리즈 호환. Idle, Standby, Power-Down 설정,
* 전압 레귤레이터 제어, 인터럽트 웨이크업, 정상 모드 복귀, CCP 보호, 상태 조회.
* @author linuxgo
* @date 2025-09-05
*/
#ifndef SLEEP_DRIVER_H
#define SLEEP_DRIVER_H
#include <avr/io.h>
#include <avr/cpufunc.h>
/**
* @brief 슬립 모드 정의
* @details SLPCTRL.CTRLA의 SMODE 값
*/
#define SLEEP_MODE_IDLE 0x0 // Idle 모드
#define SLEEP_MODE_STANDBY 0x1 // Standby 모드
#define SLEEP_MODE_PDOWN 0x2 // Power-Down 모드
/**
* @brief 전원 모드 정의
* @details SLPCTRL.VREGCTRL의 PMODE 값
*/
#define SLEEP_PMODE_AUTO 0x0 // Normal (AUTO) 모드
#define SLEEP_PMODE_FULL 0x1 // Performance (FULL) 모드
/**
* @brief 슬립 상태 구조체
* @details 현재 슬립 모드, 전원 모드, HTLLEN 상태 저장
*/
typedef struct {
uint8_t mode; // 슬립 모드 (SLEEP_MODE_*)
uint8_t pmode; // 전원 모드 (SLEEP_PMODE_*)
uint8_t htllen; // 고온 저누설 (0=비활성, 1=활성)
uint8_t active; // Active 모드 여부 (0=슬립, 1=Active)
} SleepStatus;
/**
* @brief 슬립 초기화: Idle 모드
* @details 빠른 웨이크업, 모든 주변 장치 동작
*/
void sleep_init_idle(void);
/**
* @brief 슬립 초기화: Standby 모드
* @details 고주파 클럭 정지, RUNSTDBY로 선택적 동작
*/
void sleep_init_standby(void);
/**
* @brief 슬립 초기화: Power-Down 모드
* @param htllen 고온 저누설 활성화 여부
* @details 초저전력, 제한된 웨이크업 소스
*/
void sleep_init_powerdown(bool htllen);
/**
* @brief 슬립 초기화: 커스텀 설정
* @param mode 슬립 모드 (SLEEP_MODE_*)
* @param pmode 전원 모드 (SLEEP_PMODE_*)
* @details 사용자 정의 슬립 및 전원 모드 설정
*/
void sleep_init_custom(uint8_t mode, uint8_t pmode);
/**
* @brief 슬립 모드 진입
* @details SLEEP 명령 실행
*/
void sleep_enter(void);
/**
* @brief 정상 모드로 복귀
* @details SEN 비트 비활성화 및 상태 복원
*/
void sleep_resume_active(void);
/**
* @brief 슬립 상태 조회
* @param status 슬립 상태 구조체 포인터
* @details 현재 슬립 모드, 전원 모드, HTLLEN, Active 상태 반환
*/
void sleep_get_status(SleepStatus *status);
#endif // SLEEP_DRIVER_H
sleep_driver.c
/**
* @file sleep_driver.c
* @brief AVR128DA64/48/32/28 슬립 컨트롤러 드라이버 구현
* @details SLPCTRL 레지스터로 슬립 모드, 전압 레귤레이터 설정.
* 인터럽트 웨이크업, 정상 모드 복귀, CCP 보호, 상태 조회.
* @author linuxgo
* @date 2025-09-05
*/
#include "sleep_driver.h"
/**
* @brief 슬립 초기화: Idle 모드
* @details 빠른 웨이크업, 모든 주변 장치 동작
*/
void sleep_init_idle(void) {
// 전압 레귤레이터: AUTO 모드
_PROTECTED_WRITE(SLPCTRL.VREGCTRL, SLEEP_PMODE_AUTO);
// 슬립 모드: IDLE, SEN=1
SLPCTRL.CTRLA = (SLEEP_MODE_IDLE << SLPCTRL_SMODE_gp) | SLPCTRL_SEN_bm;
}
/**
* @brief 슬립 초기화: Standby 모드
* @details 고주파 클럭 정지, RUNSTDBY로 선택적 동작
*/
void sleep_init_standby(void) {
// 전압 레귤레이터: AUTO 모드, HTLLEN=0 (Standby에서는 사용 불가)
_PROTECTED_WRITE(SLPCTRL.VREGCTRL, SLEEP_PMODE_AUTO);
// 슬립 모드: STANDBY, SEN=1
SLPCTRL.CTRLA = (SLEEP_MODE_STANDBY << SLPCTRL_SMODE_gp) | SLPCTRL_SEN_bm;
}
/**
* @brief 슬립 초기화: Power-Down 모드
* @param htllen 고온 저누설 활성화 여부
* @details 초저전력, 제한된 웨이크업 소스
*/
void sleep_init_powerdown(bool htllen) {
// TWI, CCL 비활성화 (HTLLEN=1 요구사항)
if (htllen) {
TWI0.CTRLA = 0;
CCL.CTRLA = 0;
}
// 전압 레귤레이터: AUTO 모드, HTLLEN 설정
_PROTECTED_WRITE(SLPCTRL.VREGCTRL, (htllen ? SLPCTRL_HTLLEN_bm : 0) | SLEEP_PMODE_AUTO);
// 슬립 모드: PDOWN, SEN=1
SLPCTRL.CTRLA = (SLEEP_MODE_PDOWN << SLPCTRL_SMODE_gp) | SLPCTRL_SEN_bm;
}
/**
* @brief 슬립 초기화: 커스텀 설정
* @param mode 슬립 모드 (SLEEP_MODE_*)
* @param pmode 전원 모드 (SLEEP_PMODE_*)
* @details 사용자 정의 슬립 및 전원 모드 설정
*/
void sleep_init_custom(uint8_t mode, uint8_t pmode) {
// HTLLEN은 Power-Down에서만 사용 가능
uint8_t htllen = (mode == SLEEP_MODE_PDOWN && pmode == SLEEP_PMODE_AUTO) ? SLPCTRL_HTLLEN_bm : 0;
if (htllen) {
TWI0.CTRLA = 0;
CCL.CTRLA = 0;
}
// 전압 레귤레이터 설정
_PROTECTED_WRITE(SLPCTRL.VREGCTRL, htllen | pmode);
// 슬립 모드 설정
SLPCTRL.CTRLA = (mode << SLPCTRL_SMODE_gp) | SLPCTRL_SEN_bm;
}
/**
* @brief 슬립 모드 진입
* @details SLEEP 명령 실행
*/
void sleep_enter(void) {
asm("SLEEP");
}
/**
* @brief 정상 모드로 복귀
* @details SEN 비트 비활성화 및 상태 복원
*/
void sleep_resume_active(void) {
// 슬립 비활성화
SLPCTRL.CTRLA &= ~SLPCTRL_SEN_bm;
}
/**
* @brief 슬립 상태 조회
* @param status 슬립 상태 구조체 포인터
* @details 현재 슬립 모드, 전원 모드, HTLLEN, Active 상태 반환
*/
void sleep_get_status(SleepStatus *status) {
status->mode = (SLPCTRL.CTRLA & SLPCTRL_SMODE_gm) >> SLPCTRL_SMODE_gp;
status->pmode = SLPCTRL.VREGCTRL & SLPCTRL_PMODE_gm;
status->htllen = (SLPCTRL.VREGCTRL & SLPCTRL_HTLLEN_bm) ? 1 : 0;
status->active = (SLPCTRL.CTRLA & SLPCTRL_SEN_bm) ? 0 : 1; // SEN=0이면 Active
}
main.c
/**
* @file main.c
* @brief AVR128DA64/48/32/28 슬립 컨트롤러 드라이버 테스트 프로그램
* @details Idle, Standby, Power-Down 모드 테스트, 웨이크업 및 정상 모드 복귀, UART로 상태 출력
* @author linuxgo
* @date 2025-09-05
*/
#ifndef F_CPU
#define F_CPU 8000000UL // 기본 클럭 주파수 8 MHz
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <string.h>
#include <avr/interrupt.h>
#include "sleep_driver.h"
#include "uart_driver.h"
volatile uint8_t port_triggered = 0;
volatile uint32_t rtc_ticks = 0;
/**
* @brief PORTC 인터럽트 핸들러
*/
ISR(PORTC_PORT_vect) {
PORTC.INTFLAGS = PORT_INT0_bm;
port_triggered = 1;
}
/**
* @brief RTC 오버플로우 인터럽트 핸들러
*/
ISR(RTC_CNT_vect) {
RTC.INTFLAGS = RTC_OVF_bm;
rtc_ticks++;
}
int main(void) {
// UART 초기화: printf용, USART0, 9600bps, 8-N-1, 비동기
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);
// PORT 인터럽트 설정: PC0, 양방향 에지
PORTC.PIN0CTRL = PORT_ISC_BOTHEDGES_gc;
PORTC.INTFLAGS = PORT_INT0_bm;
// RTC 설정: XOSC32K, 1초 주기 오버플로우
_PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_CSUT_16K_gc | CLKCTRL_ENABLE_bm);
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm));
RTC.CLKSEL = RTC_CLKSEL_XOSC32K_gc;
RTC.PER = 32767;
RTC.INTCTRL = RTC_OVF_bm;
RTC.CTRLA = RTC_PRESCALER_DIV1_gc | RTC_RTCEN_bm;
// LED 출력 설정: PA7
PORTA.DIRSET = PIN7_bm;
// 전역 인터럽트 활성화
sei();
// 테스트 시작 메시지
printf("Sleep Driver Test Start\r\n");
_delay_ms(1000);
// 슬립 상태 구조체
SleepStatus status;
// 테스트 1: Idle 모드
sleep_init_idle();
sleep_get_status(&status);
printf("Test 1: Idle Mode, Mode=%d, PMODE=%d, HTLLEN=%d, Active=%d\r\n",
status.mode, status.pmode, status.htllen, status.active);
sleep_enter();
if (port_triggered) {
printf("Woken up by PORT interrupt\r\n");
port_triggered = 0;
sleep_resume_active(); // 정상 모드 복귀
PORTA.OUTTGL = PIN7_bm; // LED 토글
}
sleep_get_status(&status);
printf("After Wake-up: Active=%d\r\n", status.active);
_delay_ms(1000);
// 테스트 2: Standby 모드
sleep_init_standby();
sleep_get_status(&status);
printf("Test 2: Standby Mode, Mode=%d, PMODE=%d, HTLLEN=%d, Active=%d\r\n",
status.mode, status.pmode, status.htllen, status.active);
sleep_enter();
if (port_triggered) {
printf("Woken up by PORT interrupt\r\n");
port_triggered = 0;
sleep_resume_active();
PORTA.OUTTGL = PIN7_bm;
}
sleep_get_status(&status);
printf("After Wake-up: Active=%d\r\n", status.active);
_delay_ms(1000);
// 테스트 3: Power-Down 모드, HTLLEN 활성화
sleep_init_powerdown(true);
sleep_get_status(&status);
printf("Test 3: Power-Down Mode, Mode=%d, PMODE=%d, HTLLEN=%d, Active=%d\r\n",
status.mode, status.pmode, status.htllen, status.active);
sleep_enter();
if (rtc_ticks > 0) {
printf("Woken up by RTC interrupt, Ticks=%ld\r\n", rtc_ticks);
sleep_resume_active();
PORTA.OUTTGL = PIN7_bm;
}
sleep_get_status(&status);
printf("After Wake-up: Active=%d\r\n", status.active);
_delay_ms(1000);
// 테스트 4: 커스텀 설정 (Standby, FULL)
sleep_init_custom(SLEEP_MODE_STANDBY, SLEEP_PMODE_FULL);
sleep_get_status(&status);
printf("Test 4: Custom Standby, FULL Mode, Mode=%d, PMODE=%d, HTLLEN=%d, Active=%d\r\n",
status.mode, status.pmode, status.htllen, status.active);
sleep_enter();
if (port_triggered) {
printf("Woken up by PORT interrupt\r\n");
port_triggered = 0;
sleep_resume_active();
PORTA.OUTTGL = PIN7_bm;
}
sleep_get_status(&status);
printf("After Wake-up: Active=%d\r\n", status.active);
_delay_ms(1000);
// Power-Down으로 복원
sleep_init_powerdown(true);
printf("Restored to Power-Down Mode\r\n");
while (1) {
sleep_enter();
if (rtc_ticks > 0) {
printf("Woken up by RTC, Ticks=%ld\r\n", rtc_ticks);
sleep_resume_active();
PORTA.OUTTGL = PIN7_bm;
sleep_init_powerdown(true); // 다음 슬립 준비
}
}
return 0;
}
sleep_low_power_example.c
/**
* @file sleep_low_power_example.c
* @brief AVR128DA 슬립 컨트롤러 저전력 예제
* @details Power-Down 모드, RTC 웨이크업, 정상 모드 복귀, 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 <avr/interrupt.h>
#include "sleep_driver.h"
#include "uart_driver.h"
volatile uint32_t rtc_ticks = 0;
/**
* @brief RTC 오버플로우 인터럽트 핸들러
*/
ISR(RTC_CNT_vect) {
RTC.INTFLAGS = RTC_OVF_bm;
rtc_ticks++;
}
int main(void) {
// 32.768 kHz XOSC32K 설정
_PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_CSUT_16K_gc | CLKCTRL_ENABLE_bm);
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm));
// RTC 설정: 1초 주기 오버플로우
RTC.CLKSEL = RTC_CLKSEL_XOSC32K_gc;
RTC.PER = 32767;
RTC.INTCTRL = RTC_OVF_bm;
RTC.CTRLA = RTC_PRESCALER_DIV1_gc | RTC_RTCEN_bm;
// 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);
// LED 출력 설정: PA7
PORTA.DIRSET = PIN7_bm;
// Power-Down 모드 설정: HTLLEN 활성화
sleep_init_powerdown(true);
// 전역 인터럽트 활성화
sei();
// 슬립 상태 확인
SleepStatus status;
sleep_get_status(&status);
printf("Low Power Test: Mode=%d, PMODE=%d, HTLLEN=%d, Active=%d\r\n",
status.mode, status.pmode, status.htllen, status.active);
while (1) {
sleep_enter();
if (rtc_ticks > 0) {
printf("Woken up by RTC, Ticks=%ld\r\n", rtc_ticks);
sleep_resume_active();
PORTA.OUTTGL = PIN7_bm; // 정상 모드 복귀 시 LED 토글
sleep_init_powerdown(true); // 다음 슬립 준비
sleep_get_status(&status);
printf("After Wake-up: Active=%d\r\n", status.active);
}
_delay_ms(1000);
}
return 0;
}
sleep_idle_example.c
/**
* @file sleep_idle_example.c
* @brief AVR128DA 슬립 컨트롤러 Idle 모드 예제
* @details Idle 모드, PORT 인터럽트 웨이크업, 정상 모드 복귀, UART 출력
* @author linuxgo
* @date 2025-09-05
*/
#ifndef F_CPU
#define F_CPU 8000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include "sleep_driver.h"
#include "uart_driver.h"
volatile uint8_t port_triggered = 0;
/**
* @brief PORTC 인터럽트 핸들러
*/
ISR(PORTC_PORT_vect) {
PORTC.INTFLAGS = PORT_INT0_bm;
port_triggered = 1;
}
int main(void) {
// PORT 인터럽트 설정: PC0, 양방향 에지
PORTC.PIN0CTRL = PORT_ISC_BOTHEDGES_gc;
PORTC.INTFLAGS = PORT_INT0_bm;
// 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);
// LED 출력 설정: PA7
PORTA.DIRSET = PIN7_bm;
// Idle 모드 설정
sleep_init_idle();
// 전역 인터럽트 활성화
sei();
// 슬립 상태 확인
SleepStatus status;
sleep_get_status(&status);
printf("Idle Mode Test: Mode=%d, PMODE=%d, HTLLEN=%d, Active=%d\r\n",
status.mode, status.pmode, status.htllen, status.active);
while (1) {
sleep_enter();
if (port_triggered) {
printf("Woken up by PORT interrupt\r\n");
port_triggered = 0;
sleep_resume_active();
PORTA.OUTTGL = PIN7_bm; // 정상 모드 복귀 시 LED 토글
sleep_get_status(&status);
printf("After Wake-up: Active=%d\r\n", status.active);
sleep_init_idle(); // 다음 슬립 준비
}
_delay_ms(1000);
}
return 0;
}
sleep_high_temp_example.c
/**
* @file sleep_high_temp_example.c
* @brief AVR128DA 슬립 컨트롤러 고온 예제
* @details Power-Down 모드, HTLLEN 활성화, 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 "sleep_driver.h"
#include "uart_driver.h"
volatile uint32_t rtc_ticks = 0;
/**
* @brief RTC 오버플로우 인터럽트 핸들러
*/
ISR(RTC_CNT_vect) {
RTC.INTFLAGS = RTC_OVF_bm;
rtc_ticks++;
}
int main(void) {
// 32.768 kHz XOSC32K 설정
_PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_CSUT_16K_gc | CLKCTRL_ENABLE_bm);
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm));
// RTC 설정: 1초 주기 오버플로우
RTC.CLKSEL = RTC_CLKSEL_XOSC32K_gc;
RTC.PER = 32767;
RTC.INTCTRL = RTC_OVF_bm;
RTC.CTRLA = RTC_PRESCALER_DIV1_gc | RTC_RTCEN_bm;
// 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);
// LED 출력 설정: PA7
PORTA.DIRSET = PIN7_bm;
// Power-Down 모드 설정: HTLLEN 활성화
sleep_init_powerdown(true);
// 전역 인터럽트 활성화
sei();
// 슬립 상태 확인
SleepStatus status;
sleep_get_status(&status);
printf("High Temp Test: Mode=%d, PMODE=%d, HTLLEN=%d, Active=%d\r\n",
status.mode, status.pmode, status.htllen, status.active);
while (1) {
sleep_enter();
if (rtc_ticks > 0) {
printf("Woken up by RTC, Ticks=%ld\r\n", rtc_ticks);
sleep_resume_active();
PORTA.OUTTGL = PIN7_bm; // 정상 모드 복귀 시 LED 토글
sleep_get_status(&status);
printf("After Wake-up: Active=%d\r\n", status.active);
sleep_init_powerdown(true); // 다음 슬립 준비
}
_delay_ms(1000);
}
return 0;
}
추가 팁
- Power-Down 최적화:
- HTLLEN=1로 70°C 이상에서 누설 전류 감소.
- TWI/CCL 비활성화 필수.
- 웨이크업 시간:
- Idle: 6 클럭 사이클로 즉시 응답.
- Standby/Power-Down: CLKCTRL 설정에 따라 추가 지연.
- 인터럽트 관리:
- 슬립 진입 전 전역 인터럽트(sei()) 활성화.
- PORT 핀은 비동기 인터럽트 지원.
- 정상 모드 복귀:
- sleep_resume_active()로 SEN 비트 비활성화.
- 웨이크업 후 주변 장치 재초기화 가능 (예: UART).
- CCP 준수:
- _PROTECTED_WRITE로 VREGCTRL 수정, 4 CPU 사이클 내 완료.
- 전력 절감:
- Power-Down에서 OSC32K/XOSC32K로 ~1 µA 소모.
- RUNSTDBY=0으로 불필요한 주변 장치 비활성화.
- 테스트 환경:
- UART 출력(PuTTY, 9600bps)으로 상태 확인.
- LED 토글 또는 오실로스코프로 웨이크업 및 정상 모드 확인.
- 애플리케이션 시나리오:
- 고성능: Idle 모드로 빠른 응답(예: 제어 시스템).
- 저전력: Power-Down 모드, RTC 웨이크업(예: IoT 센서).
- 고온: HTLLEN=1로 누설 전류 감소(예: 산업 장비).
결론
본 슬립 컨트롤러 드라이버는 AVR128DA64/48/32/28 시리즈의 SLPCTRL 기능을 완벽히 활용하도록 설계되었습니다. Idle, Standby, Power-Down 모드를 지원하며, 전압 레귤레이터 제어, 인터럽트 웨이크업, 정상 모드 복귀, CCP 보호, 상태 조회 기능을 제공합니다. _PROTECTED_WRITE로 안정성을 보장하며, 저전력 IoT, 실시간 제어, 고온 애플리케이션 등 다양한 시나리오에 유연하게 적용 가능합니다. 제공된 예제 코드는 Idle, Power-Down, 고온 테스트를 포함하며, 웨이크업 및 정상 모드 복귀를 명확히 구현하여 Microchip Studio에서 검증 가능합니다.
'MCU > AVR' 카테고리의 다른 글
| AVR32DA/64DA/128DA NVMCTRL 드라이버 설계 및 구현 (0) | 2025.09.05 |
|---|---|
| AVR128DA64/48/32/28 클럭 드라이버 설계 및 구현 (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 |