인터럽트
- Lecture Overview
TC275 보드에서 외부 Interrupt를 사용하여 LED/SW를 제어하자
- 인터럽트를 사용하기 위해 참조해야할 문서
- Datasheet vs User Manual (Reference Manual)
- Datasheet: HW적인 정의
전압이 얼마 필요하고, 회로가 어떻게 구성되어있다. 뭐 이런거
- UM, RM: 기능(SW)적인 정의
이걸 많이 참고한다. 범용적으로 '데이터 시트 봐라.' 이렇게 많이 말하기는 함.
- 폴링 방식과 인터럽트 방식
- 폴링 방식: 우선순위가 높은 코드를 먼저 처리하는 방식
- 인터럽트: 정상적인 실행 순서를 바꿀 만큼 비정상적이고 중요한 사건
- 우선 처리를 위한 사건을 정의하고, 우선 순위에 따라 실행 순서를 변경
- 하드웨어 vs 소프트웨어 인터럽트
- HW 인터럽트: 하드웨어에 의해 발생, uC의 인터럽트
ex) 타이머 모듈 -> 타이머 모듈에서 시그널을 준다.
이 칩은 운영체제가 없는 상태라서 HW 인터럽트만 발생
- SW 인터럽트: 운영체제의 커널을 통해 발생
- 폴링 방식
하나의 동작에 의해 다른 하나의 동작이 지연될 수 있음
- 인터럽트 처리 방식
- 인터럽트 처리 루틴 (Interrupt Service Routine, ISR)
- 인터럽트 발생 시 HW 도움에 의해 ISR이 자동으로 호출
- ISR 호출 및 실행
- ISR 호출을 위한 3가지 조건
- 전역적인 인터럽트 활성화 비트 세트
- 인터럽트 별 인터럽트 활성화 비트 세트
- 인터럽트 발생 조건 충족
현재 falling edge냐 rising edge냐 이런거
- 인터럽트 처리 순서
- 2번 인터럽트 발생
-> Program Counter(PC)를 인터럽트 벡터 테이블의 2번 위치로 이동
-> 해당 ISR의 위치로 이동
-> ISR 실행 (인터럽트 처리)
-> 인터럽트 발생 전 위치로 복귀
- 인터럽트 사용 시 주의사항
- 중첩된 인터럽트
- ISR 내에서 인터럽트 처리는 권장하지 않음
- ISR은 가능한 짧게 작성하는 것이 바람직함
최대한 빨리 MCU가 처리하고 돌아올 수 있게 해줘야함.
- 인터럽트 우선순위
- 큰 번호의 인터럽트가 우선순위가 높음 (시스템에 따라 다름)
만약 한번에 여러개의 인터럽트가 발생했을 때 유리하다. 거의 그런일은 없지만
- 최적화 방지
- ISR은 일반 함수와 달리 코드 내에서 명시적으로 호출하지 않음
- 따라서 ISR 내에서 값이 바뀌는 변수는 최적화에서 제외하기 위해 volatile 키워드를 사용함
- TC275 외부 인터럽트 사용
- External Request Unit (ERU)
- 외부 스위치의 입력은 "External Request"에 해당
- External Request Unit(ERU) 사용

- 요소를 하나씩 살펴봅시다.
- External Request Selection (ERS) Unit -> per 8 input channel
- Input channel에 연결된 4개의 pin 중 하나를 선택
- P02.1 스위치를 사용하므로 ERS2 사용함을 확인

그림이 없는 것들은 내부 인터럽트
파란색 LED가 꺼질 때 RGB가 토글되도록 할 수도 있다.
인터럽트의 입력이 반드시 입력모드일 필요는 없다. 출력이 입력으로 들어올 수도 있다.
- Event Trigger Logic (ETL) Unit
- EICR에 작성된 내용을 바탕으로 rising/falling edge를 선택하여 Trigger 이벤트를 발생시킴
- Control 레지스터
- EICR 레지스터

일단 EXIS와 FEN, REN 만 기억 -> falling edge enable, rising edge enable
- Output Gating Unit (OGU) -> per 8 output channel
- Input Channel 에서 생성된 Trigger Pulser를 조합하여 External Request output 생성
- Control 레지스터
- IGCR 레지스터

- Interrupt Router (IR)
- ERU의 출력은 IR의 입력으로 연결됨

- 인터럽트를 위한 레지스터 설정
- EICR 설정 -> EICR0이 ERS0, ERS1과 ETL0, ETL1을 control한다.
- ERS2를 사용하기 때문에 EICR1을 사용
- 두번째 input을 사용하므로 EXIS0은 0b001로 세팅

아래 라인이 짝수번째 ERS control, 윗 라인이 홀수번째 ERS control
- 사용하는 회로가 눌렸을 때 1->0으로 변화하므로, falling edge로 설정
- Interrupt Enable
- Falling edge enable
- OGU0로 전달하기 위해
- INP(12~14th bit)를 0b000으로 설정
- IGCR 설정
IOUT로 전달하기 위해
IGP(14~15th bit)를 0b01로 설정



