AVR(Atmega128) Interrupt 1
Interrupt Polling 사용자가명령어를사용하여입력핀의값을계속읽어서변화를알아냄 모든경우의입력또는값의변화에대응하여처리가가능 Interrupt MCU 자체가하드웨어적으로그변화를체크하여변화시에만일정한동작 하드웨어적으로지원되는몇개의입력또는값의변화에만대응처리가가능 처리속도는일반적인경우인터럽트가빠름 인터럽트발생시 MCU는지금까지실행하던프로그램을일단중단 사용자에의해정해진인터럽트서비스루틴을실행함. 인터럽트서비스루틴의실행이끝나면다시원래실행하던프로그램으로돌아가서하던일을계속함. 2
Interrupt Source 와 Vector Table Interrupt Source Interrupt를발생시킬수있도록만들어진것 외부입력핀, 카운터, serial port 등 Interrupt Vector Table(Interrupt Jump Table) Interrupt 발생시분기장소를기록해놓은특정번지의내용 Interrupt Service Routine(Interrupt Handler) Interrupt 처리프로그램 3
Interrupt 처리 [ 표 ] Reset & Interrupt Vector ATmega128은리셋을포함하여 35개의 Interrupt Source 를제공 Interrupt와 Reset Vector는각각프로그램메모리영역내에별도의 Vector를가지고있다. 모든 Interrupt에는 Interrupt 를 Enable 시키기위해상태레지스터 SREG의 I비트와함께각각의개별적인 Interrupt Enable Bit가할당되어있다. (1) 퓨즈비트의 BOOTRST 비트를 0으로하면, 리셋때부트로더비트로점프함. (2) MCUCR의 IVSEL비트가 1이면, 인터럽트벡터는부트플래시섹션의스타트번지로이동한다. 따라서, 각인터럽트벡터어드레스는부트플래시섹션의시작번지에이표의프로그램주소가더해진값이된다. 4
Interrupt 처리 (3) ATmega103 호환모드에서는 0x30 ~ 0x44는존재하지않는다. 일반적으로인터럽트우선순위는가장낮은주소를갖는인터럽트 (Reset Interrupt) 가가장높은인터럽트우선순위를가진다. 인터럽트가발생하여인터럽트서비스루틴으로점프하게되면 SREG 레지스터의 I비트는 0 으로되어모든인터럽트가무시된다. 서비스루틴을빠져나오는명령인 RETI를사용하면 I 비트는자동적으로셋된다. 또한사용자는인터럽트를인에이블시키기위해 I비트를셋할수도있다. 5 [ 표 ] Reset & Interrupt Vector(Continued)
Interrupt 처리 [ 표 ] 리셋및인터럽트벡터위치 Boot Reset Address 는다음표의 BOOTSZ1..0 값에따른부트로더섹션의시작번지 6
Memory Sections 7
전형적인경우 (BOOTRST=1, IVSEL=0) 프로그램 리셋주소는 0x0000, 인터럽트벡터시작주소는 0x0002 Address Labels Code Comments 0x0000 jmp RESET ;Reset Handler 0x0002 jmp EXT_INT0 ;IRQ0 Handler 0x0004 jmp EXT_INT1 ;IRQ1 Handler. 0x0044 jmp SPM_RDY ;Store Program Memory ;Ready Handler ; 0x0046 RESET: ldi r16, high(ramend) ;Main Program Start 0x0047 out SPH, r16 ;Set Stack Pointer to top of RAM 0x0048 0x0049 ldi r16, low(ramend) out SPL, r16 0x004A sei ;Enable Interrupts 0x004B <inst> xxx 8
BOOTRST=1, IVSEL=1 이고부트로더크기가 8Kbyte 인경우 부트로더섹션 0xF000 ~ 0xFFFF, 리셋주소는 0x0000, 인터럽트벡터시작주소는 0xF002 Address Labels Code Comments 0x0000 RESET: ldi r16, high(ramend) ;Main Program Start 0x0001 out SPH, r16 ;Set Stack Pointer to top of RAM 0x0002 ldi r16, low(ramend) 0x0003 out SPL, r16 0x0004 sei ;Enable Interrupts 0x0005 <inst> xxx.org 0xF002 0xF002 jmp EXT_INT0 ;IRQ0 Handler 0xF004 jmp EXT_INT1 ;IRQ1 Handler. 0xF044 jmp SPM_RDY ;Store Program Memory ;Ready Handler 9
BOOTRST=0, IVSEL=0 이고부트로더크기가 8Kbyte 인경우 부트로더섹션 0xF000 ~ 0xFFFF, 리셋주소는 0xF000, 인터럽트벡터시작주소는 0x0002 Address Labels Code Comments.org 0x0002 0x0002 jmp EXT_INT0 ;IRQ0 Handler. 0x0044 jmp SPM_RDY ;Store Program Memory ;Ready Handler ;.org 0xF000 0xF000 RESET: ldi r16, high(ramend) ;Main Program Start 0xF001 out SPH, r16 ;Set Stack Pointer to top of RAM 0xF002 ldi r16, low(ramend) 0xF003 out SPL, r16 0xF004 sei ;Enable Interrupts 0xF005 <inst> xxx 10
BOOTRST=0, IVSEL=1 이고부트로더크기가 8Kbyte 인경우 부트로더섹션 0xF000 ~ 0xFFFF, 리셋주소는 0xF000, 인터럽트벡터시작주소는 0xF002 Address Labels Code Comments.org 0xF000 0xF000 jmp RESET ;Reset Handler 0xF002 jmp EXT_INT0 ;IRQ0 Handler 0xF004 jmp EXT_INT1 ;IRQ1 Handler. 0xF044 jmp SPM_RDY ;Store Program Memory ;Ready Handler ; 0xF046 RESET: ldi r16, high(ramend) ;Main Program Start 0xF047 out SPH, r16 ;Set Stack Pointer to top of RAM 0xF048 ldi r16, low(ramend) 0xF049 out SPL, r16 0xF04A sei ;Enable Interrupts 0xF04B <inst> xxx 11
12 Assembly & C Code Example Assembly Code Example Move_interrupts: ; Enable change of interrupt vectors ldi r16, (1<<IVCE) out MCUCR, r16 ; Move interrupts to boot flash section ldi r16, (1<<IVSEL) out MCUCR, r16 ret C Code Example void Move_interrupts(void) { /* Enable change of interrupt vectors */ MCUCR = (1<<IVCE); /* Move interrupts to boot flash section */ MCUCR = (1<<IVSEL);
MCU Control Register MCUCR Bit 1-IVSEL(Interrupt Vector Select) 0 : 인터럽트벡터는플래시메모리의시작에위치 1 : 인터럽트벡터는플래시메모리의부트로더섹션의선두위치로이동 부트로더의선두주소는 BOOTSZ1..0 에의해결정 IVSEL 비트에새로운값을쓰기위해서는 IVCE 비트 = 1 4 사이클이내에 IVSEL 비트에원하는값을 write 하여야함. 이 4 사이클동안 MCU 는인터럽트금지상태가됨. Bit 0-IVCE(Interrupt Vector Change Enable) IVCE 비트가 1이되고 4사이클후또는 IVSEL에값이셋되었을때 IVCE 비트는하드웨어적으로클리어된다. 13
External Interrupt 외부인터럽트는 INT7~0 핀에의해트리거 (trigger) 된다. 만약인터럽트가설정되었다면 INT7:0 핀이출력으로설정되어있어도인터럽트가발생한다. 외부인터럽트는하강에지 (falling edge), 상승에지 (rising edge) 또는레벨트리거 (low level) 신호에의해발생하며, 외부인터럽트제어레지스터인 EICRA와 EICRB 레지스터설정으로가능하다. External Interrupt Control Register A EICRA INT0~INT3에대한인터럽트트리거방식을설정 ISCn1 ISCn0 설명 0 0 INTn의 Low 레벨에서인터럽트요구 0 1-1 0 INTn의하강에지에서비동기적으로인터럽트요구 1 1 INTn의상승에지에서비동기적으로인터럽트요구 14 INT0~INT3의레벨트리거와에지트리거방식에의한외부인터럽트는클럭에상관없이비동기적으로검출되며, 슬립모드를해제하는수단으로사용가능 에지트리거로사용되는비동기인터럽트의경우최소 50ns 이상의펄스폭을가져야한다.
External Interrupt External Interrupt Control Register B EICRB INT4~INT7 에대한인터럽트트리거방식을설정 ISCn1 ISCn0 설명 0 0 INTn 의 Low 레벨에서인터럽트요구 0 1 INTn 에논리적인변화가있을때인터럽트요구 1 0 INTn 의하강에지에서인터럽트요구 1 1 INTn 의상승에지에서인터럽트요구 INT4~INT7의에지트리거방식에의한외부인터럽트는 I/O클럭에의해동작한다. I/O 클럭은아이들 (idle) 모드를제외한모든슬립 (sleep) 모드에서동작을하지않기때문에슬립모드를해제하는수단으로사용될수없다. 에지크리거로사용되는인터럽트는최소 1주기이상의펄스폭을가져야하며, 레벨트리거를사용하는경우에는현재실행중인명령어가끝날때까지 LOW 레벨을유지하여야한다. 15
External Interrupt External Interrupt Mask Register EIMSK 8 개의외부인터럽트를인에이블시키는레지스터 SREG 의 I 비트가 1 이고, INT0~INT7 비트가 1 일경우해당외부인터럽트가인에이블되며, 트리거방식은외부인터럽트제어레지스터 (EICRA, EICRB) 로설정가능 External Interrupt Flag Register EIFR 외부인터럽트의발생여부를나타내는레지스터 INT0~INT7 핀에서인터럽트요구이벤트가발생했을경우이비트가 1 로된다. 이때 SREG의 I비트와 EIMSK 레지스터의 INT0~INT7 비트가 1 이면 MCU는해당되는인터럽트벡터로점프한다. 인터럽트루틴이실행되면플래그는자동적으로클리어되거나또는플래그비트에 1을쓰면클리어된다. 레벨트리거의경우항상클리어되어있다. 16
External Interrupt Status Register SREG BIT 7 I : Global Interrupt Enable 비트 인터럽트를인에이블시키기위해서는반드시 1 이되어야함. 인터럽트가발생하여인터럽트서비스루틴으로점프하게되면 SREG 레지스터의 I 비트는 0 으로되어모든인터럽트가무시된다. 서비스루틴을빠져나오는명령인 RETI를사용하면 I비트는자동적으로셋된다. 또한사용자는인터럽트를인에이블시키기위해 I비트를셋할수도있다. 17
AVR Edit 에서의 interrupt 사용법 AVR Edit 에서 Interrupt 를사용하기위한형식 #include <avr/signal.h> INTERRUPT ( vector_default) { { #include <avr/signal.h> SIGNAL ( vector_default) // user code here // user code here #include <avr/interrupt.h> #define cli() asm volatile ( cli ::) #define sei() asm volatile ( sei ::) void timer enable int (unsigned char ints) #include <avr/signal.h> #define INTERRUPT(signame) #define SIGNAL(signame) #define EMPTY INTERRUPT(signame) 18
SIGNAL() and INTERRUPT() macros Signal Name SIG_2WIRE_SERIAL SIG_ADC SIG_COMPARATOR Description 2-wire serial interface (aka. I178C [tm]) ADC Conversion complete Analog Comparator Interrupt SIG_EEPROM_READY EEPROM ready SIG_FPGA_INTERRUPT0~15 SIG_INPUT_CAPTURE1 Input Capture1 Interrupt SIG_INPUT_CAPTURE3 Input Capture3 Interrupt SIG_INTERRUPT0~7 External Interrupt0 ~ 7 SIG_OUTPUT_COMPARE0 Output Compare0 Interrupt SIG_OUTPUT_COMPARE1A~1C Output Compare1(A)~1(C) Interrupt SIG_OUTPUT_COMPARE2 Output Compare2 Interrupt SIG_OUTPUT_COMPARE3A~3C Output Compare3(A)~3(C) Interrupt SIG_OVERFLOW0~3 Overflow0~3 Interrupt SIG_PIN SIG_PIN_CHANGE0~1 SIG_RDMAC SIG_SPI SPI Interrupt SIG_SPM_READY Store program memory ready SIG_SUSPEND_RESUME 19 SIG_TDMAC
SIGNAL() and INTERRUPT() macros 20 Signal Name SIG_SUSPEND_RESUME SIG_TDMAC SIG_UART0 SIG_UART0_DATA SIG_UART0_RECV SIG_UART0_TRANS SIG_UART1 SIG_UART1_DATA SIG_UART1_RECV SIG_UART1_TRANS SIG_UART_DATA SIG_UART_RECV SIG_UART_TRANS SIG_USART0_DATA SIG_USART0_RECV SIG_USART0_TRANS SIG_USART1_DATA SIG_USART1_RECV SIG_USART1_TRANS SIG_USB_HW Description UART(0) Data Register Empty Interrupt UART(0) Receive Complete Interrupt UART(0) Transmit Complete Interrupt UART(1) Data Register Empty Interrupt UART(1) Receive Complete Interrupt UART(1) Transmit Complete Interrupt UART Data Register Empty Interrupt UART Receive Complete Interrupt UART Transmit Complete Interrupt USART(0) Data Register Empty Interrupt USART(0) Receive Complete Interrupt USART(0) Transmit Complete Interrupt USART(1) Data Register Empty Interrupt USART(1) Receive Complete Interrupt USART(1) Transmit Complete Interrupt
Interrupt H/W 연결 INT0~INT3 이 25~28 번핀을사용할수있는것을보여준다. 하지만이핀들은다른용도와겹치기때문에타겟보드에서는 INT4~ INT7 을쓰는것을권장하고있다. 그림은 INT4~INT7 이 6~9 번핀으로사용할수있는것을보여주고있다 21
22 외부인터럽트프로그램예 외부인터럽트4에대한 LED 순차점멸프로그램 외부인터럽트 4의입력트리거는하강에지에서발생함. 외부트리거신호는입력스위치 SW6 #include <avr/io.h> #include <avr/signal.h> #include <avr/interrupt.h> // PORTF OUTPUT, PORTC INPUT #define OUT_SET DDRF #define OUT_LED PORTF unsigned char led=0xfe; // INT4 의외부인터럽트함수 SIGNAL (SIG_INTERRUPT4) { led <<= 1; led = 0x01; if(led == 0xFF) led = 0xFE; OUT_LED = led; int main(void) { OUT_SET = 0xFF; // LED 포트를출력모드로설정 OUT_LED = led; // LED 포트초기화 // INT4 을 Falling Edge Trig 인터럽트설정 EICRB = 0x02; // 혹은 EICRB=(1 << ISC41) (0 << ISC40); // INT4을활성화 EIMSK = (1 << INT4); // 혹은 EIMSK=0x10; // 글로벌인터럽트활성화 sei(); // 혹은 SREG=0x80; while(1); return 1; 보고서 #4 입력트리거방식은인터럽트레벨트리거방식으로하여스위치를누르고있는동안 LED 가 LED4-LED5-. LED12-LED4-.. 형식으로계속하여불이들어오다가스위치에서손을떼면순차점멸하던 LED가정지하도록하는프로그램을작성하시오.
23 Sensor Test 회로도
교재 p.136 수광센서가차단되었을때모든 LED 가켜지는예제프로그램실습 #include <avr/io.h> #include <avr/signal.h> #include <avr/interrupt.h> // PF0 ~ PF7 61 ~ 54 #define DDR_LED DDRF #define PORT_LED PORTF #define PIN_LED PINF volatile unsigned char int_flag; // INT4의외부인터럽트함수 SIGNAL(SIG_INTERRUPT4) { int_flag = 1; int main(void) { DDR_LED = 0xFF; // LED 포트를출력모드로설정 PORT_LED = 0xFF; // LED 포트초기화 // INT4을 low level 인터럽트설정 EICRB = (0 << ISC41) (0 << ISC40); // INT4을활성화 EIMSK = (1 << INT4); sei(); // 글로벌인터럽트활성화 for (;;) { if (int_flag) { int_flag = 0; PORT_LED = 0x00; else { PORT_LED = 0xFF; return 1; 24
Interrupt 에의한프로그램실습 외부인터럽트4/5에대한 7segment 카운트 (0~99까지) 프로그램 외부인터럽트 4/5의입력트리거는하강에지에서발생함. 보고서 #6 외부트리거신호는입력스위치 SW6(1의자리 )/SW7(10의자리 ) #include <avr/interrupt.h> #define OUT_SET #define OUT_FND #define IN_SET #define IN_KEY unsigned char fnd=0x00; DDRF PORTF DDRC PINC SIGNAL (SIG_INTERRUPT4) { fnd=fnd + 1; OUT_FND = ((fnd/10) << 4) (fnd % 10); SIGNAL (SIG_INTERRUPT5) { fnd=fnd + 10; OUT_FND = ((fnd/10) << 4) (fnd % 10); 프로그램실습후문제점이있으면수정하여보고서로제출하시기바랍니다. int main(void) { OUT_SET = 0xFF; // FND 포트를출력모드로설정 OUT_FND = 0xFF; // FND 포트초기화 // INT4 & INT5 를 Falling Edge Trig 인터럽트설정 EICRB = 0x0A; // 혹은 EICRB=(1 << ISC41) (0 << ISC40) (1 << ISC51) (0 << ISC50); // INT4을활성화 EIMSK = (1 << INT4) (1<<INT5); // 혹은EIMSK=0x30; // 글로벌인터럽트활성화 sei(); // 혹은 SREG=0x80; while(1); return 1; 25
26 폴링방식에의한프로그램실습 7segment 카운트 (0~99까지) 프로그램 SW6(1의자리 ), SW7(10의자리 ) #include <avr/io.h> #define OUT_SET DDRF #define OUT_FND PORTF #define IN_SET DDRC #define IN_KEY PINC void Seg_out(void); void sw_key1(void); void sw_key2(void); unsigned char fnd=0x00; int main(void) { unsigned char sw; OUT_SET = 0xFF; // FND 포트를출력모드로설정 OUT_FND = fnd; // FND 포트초기화 while(1){ Seg_out(); sw=(in_key 0xFC); if(sw == 0xFE) sw_key1(); else if(sw == 0xFD) sw_key2(); for (i = 0; i < 10000; i++) for (j = 0; j < 3000; j++); return 1; 보고서 #7 보고서 #6 에서수정된프로그램을추가한후스위치를한번씩누를때마다 7segment 의값이 1 씩변하도록프로그램을변경하시오. 단, 인터럽트는사용하지말것 void Seg_out() { OUT_FND = ((fnd/10) << 4) (fnd%10); void sw_key1() { fnd=fnd + 1; void sw_key2() { fnd=fnd + 10;