1. AVR128DB48 이벤트 시스템 모듈 개요
Microchip의 AVR128DB48은 AVR DB 시리즈의 8비트 마이크로컨트롤러로, 이벤트 시스템(Event System)을 통해 주변 장치 간의 효율적인 비동기 통신을 지원합니다. 이벤트 시스템은 CPU 개입 없이 하드웨어 이벤트(예: GPIO 핀 입력, 타이머 오버플로우, ADC 완료)를 다른 주변 장치로 전달하여 저지연, 저전력 애플리케이션(예: 센서 트리거, PWM 제어, 인터럽트 처리)에 적합합니다. 이 문서는 이벤트 생성자(GPIO, 타이머, ADC)를 기준으로 AVR128DB48의 이벤트 시스템 설정 방법, Bitfield 구조를 활용한 레지스터 설정, 그리고 실용적인 예제 코드를 제공하여 초보자와 숙련된 개발자 모두 쉽게 활용할 수 있도록 돕습니다.
이벤트 시스템 주요 사양
- 채널: 6개의 이벤트 채널 (EVSYS.CHANNEL0 ~ CHANNEL5)
- 이벤트 생성자: GPIO 핀, 타이머(TCA/TCB), ADC, CCL, USART 등
- 이벤트 사용자: 타이머, ADC, DAC, CCL, TWI 등
- 주요 기능:
- 비동기 이벤트 라우팅
- 동기/비동기 채널 선택
- 이벤트 스트로브 및 엣지 감지
- 주요 레지스터:
- EVSYS.CHANNELn: 이벤트 생성자 선택 (n=0~5)
- EVSYS.USERm: 이벤트 사용자 설정 (m=0~15)
- EVSYS.STROBE: 이벤트 스트로브 트리거
- 클럭 소스: 시스템 클럭 (최대 24MHz, OSCHF 내부 오실레이터)
- 전력 관리: 저전력 모드에서 이벤트 시스템 동작 지원
- 전압 레벨: 1.8V~5.5V 동작 지원
2. 이벤트 시스템 Bitfield 설정 상세
AVR128DB48의 이벤트 시스템 레지스터는 Bitfield 구조로 정의되며, <avr/io.h> 헤더 파일을 통해 접근합니다. 주요 레지스터는 다음과 같습니다:
2.1 EVSYS.CHANNELn (이벤트 채널 설정, n=0~5)
- GEN: 이벤트 생성자 선택
- 예: EVSYS_GEN_PORTA_PIN0_gc (PA0 핀 이벤트)
- 예: EVSYS_GEN_TCA0_OVF_LUNF_gc (TCA0 오버플로우 이벤트)
- 예: EVSYS_GEN_ADC0_RESRDY_gc (ADC0 결과 준비 이벤트)
- SYNC: 동기/비동기 모드 선택 (1: 동기, 0: 비동기)
2.2 EVSYS.USERm (이벤트 사용자 설정, m=0~15)
- CHANNEL: 이벤트 채널 선택
- 예: EVSYS_CHANNEL_CHANNEL0_gc (채널 0 선택)
- 사용자 예:
- EVSYS_USER_TCB0_CAPT (TCB0 캡처 이벤트)
- EVSYS_USER_ADC0_START (ADC0 변환 시작)
- EVSYS_USER_CCL (CCL 입력)
2.3 EVSYS.STROBE
- CHnSTR: 특정 채널에 이벤트 스트로브 트리거 (n=0~5)
- 예: EVSYS_STROBE_CH0STR_bm (채널 0 스트로브)
3. 이벤트 시스템 설정 절차
- 시스템 초기화:
- set_system_clock()로 시스템 클럭 설정 (24MHz, XOSC32K 오토튜닝)
- 인터럽트 비활성화 (cli())
- 이벤트 생성자 설정:
- EVSYS.CHANNELn에 이벤트 소스 선택 (예: GPIO, 타이머, ADC)
- 이벤트 사용자 설정:
- EVSYS.USERm에 이벤트 채널 연결 (예: ADC, 타이머, CCL)
- 이벤트 채널 활성화:
- 별도의 활성화 불필요 (설정 후 즉시 동작)
- 이벤트 트리거:
- 이벤트 소스 발생 시 자동 라우팅 또는 EVSYS.STROBE로 수동 트리거
- 결과 확인:
- 연결된 주변 장치의 동작 확인 (예: ADC 결과, 타이머 카운트, CCL 출력)
4. 이벤트 시스템 설정 고려사항
- 클럭 안정성: 시스템 클럭과 XOSC32K 안정화 확인
- 이벤트 충돌: 동일 채널에 다중 생성자/사용자 연결 주의
- 비동기 모드: 고속 이벤트 처리 시 비동기 모드 권장
- 저전력: 이벤트 시스템은 CPU 개입 최소화로 전력 소모 감소
- 멀티플렉싱: GPIO 핀이 이벤트 소스로 사용될 경우 다른 기능(UART, SPI 등) 충돌 주의
- 이벤트 타이밍: 생성자와 사용자의 클럭 동기화 주의 (동기 모드 사용 시)
5. 실용적인 이벤트 시스템 예제 코드 (생성자 기준)
아래는 AVR128DB48 이벤트 시스템을 Bitfield 구조로 설정한 3개의 예제 코드로, 각 예제는 특정 이벤트 생성자(GPIO 핀, 타이머, ADC)를 기준으로 구성되었습니다. 모든 코드에는 상세한 주석이 포함되어 있으며, 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
#include <avr/io.h> // AVR 입출력 관련 헤더 파일
#include <avr/interrupt.h> // 인터럽트 처리 관련 헤더 파일
#include <util/delay.h> // 지연 함수 관련 헤더 파일
#define F_CPU 24000000UL // 시스템 클록 주파수를 24 MHz로 정의 (지연 함수 정확도를 위해 필요)
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_CLKDIV1_gc | TCB_ENABLE_bm; // 24MHz 클럭 사용, 타이머 활성화
// TCB_CLKSEL_CLKDIV1_gc: 클럭 분주 없이 24MHz 사용
// TCB_ENABLE_bm: TCB0 타이머 활성화
}
void evsys_init(void) {
// 이벤트 채널 0: PA0 핀 이벤트 연결
EVSYS.CHANNEL0 = EVSYS_GEN_PORTA_PIN0_gc; // PA0 핀을 이벤트 생성자로 선택
// 비동기 모드로 설정 (기본값, SYNC 비트 설정 안 함)
// 이벤트 사용자: CCL 및 TCB0에 채널 0 연결
EVSYS.USERCCL = EVSYS_CHANNEL_CHANNEL0_gc; // CCL에 이벤트 채널 0 연결
EVSYS.USERTCB0 = EVSYS_CHANNEL_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
#include <avr/io.h> // AVR 입출력 관련 헤더 파일
#include <avr/interrupt.h> // 인터럽트 처리 관련 헤더 파일
#include <util/delay.h> // 지연 함수 관련 헤더 파일
#define F_CPU 24000000UL // 시스템 클록 주파수를 24 MHz로 정의 (지연 함수 정확도를 위해 필요)
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 주기로 오버 Seungcheol 이벤트 생성
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_CLKDIV1_gc | TCB_ENABLE_bm; // 24MHz 클럭 사용, 타이머 활성화
// TCB_CLKSEL_CLKDIV1_gc: 클럭 분주 없이 24MHz 사용
// TCB_ENABLE_bm: TCB0 타이머 활성화
}
void adc_init(void) {
// ADC0 설정: PA0에서 아날로그 입력 읽기
VREF.CTRLA = VREF_ADC0REFSEL_2V5_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_GEN_TCA0_OVF_LUNF_gc; // TCA0 오버플로우를 이벤트 생성자로 선택
// 비동기 모드로 설정 (기본값, SYNC 비트 설정 안 함)
// 이벤트 사용자: ADC0 및 TCB0에 채널 0 연결
EVSYS.USERADC0 = EVSYS_CHANNEL_CHANNEL0_gc; // ADC0에 이벤트 채널 0 연결 (변환 트리거)
EVSYS.USERTCB0 = EVSYS_CHANNEL_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 및 DAC 트리거)
// File: evsys_adc_generator.c
// Description: AVR128DB48 이벤트 시스템 예제 (ADC0 결과 준비로 TCB 및 DAC 트리거)
// Compiler: AVR-GCC
// Target: AVR128DB48
#include <avr/io.h> // AVR 입출력 관련 헤더 파일
#include <avr/interrupt.h> // 인터럽트 처리 관련 헤더 파일
#include <util/delay.h> // 지연 함수 관련 헤더 파일
#define F_CPU 24000000UL // 시스템 클록 주파수를 24 MHz로 정의 (지연 함수 정확도를 위해 필요)
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.CTRLA = VREF_ADC0REFSEL_2V5_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_CLKDIV1_gc | TCB_ENABLE_bm; // 24MHz 클럭 사용, 타이머 활성화
// TCB_CLKSEL_CLKDIV1_gc: 클럭 분주 없이 24MHz 사용
// TCB_ENABLE_bm: TCB0 타이머 활성화
}
void dac_init(void) {
// DAC0 설정: PA6에서 아날로그 출력
VREF.CTRLA |= VREF_DAC0REFSEL_2V5_gc; // DAC 레퍼런스 전압을 2.5V로 설정
DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; // DAC 활성화, PA6 출력 활성화
}
void evsys_init(void) {
// 이벤트 채널 0: ADC0 결과 준비 이벤트 연결
EVSYS.CHANNEL0 = EVSYS_GEN_ADC0_RESRDY_gc; // ADC0 결과 준비를 이벤트 생성자로 선택
// 비동기 모드로 설정 (기본값, SYNC 비트 설정 안 함)
// 이벤트 사용자: TCB0 및 DAC에 채널 0 연결
EVSYS.USERTCB0 = EVSYS_CHANNEL_CHANNEL0_gc; // TCB0에 이벤트 채널 0 연결 (카운트 트리거)
EVSYS.USERDAC0 = EVSYS_CHANNEL_CHANNEL0_gc; // DAC0에 이벤트 채널 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>, <avr/interrupt.h>, <util/delay.h> 포함
- 프로젝트 설정: AVR128DB48 타겟으로 프로젝트 생성
- 클럭 정의: #define F_CPU 24000000UL로 시스템 클럭 설정
6.2 코드 실행
- 각 예제를 별도의 .c 파일로 저장하거나, main.c에 복사
- 다른 예제 코드 주석 처리
- Atmel Studio/MPLAB X IDE에서 빌드 및 플래싱
6.3 하드웨어 준비
- GPIO 입력: PA0에 버튼(예제 1) 또는 아날로그 신호(예: 가변 저항, 예제 2, 3) 연결
- LED 출력: PB3에 LED 및 전류 제한 저항(예: 330Ω) 연결 (예제 1)
- DAC 출력: PA6에 멀티미터 또는 오실로스코프로 출력 확인 (예제 3)
- 전원: 1.8V~5.5V 전원 공급
- 디바운싱: 버튼 입력 시 10ms 이상 대기 또는 하드웨어 디바운싱 회로 추가
6.4 디버깅
- Atmel Studio/MPLAB X IDE의 디버거 사용
- EVSYS.CHANNELn, EVSYS.USERm, 관련 주변 장치 레지스터(ADC0.RES, TCB0.CNT, DAC0.DATA) 확인
- 오실로스코프 또는 로직 분석기로 이벤트 신호 및 출력 점검
7. 추가 팁
- 클럭 설정: set_system_clock()로 XOSC32K 안정화 및 24MHz 설정 확인
- 노이즈 감소: 입력 핀에 풀업 저항 및 외부 디바운싱 회로 추가, 아날로그 입력에 커패시터(0.1µF) 사용
- Microchip 리소스: AVR128DB48 데이터시트, Application Notes, AVR-GCC 예제
- 문제 해결:
- 이벤트 미작동: EVSYS.CHANNELn 및 EVSYS.USERm 설정, 생성자/사용자 활성화 확인
- 출력 오류: ADC, TCB, DAC, CCL 레지스터 및 핀 설정 확인
- 버튼 입력 불안정: 디바운싱 처리(소프트웨어/하드웨어) 추가
- 커뮤니티: Microchip Community, AVR Freaks 포럼 참고
8. 결론
이 문서는 AVR128DB48의 이벤트 시스템 모듈을 이벤트 생성자(GPIO, 타이머, ADC)를 기준으로 설정 방법과 Bitfield 구조를 활용한 예제 코드를 제공하여 CPU 개입 없이 주변 장치 간 통신을 구현할 수 있도록 구성했습니다. 상세한 주석이 포함된 코드는 초보자가 각 생성자의 동작을 쉽게 이해하도록 돕고, 숙련자는 다중 사용자 연결 및 복잡한 이벤트 라우팅을 활용하여 효율적인 시스템을 구현할 수 있도록 지원합니다.
키워드: AVR128DB48, 이벤트 시스템, AVR, 마이크로컨트롤러, Atmel Studio, MPLAB X IDE, 이벤트 생성자, GPIO 이벤트, 타이머 오버플로우, ADC 결과 준비, CCL, TCB, DAC
'MCU > AVR' 카테고리의 다른 글
[AVR128DB48] LIN, IrDA, RS485, MPCM, 스타트 프레임 감지, 동기 모드 사용 방법 및 예제 코드 (0) | 2025.08.20 |
---|---|
[AVR128DB48] OPAMP 및 아날로그 비교기 사용 방법 및 예제 코드 (0) | 2025.08.20 |
[AVR128DB48] PWM 사용 방법 및 예제 코드 (0) | 2025.08.20 |
[AVR128DB48] ADC 및 DAC 사용 방법 및 예제 코드 (0) | 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 |