- SCUERU0 설정
- SRPN은 0x10으로, 나머지는 CPU0를 사용하도록 설정
- 인터럽트 핸들러 설정
- Interrupt가 발생하면 BLUE LED를 켜는 동작 설정
- 해당 prio에 사용할 isr(interrupt service routine)을 vector table에 등록
#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"
#define PCn_2_IDX 19
#define P2_IDX 2
#define PCn_1_IDX 11
#define P1_IDX 1
// ERU related
#define EXIS0_IDX 4
#define FEN0_IDX 8
#define EIEN0_IDX 11
#define INP0_IDX 12
#define IGP0_IDX 14
// SRC related
#define SRE_IDX 10
#define TOS_IDX 11
IfxCpu_syncEvent g_cpuSyncEvent = 0;
void initERU(void);
void initGPIO(void);
IFX_INTERRUPT(ISR0, 0, 0x10);
void ISR0(void){
P10_OUT.U = 0x1 << P2_IDX;
}
int core0_main(void)
{
IfxCpu_enableInterrupts();
/* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
* Enable the watchdogs and service them periodically if it is required
*/
IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
/* Wait for CPU sync event */
IfxCpu_emitEvent(&g_cpuSyncEvent);
IfxCpu_waitEvent(&g_cpuSyncEvent, 1);
initGPIO();
initERU();
while(1)
{
}
return (1);
}
void initGPIO(void){
P02_IOCR0.U &= ~(0x1F << PCn_1_IDX);
P02_IOCR0.U |= 0x02 << PCn_1_IDX;
P10_IOCR0.U &= ~(0x1F << PCn_1_IDX);
P10_IOCR0.U |= 0x10 << PCn_1_IDX;
}
void initERU(void){
// ERU(External Request Unit) setting
SCU_EICR1.U &= ~(0x7 << EXIS0_IDX);
SCU_EICR1.U |= 0x1 << EXIS0_IDX;
SCU_EICR1.U |= 1 << FEN0_IDX;
SCU_EICR1.U |= 1 << EIEN0_IDX;
SCU_EICR1.U &= ~(0x7 << INP0_IDX);
SCU_IGCR0.U &= ~(0x3 << IGP0_IDX);
SCU_IGCR0.U |= 0x1 << IGP0_IDX;
// SRC(Service Request Control) setting -> ERU에서 들어온 것을 처리
SRC_SCU_SCU_ERU0.U &= ~0xFF;
SRC_SCU_SCU_ERU0.U |= 0x10;
SRC_SCU_SCU_ERU0.U |= 1 << SRE_IDX;
SRC_SCU_SCU_ERU0.U &= ~(0x3 << TOS_IDX);
}
- 실습 2) LED Blinking 멈추기
- 문제 구현 방법론 -> Finite State Machine 기법 -> 교수님이 매우 중시
1) State Transition
조건 검사를 해서 ST 일어나게
2) State Action
state에 따른 동작
switch 문으로 보통 작성한다.
switch 문 쓸 때 default는 꼭 넣어줘라.
#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"
#define PCn_2_IDX 19
#define P2_IDX 2
#define PCn_1_IDX 11
#define P1_IDX 1
// ERU related
#define EXIS0_IDX 4
#define EXIS1_IDX 20
#define FEN0_IDX 8
#define FEN1_IDX 24
#define EIEN0_IDX 11
#define EIEN1_IDX 27
#define INP0_IDX 12
#define INP1_IDX 28
#define IGP0_IDX 14
#define IGP1_IDX 30
// SRC related
#define SRE_IDX 10
#define TOS_IDX 11
IfxCpu_syncEvent g_cpuSyncEvent = 0;
volatile unsigned toggle = 1;
enum state{
BLINK,
STOP
}state;
void initERU(void);
void initGPIO(void);
IFX_INTERRUPT(ISR0, 0, 0x10);
void ISR0(void){
switch(state){
case BLINK:
state = STOP;
break;
case STOP:
state = BLINK;
break;
default:
break;
}
}
int core0_main(void)
{
IfxCpu_enableInterrupts();
/* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
* Enable the watchdogs and service them periodically if it is required
*/
IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
/* Wait for CPU sync event */
IfxCpu_emitEvent(&g_cpuSyncEvent);
IfxCpu_waitEvent(&g_cpuSyncEvent, 1);
initGPIO();
initERU();
P10_OMR.U = 0x20004;
P10_OMR.U = 0x40002;
while(1)
{
switch(state){
case BLINK:
P10_OMR.U = 0x60006;
for(int i = 0; i < 10000000; i++) ;
break;
case STOP:
default:
break;
}
}
return (1);
}
void initGPIO(){
P02_IOCR0.U &= ~(0x1F << PCn_1_IDX);
P02_IOCR0.U |= 0x02 << PCn_1_IDX;
P10_IOCR0.U &= ~(0x1F << PCn_1_IDX);
P10_IOCR0.U |= 0x10 << PCn_1_IDX;
P10_IOCR0.U &= ~(0x1F << PCn_2_IDX);
P10_IOCR0.U |= 0x10 << PCn_2_IDX;
}
void initERU(void){
//set EICR
SCU_EICR1.U &= ~(0x7 << EXIS0_IDX);
SCU_EICR1.U |= 0x1 << EXIS0_IDX;
SCU_EICR1.U |= 1 << FEN0_IDX;
SCU_EICR1.U |= 1 << EIEN0_IDX;
SCU_EICR1.U &= ~(0x7 << INP0_IDX);
SCU_IGCR0.U &= ~(0X3 << IGP0_IDX);
SCU_IGCR0.U |= 0x1 << IGP0_IDX;
SRC_SCU_SCU_ERU0.U &= ~0xFF;
SRC_SCU_SCU_ERU0.U |= 0x10;
SRC_SCU_SCU_ERU0.U |= 1 << SRE_IDX;
SRC_SCU_SCU_ERU0.U &= ~(0x3 << TOS_IDX);
}