1. AVR128DB48 Event System 모듈 개요
Microchip의 AVR128DB48 마이크로컨트롤러는 Event System (EVSYS) 모듈을 통해 주변 장치 간 직접적인 신호 전달을 지원합니다. 이는 CPU 개입 없이 저지연, 저전력 통신을 가능하게 하며, 타이머, ADC, 비교기 등 다양한 애플리케이션에 적합합니다. 이 문서에서는 EVSYS 설정 방법, 레지스터 구조, 그리고 실용적인 예제 코드를 제공하여 초보자와 숙련된 개발자 모두 쉽게 활용할 수 있도록 돕습니다.
주요 사양
- EVSYS 채널: 최대 10개 (CHANNEL0 ~ CHANNEL9)
- 지원 기능:
- 동기/비동기 이벤트 처리
- 슬립 모드 지원 (SleepWalking)
- 소프트웨어 이벤트 트리거
- QDEC(Quadrature Decoder) 지원
- 주요 레지스터:
- SWEVENTA/B: 소프트웨어 이벤트 트리거
- CHANNELn: 이벤트 생성자 선택 (n = 0~9)
- USERm: 이벤트 사용자 채널 연결 (m = CCLLUT0A, ADCn START 등)
- 이벤트 유형: 펄스(Pulse) 또는 레벨(Level)
- 전력 관리: 저전력 모드 지원
- 전압 레벨: 1.8V~5.5V 동작 지원
2. Event System Bitfield 설정
AVR128DB48의 EVSYS 레지스터는 Bitfield 구조로 정의되며, <avr/io.h> 헤더 파일을 통해 접근합니다. 주요 레지스터는 다음과 같습니다:
2.1 SWEVENTA (소프트웨어 이벤트 A)
- 비트 [7:0] SWEVENTA[7:0]: 채널 0~7에 소프트웨어 이벤트 발생 (동기 채널용)
2.2 SWEVENTB (소프트웨어 이벤트 B)
- 비트 [7:0] SWEVENTB[7:0]: 채널 8~9에 해당 (비트 0~1 사용, 나머지 reserved)
2.3 CHANNELn (채널 설정, n = 0~9)
- 비트 [7:0] CHANNELn[7:0]: 이벤트 생성자 ID 선택 (0x00 = OFF, 예: RTC OVF, TCAn OVF 등)
2.4 USERm (사용자 설정, m = USERCCLLUT0A 등)
- 비트 [7:0] USERm[7:0]: [5:0] = 채널 번호 (0~9), 상위 비트 reserved
3. Event System 설정 절차
- 시스템 초기화:
- set_system_clock()으로 시스템 클럭 설정 (예: 24MHz)
- 인터럽트 비활성화 (cli())
- 포트 설정:
- 이벤트 출력 핀 설정 (필요 시 EVSYS EVOUTx 사용)
- 채널 설정:
- CHANNELn 레지스터로 생성자 선택
- 사용자 연결:
- USERm 레지스터로 채널 연결
- 이벤트 활성화:
- 주변 장치 설정에서 이벤트 입력 활성화 (예: TCA.EVCTRL)
- 실행:
- 설정 후 즉시 동작
4. Event System 설정 고려사항
- 클럭 설정: 시스템 클럭 안정화 확인
- 동기/비동기: 비동기 이벤트는 슬립 모드에서 유용
- 채널 충돌: 동일 채널에 여러 사용자 주의
- 저전력: 불필요한 채널 비활성화
- 핀 멀티플렉싱: EVSYS EVOUTx와 다른 기능 충돌 확인
5. Event System 예제 코드
아래는 AVR128DB48 EVSYS를 Bitfield 구조로 설정한 예제 코드입니다. Atmel Studio 또는 MPLAB X IDE와 AVR-GCC 환경에서 실행 가능합니다.
5.1 예제 1: GPIO 핀 이벤트 생성자 (PA0 버튼으로 CCL 및 TCB 트리거)
// File: evsys_gpio_generator.c
// Description: AVR128DB48 이벤트 시스템 예제 (PA0 핀 이벤트로 CCL 및 TCB 트리거)
// Compiler: AVR-GCC
// Target: AVR128DB48
#define F_CPU 24000000UL // 시스템 클록 주파수를 24 MHz로 정의 (지연 함수 정확도를 위해 필요)
#include <avr/io.h> // AVR 입출력 관련 헤더 파일
#include <avr/interrupt.h> // 인터럽트 처리 관련 헤더 파일
#include <util/delay.h> // 지연 함수 관련 헤더 파일
volatile uint16_t timer_count = 0; // TCB0 카운트 값을 저장하는 전역 변수 (인터럽트에서 사용)
void set_system_clock(void) {
// 32.768 kHz 외부 크리스털 오실레이터(XOSC32K) 활성화
_PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_ENABLE_bm | CLKCTRL_RUNSTDBY_bm);
// CLKCTRL.XOSC32KCTRLA 레지스터에 쓰기 보호 해제 후 설정
// CLKCTRL_ENABLE_bm: XOSC32K 활성화
// CLKCTRL_RUNSTDBY_bm: 스탠바이 모드에서도 XOSC32K 동작 유지
// XOSC32K가 안정될 때까지 대기
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm));
// CLKCTRL.MCLKSTATUS의 XOSC32KS_bm 비트가 1이 될 때까지 대기 (안정화 확인)
// 내부 OSCHF를 24 MHz로 설정하고 XOSC32K를 참조하여 오토튜닝 활성화
_PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_24M_gc | CLKCTRL_AUTOTUNE_bm);
// CLKCTRL.OSCHFCTRLA 레지스터에 쓰기 보호 해제 후 설정
// CLKCTRL_FRQSEL_24M_gc: OSCHF를 24 MHz로 설정
// CLKCTRL_AUTOTUNE_bm: XOSC32K를 참조한 오토튜닝 활성화
// OSCHF를 시스템 클록 소스로 설정
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
// CLKCTRL.MCLKCTRLA 레지스터에 쓰기 보호 해제 후 설정
// CLKCTRL_CLKSEL_OSCHF_gc: 시스템 클록 소스를 OSCHF로 선택
// 클록 프리스케일러 비활성화 (24 MHz 그대로 사용)
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0x00);
// CLKCTRL.MCLKCTRLB 레지스터를 0으로 설정하여 프리스케일러 비활성화
}
void gpio_init(void) {
// PA0를 입력 핀으로 설정 (버튼 연결)
PORTA.DIRCLR = PIN0_bm; // PA0 핀의 방향을 입력으로 설정
PORTA.PIN0CTRL |= PORT_PULLUPEN_bm; // PA0에 풀업 저항 활성화 (버튼 입력 안정화)
// PB3를 출력 핀으로 설정 (LED 연결)
PORTB.DIRSET = PIN3_bm; // PB3 핀의 방향을 출력으로 설정 (Curiosity Nano의 LED0)
}
void ccl_init(void) {
// CCL(구성 가능 논리) 모듈 설정: PA0 이벤트 입력을 PB3 출력으로 연결
CCL.LUT0CTRLA = CCL_ENABLE_bm; // LUT0(논리 유닛 0) 활성화
CCL.LUT0CTRLB = CCL_INSEL0_EVENTA_gc; // LUT0의 입력으로 이벤트 채널 0 선택
CCL.LUT0CTRLC = CCL_OUTEN_bm; // LUT0의 출력 활성화 (PB3에 연결)
CCL.TRUTH0 = 0x01; // 진리표 설정: 입력 그대로 출력 (PA0 상태를 PB3에 반영)
CCL.CTRLA = CCL_ENABLE_bm; // CCL 모듈 전체 활성화
}
void timer_init(void) {
// TCB0 설정: 이벤트 입력으로 카운트 증가
TCB0.CTRLB = TCB_CNTMODE_INT_gc; // TCB0를 이벤트 입력 카운트 모드로 설정
TCB0.CTRLA = TCB_CLKSEL_DIV1_gc | TCB_ENABLE_bm; // 24MHz 클럭 사용, 타이머 활성화
// TCB_CLKSEL_CLKDIV1_gc: 클럭 분주 없이 24MHz 사용
// TCB_ENABLE_bm: TCB0 타이머 활성화
}
void evsys_init(void) {
// 이벤트 채널 0: PA0 핀 이벤트 연결
EVSYS.CHANNEL0 = EVSYS_CHANNEL0_PORTA_PIN0_gc; // PA0 핀을 이벤트 생성자로 선택
// 비동기 모드로 설정 (기본값, SYNC 비트 설정 안 함)
// 이벤트 사용자: CCL 및 TCB0에 채널 0 연결
EVSYS.USERCCLLUT0A= EVSYS_USER_CHANNEL0_gc; // CCL에 이벤트 채널 0 연결
EVSYS.USERTCB0CAPT = EVSYS_USER_CHANNEL0_gc; // TCB0에 이벤트 채널 0 연결
}
ISR(TCB0_INT_vect) {
// TCB0 인터럽트 서비스 루틴: PA0 이벤트로 카운트 증가 시 호출
timer_count = TCB0.CNT; // TCB0의 현재 카운트 값을 읽어 저장
TCB0.INTFLAGS = TCB_CAPT_bm; // TCB0 캡처 인터럽트 플래그 클리어
}
int main(void) {
// 시스템 클록 설정 호출
set_system_clock(); // 24MHz 시스템 클럭과 XOSC32K 설정
// GPIO 초기화 호출
gpio_init(); // PA0(입력), PB3(출력) 설정
// CCL 초기화 호출
ccl_init(); // CCL을 통해 PA0 이벤트를 PB3 출력으로 라우팅
// 타이머 초기화 호출
timer_init(); // TCB0 설정 (이벤트 카운트 모드)
// 이벤트 시스템 초기화 호출
evsys_init(); // PA0 이벤트를 CCL 및 TCB0로 연결
// 글로벌 인터럽트 활성화
sei(); // TCB0 인터럽트 서비스 루틴 실행 허용
while (1) {
// 무한 루프: 이벤트 시스템이 PA0 버튼 이벤트를 CCL(즉시 LED 제어) 및 TCB0(카운트)로 라우팅
_delay_ms(10); // 버튼 디바운싱을 위한 10ms 대기
}
return 0; // 프로그램 종료 (실제로는 도달하지 않음)
}
설명:
- 이벤트 생성자: PA0 핀 (버튼 입력)
- 이벤트 사용자: CCL (PB3 LED 제어), TCB0 (카운트 증가)
- 기능: PA0 버튼 입력이 이벤트 채널 0을 통해 CCL로 전달되어 PB3 LED를 즉시 제어하고, 동시에 TCB0의 카운트를 증가시켜 인터럽트에서 카운트 값을 확인
- 설정: PA0 입력(풀업), PB3 출력, 이벤트 채널 0, CCL 및 TCB0 사용자 설정
- 출력: 버튼 누름/놓음에 따라 PB3 LED ON/OFF, TCB0 카운트 증가
5.2 예제 2: 타이머 이벤트 생성자 (TCA0 오버플로우로 ADC 및 TCB 트리거)
// File: evsys_timer_generator.c
// Description: AVR128DB48 이벤트 시스템 예제 (TCA0 오버플로우로 ADC 및 TCB 트리거)
// Compiler: AVR-GCC
// Target: AVR128DB48
#define F_CPU 24000000UL // 시스템 클록 주파수를 24 MHz로 정의 (지연 함수 정확도를 위해 필요)
#include <avr/io.h> // AVR 입출력 관련 헤더 파일
#include <avr/interrupt.h> // 인터럽트 처리 관련 헤더 파일
#include <util/delay.h> // 지연 함수 관련 헤더 파일
volatile uint16_t timer_count = 0; // TCB0 카운트 값을 저장하는 전역 변수
volatile uint16_t adc_value = 0; // ADC 값을 저장하는 전역 변수
void set_system_clock(void) {
// 32.768 kHz 외부 크리스털 오실레이터(XOSC32K) 활성화
_PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_ENABLE_bm | CLKCTRL_RUNSTDBY_bm);
// CLKCTRL.XOSC32KCTRLA 레지스터에 쓰기 보호 해제 후 설정
// CLKCTRL_ENABLE_bm: XOSC32K 활성화
// CLKCTRL_RUNSTDBY_bm: 스탠바이 모드에서도 XOSC32K 동작 유지
// XOSC32K가 안정될 때까지 대기
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm));
// CLKCTRL.MCLKSTATUS의 XOSC32KS_bm 비트가 1이 될 때까지 대기 (안정화 확인)
// 내부 OSCHF를 24 MHz로 설정하고 XOSC32K를 참조하여 오토튜닝 활성화
_PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_24M_gc | CLKCTRL_AUTOTUNE_bm);
// CLKCTRL.OSCHFCTRLA 레지스터에 쓰기 보호 해제 후 설정
// CLKCTRL_FRQSEL_24M_gc: OSCHF를 24 MHz로 설정
// CLKCTRL_AUTOTUNE_bm: XOSC32K를 참조한 오토튜닝 활성화
// OSCHF를 시스템 클록 소스로 설정
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
// CLKCTRL.MCLKCTRLA 레지스터에 쓰기 보호 해제 후 설정
// CLKCTRL_CLKSEL_OSCHF_gc: 시스템 클록 소스를 OSCHF로 선택
// 클록 프리스케일러 비활성화 (24 MHz 그대로 사용)
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0x00);
// CLKCTRL.MCLKCTRLB 레지스터를 0으로 설정하여 프리스케일러 비활성화
}
void timer_init(void) {
// TCA0 타이머 설정: 약 1ms 주기로 오버 이벤트 생성
TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV256_gc | TCA_SINGLE_ENABLE_bm;
// TCA0 클럭을 24MHz/256 = 93.75kHz로 설정하고 타이머 활성화
// TCA_SINGLE_CLKSEL_DIV256_gc: 클럭 분주율 256
// TCA_SINGLE_ENABLE_bm: 타이머 활성화
TCA0.SINGLE.PER = 93; // 주기 설정: 93.75kHz / 93 = 약 1ms 오버플로우
}
void tcb_init(void) {
// TCB0 설정: 이벤트 입력으로 카운트 증가
TCB0.CTRLB = TCB_CNTMODE_INT_gc; // TCB0를 이벤트 입력 카운트 모드로 설정
TCB0.CTRLA = TCB_CLKSEL_DIV1_gc | TCB_ENABLE_bm; // 24MHz 클럭 사용, 타이머 활성화
// TCB_CLKSEL_CLKDIV1_gc: 클럭 분주 없이 24MHz 사용
// TCB_ENABLE_bm: TCB0 타이머 활성화
}
void adc_init(void) {
// ADC0 설정: PA0에서 아날로그 입력 읽기
VREF.ADC0REF = VREF_REFSEL_2V500_gc; // ADC 레퍼런스 전압을 2.5V로 설정
PORTA.DIRCLR = PIN0_bm; // PA0 핀을 입력으로 설정 (아날로그 입력)
ADC0.MUXPOS = ADC_MUXPOS_AIN0_gc; // PA0를 ADC 입력 채널로 선택
ADC0.CTRLA = ADC_ENABLE_bm; // ADC 활성화, 기본 12비트 해상도
}
void evsys_init(void) {
// 이벤트 채널 0: TCA0 오버플로우 이벤트 연결
EVSYS.CHANNEL0 = EVSYS_CHANNEL0_TCA0_OVF_LUNF_gc; // TCA0 오버플로우를 이벤트 생성자로 선택
// 비동기 모드로 설정 (기본값, SYNC 비트 설정 안 함)
// 이벤트 사용자: ADC0 및 TCB0에 채널 0 연결
EVSYS.USERADC0START = EVSYS_USER_CHANNEL0_gc; // ADC0에 이벤트 채널 0 연결 (변환 트리거)
EVSYS.USERTCB0CAPT= EVSYS_USER_CHANNEL0_gc; // TCB0에 이벤트 채널 0 연결 (카운트 트리거)
}
ISR(TCB0_INT_vect) {
// TCB0 인터럽트 서비스 루틴: TCA0 오버플로우 이벤트로 카운트 증가 시 호출
timer_count = TCB0.CNT; // TCB0의 현재 카운트 값을 읽어 저장
TCB0.INTFLAGS = TCB_CAPT_bm; // TCB0 캡처 인터럽트 플래그 클리어
}
ISR(ADC0_RESRDY_vect) {
// ADC0 인터럽트 서비스 루틴: TCA0 오버플로우로 트리거된 ADC 변환 완료 시 호출
adc_value = ADC0.RES; // 12비트 ADC 변환 결과 읽기 (0~4095)
ADC0.INTFLAGS = ADC_RESRDY_bm; // ADC 결과 준비 인터럽트 플래그 클리어
}
int main(void) {
// 시스템 클록 설정 호출
set_system_clock(); // 24MHz 시스템 클럭과 XOSC32K 설정
// 타이머 초기화 호출
timer_init(); // TCA0 설정 (1ms 주기 오버플로우)
// TCB0 초기화 호출
tcb_init(); // TCB0 설정 (이벤트 카운트 모드)
// ADC 초기화 호출
adc_init(); // PA0 입력 및 ADC0 설정
// 이벤트 시스템 초기화 호출
evsys_init(); // TCA0 오버플로우를 ADC0 및 TCB0로 연결
// 글로벌 인터럽트 활성화
sei(); // ADC0 및 TCB0 인터럽트 서비스 루틴 실행 허용
while (1) {
// 무한 루프: TCA0 오버플로우 이벤트가 ADC0 변환과 TCB0 카운트를 주기적으로 트리거
// adc_value 및 timer_count를 UART 또는 디버거로 출력 가능
_delay_ms(100); // 결과 출력 주기 조정을 위한 대기
}
return 0; // 프로그램 종료 (실제로는 도달하지 않음)
}
설명:
- 이벤트 생성자: TCA0 오버플로우 (1ms 주기)
- 이벤트 사용자: ADC0 (PA0에서 변환 트리거), TCB0 (카운트 증가)
- 기능: TCA0 오버플로우 이벤트가 이벤트 채널 0을 통해 ADC0 변환을 시작하고 TCB0 카운트를 증가시킴
- 설정: TCA0(1ms 주기), PA0(ADC 입력), TCB0 이벤트 카운트, 이벤트 채널 0
- 출력: ADC 값(12비트, 0~4095) 및 TCB0 카운트 증가 (1ms마다)
5.3 예제 3: ADC 이벤트 생성자 (ADC0 결과 준비로 TCB )
// File: evsys_adc_generator.c
// Description: AVR128DB48 이벤트 시스템 예제 (ADC0 결과 준비로 TCB 및 DAC 트리거)
// Compiler: AVR-GCC
// Target: AVR128DB48
#define F_CPU 24000000UL // 시스템 클록 주파수를 24 MHz로 정의 (지연 함수 정확도를 위해 필요)
#include <avr/io.h> // AVR 입출력 관련 헤더 파일
#include <avr/interrupt.h> // 인터럽트 처리 관련 헤더 파일
#include <util/delay.h> // 지연 함수 관련 헤더 파일
volatile uint16_t timer_count = 0; // TCB0 카운트 값을 저장하는 전역 변수
volatile uint16_t adc_value = 0; // ADC 값을 저장하는 전역 변수
void set_system_clock(void) {
// 32.768 kHz 외부 크리스털 오실레이터(XOSC32K) 활성화
_PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_ENABLE_bm | CLKCTRL_RUNSTDBY_bm);
// CLKCTRL.XOSC32KCTRLA 레지스터에 쓰기 보호 해제 후 설정
// CLKCTRL_ENABLE_bm: XOSC32K 활성화
// CLKCTRL_RUNSTDBY_bm: 스탠바이 모드에서도 XOSC32K 동작 유지
// XOSC32K가 안정될 때까지 대기
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm));
// CLKCTRL.MCLKSTATUS의 XOSC32KS_bm 비트가 1이 될 때까지 대기 (안정화 확인)
// 내부 OSCHF를 24 MHz로 설정하고 XOSC32K를 참조하여 오토튜닝 활성화
_PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_24M_gc | CLKCTRL_AUTOTUNE_bm);
// CLKCTRL.OSCHFCTRLA 레지스터에 쓰기 보호 해제 후 설정
// CLKCTRL_FRQSEL_24M_gc: OSCHF를 24 MHz로 설정
// CLKCTRL_AUTOTUNE_bm: XOSC32K를 참조한 오토튜닝 활성화
// OSCHF를 시스템 클록 소스로 설정
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
// CLKCTRL.MCLKCTRLA 레지스터에 쓰기 보호 해제 후 설정
// CLKCTRL_CLKSEL_OSCHF_gc: 시스템 클록 소스를 OSCHF로 선택
// 클록 프리스케일러 비활성화 (24 MHz 그대로 사용)
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0x00);
// CLKCTRL.MCLKCTRLB 레지스터를 0으로 설정하여 프리스케일러 비활성화
}
void adc_init(void) {
// ADC0 설정: PA0에서 아날로그 입력 읽기
VREF.ADC0REF = VREF_REFSEL_2V500_gc; // ADC 레퍼런스 전압을 2.5V로 설정
PORTA.DIRCLR = PIN0_bm; // PA0 핀을 입력으로 설정 (아날로그 입력)
ADC0.MUXPOS = ADC_MUXPOS_AIN0_gc; // PA0를 ADC 입력 채널로 선택
ADC0.CTRLA = ADC_ENABLE_bm | ADC_FREERUN_bm; // ADC 활성화, 프리 러닝 모드
// ADC_FREERUN_bm: 연속 변환 모드 활성화
ADC0.COMMAND = ADC_STCONV_bm; // ADC 변환 시작
}
void tcb_init(void) {
// TCB0 설정: 이벤트 입력으로 카운트 증가
TCB0.CTRLB = TCB_CNTMODE_INT_gc; // TCB0를 이벤트 입력 카운트 모드로 설정
TCB0.CTRLA = TCB_CLKSEL_DIV1_gc | TCB_ENABLE_bm; // 24MHz 클럭 사용, 타이머 활성화
// TCB_CLKSEL_CLKDIV1_gc: 클럭 분주 없이 24MHz 사용
// TCB_ENABLE_bm: TCB0 타이머 활성화
}
void dac_init(void) {
// DAC0 설정: PA6에서 아날로그 출력
VREF.DAC0REF |= VREF_REFSEL_2V500_gc; // DAC 레퍼런스 전압을 2.5V로 설정
DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; // DAC 활성화, PA6 출력 활성화
}
void evsys_init(void) {
// 이벤트 채널 0: ADC0 결과 준비 이벤트 연결
EVSYS.CHANNEL0 = EVSYS_CHANNEL0_ADC0_RESRDY_gc; // ADC0 결과 준비를 이벤트 생성자로 선택
// 비동기 모드로 설정 (기본값, SYNC 비트 설정 안 함)
// 이벤트 사용자: TCB0 연결
EVSYS.USERTCB0COUNT = EVSYS_USER_CHANNEL0_gc; // TCB0에 이벤트 채널 0 연결 (카운트 트리거)
}
ISR(TCB0_INT_vect) {
// TCB0 인터럽트 서비스 루틴: ADC0 결과 준비 이벤트로 카운트 증가 시 호출
timer_count = TCB0.CNT; // TCB0의 현재 카운트 값을 읽어 저장
TCB0.INTFLAGS = TCB_CAPT_bm; // TCB0 캡처 인터럽트 플래그 클리어
}
ISR(ADC0_RESRDY_vect) {
// ADC0 인터럽트 서비스 루틴: ADC 변환 완료 시 호출
adc_value = ADC0.RES; // 12비트 ADC 변환 결과 읽기 (0~4095)
DAC0.DATA = (adc_value >> 2) & 0x03FF; // 12비트 ADC 값을 10비트 DAC 값으로 변환하여 출력
ADC0.INTFLAGS = ADC_RESRDY_bm; // ADC 결과 준비 인터럽트 플래그 클리어
}
int main(void) {
// 시스템 클록 설정 호출
set_system_clock(); // 24MHz 시스템 클럭과 XOSC32K 설정
// ADC 초기화 호출
adc_init(); // PA0 입력 및 ADC0 설정 (프리 러닝 모드)
// TCB0 초기화 호출
tcb_init(); // TCB0 설정 (이벤트 카운트 모드)
// DAC 초기화 호출
dac_init(); // DAC0 설정 (PA6 출력)
// 이벤트 시스템 초기화 호출
evsys_init(); // ADC0 결과 준비 이벤트를 TCB0 및 DAC0로 연결
// 글로벌 인터럽트 활성화
sei(); // ADC0 및 TCB0 인터럽트 서비스 루틴 실행 허용
while (1) {
// 무한 루프: ADC0 결과 준비 이벤트가 TCB0 카운트와 DAC0 출력을 트리거
// adc_value 및 timer_count를 UART 또는 디버거로 출력 가능
_delay_ms(100); // 결과 출력 주기 조정을 위한 대기
}
return 0; // 프로그램 종료 (실제로는 도달하지 않음)
}
설명:
- 이벤트 생성자: ADC0 결과 준비 (프리 러닝 모드)
- 이벤트 사용자: TCB0 (카운트 증가), DAC0 (PA6 출력 업데이트)
- 기능: ADC0의 결과 준비 이벤트가 이벤트 채널 0을 통해 TCB0 카운트를 증가시키고 DAC0에 ADC 값을 출력
- 설정: PA0(ADC 입력), PA6(DAC 출력), TCB0 이벤트 카운트, 이벤트 채널 0
- 출력: ADC 값(12비트)을 PA6에서 아날로그 출력, TCB0 카운트 증가
6. 사용 방법
6.1 환경 설정
- AVR-GCC 설치: Atmel Studio 또는 MPLAB X IDE에 AVR-GCC 툴체인 설치
- 헤더 파일: <avr/io.h>, <util/delay.h> 포함
- 프로젝트 설정: AVR128DB48 타겟으로 프로젝트 생성
- 클럭 정의: #define F_CPU 24000000UL로 설정
6.2 코드 실행
- 각 예제를 .c 파일로 저장하거나 main.c에 복사
- Atmel Studio/MPLAB X IDE에서 빌드 및 플래싱
6.3 하드웨어 준비
- 이벤트 출력: EVSYS EVOUTx로 핀 확인 (필요 시)
- 전원: 1.8V~5.5V 공급
- 디버깅 도구: 오실로스코프로 이벤트 신호 점검
6.4 디버깅
- Atmel Studio 디버거 사용
- EVSYS.CHANNELn, USERm 레지스터 확인
- 이벤트 발생 타이밍 점검
7. 추가 팁
- 생성자 선택: 애플리케이션에 적합한 생성자 확인 (예: RTC OVF, TCAn CMP)
- 채널 관리: 중복 사용 피하기
- Microchip 리소스: AVR128DB48 데이터시트, Application Notes 참조
- 문제 해결:
- 이벤트 없음: CHANNELn, USERm 설정 확인
- 지연: 동기/비동기 설정 점검
- 커뮤니티: Microchip Community, AVR Freaks 참고
8. 결론
이 문서는 AVR128DB48 EVSYS 모듈의 설정 방법과 Bitfield 구조를 활용한 예제 코드를 제공하여 저전력, 저지연 통신 애플리케이션에 적용 가능하도록 구성했습니다. 초보자, 숙련자는 소프트웨어 트리거 예제를 확장하여 복잡한 시스템을 구현할 수 있습니다.
키워드: AVR128DB48, EVSYS, Event System, 마이크로컨트롤러, Atmel Studio, MPLAB X IDE, 저전력 통신, 인터럽트
'MCU > AVR' 카테고리의 다른 글
AVR128DB48 ZCD 사용 방법 및 예제 코드 (3) | 2025.08.20 |
---|---|
AVR128DB48 ADC 차동모드 설정 방법 및 예제 코드 (0) | 2025.08.20 |
AVR128DB48 RTC 사용 방법 및 예제 코드 (0) | 2025.08.20 |
AVR128DB48 LIN, IrDA, RS485, MPCM, 스타트 프레임 감지, 동기 모드 사용 방법 및 예제 코드 (1) | 2025.08.20 |
AVR128DB48 Watchdog 사용 방법 및 예제 코드 (0) | 2025.08.19 |
AVR128DB48 SPI 사용 방법 및 예제 코드 (0) | 2025.08.19 |
AVR128DB48 I2C 사용 방법 및 예제 코드(수정) (0) | 2025.08.19 |
AVR128DB48 UART 사용 방법 및 예제 코드(수정) (1) | 2025.08.19 |