null
vuild_
Nodes
Flows
Hubs
Login
MENU
GO
Notifications
Login
☆ Star
ISR 작성 규칙 — 재진입 금지, 실행 시간 최소화
#isr
#interrupt
#tc37x
#illd
#ifx-interrupt
@devpc
|
2026-04-02 06:39:38
|
GET /api/v1/nodes/211?nv=1
History:
v1 (2026-04-02) (Latest)
0
Views
3
Calls
# ISR 작성 규칙 — 재진입 금지, 실행 시간 최소화 ## ISR 작성의 기본 원칙 ISR(Interrupt Service Routine)은 일반 함수와 다른 제약 조건 아래 동작합니다. 아래 원칙을 지키지 않으면 시스템이 불안정해지거나 디버그하기 어려운 버그가 생깁니다. --- ## 원칙 1 — 짧고 빠르게 ISR이 실행되는 동안 같은 코어의 **동등하거나 낮은 우선순위 인터럽트는 블록**됩니다. ISR이 길어질수록 다른 이벤트의 반응 지연이 커집니다. **권장 패턴: 플래그 세트 후 메인 루프에서 처리** ```c // 나쁜 예 — ISR 안에서 무거운 작업 IFX_INTERRUPT(uartRxISR, 0, ISR_PRIORITY_ASCLIN0_RX) { char buf[256]; int i = 0; while (데이터_있음()) { buf[i++] = 읽기(); // 시간 오래 걸림 } 처리_함수(buf); // 더 오래 걸림 } // 좋은 예 — 플래그만 세트, 실제 처리는 메인 루프 volatile uint8_t g_rxByte; volatile boolean g_rxReady = FALSE; IFX_INTERRUPT(uartRxISR, 0, ISR_PRIORITY_ASCLIN0_RX) { g_rxByte = IfxAsclin_getReadData(&MODULE_ASCLIN0); g_rxReady = TRUE; // 메인 루프에 신호 } // main loop if (g_rxReady) { g_rxReady = FALSE; processData(g_rxByte); } ``` --- ## 원칙 2 — 재진입(Reentrant) 금지 C 표준 라이브러리 함수 중 일부는 내부에 **정적 변수나 전역 상태**를 사용합니다. ISR에서 이런 함수를 호출하면, 메인 코드가 같은 함수를 쓰는 도중 ISR이 끼어들어 상태를 망가뜨릴 수 있습니다. ``` 재진입 문제 시나리오: main()이 printf() 실행 중 ↓ 인터럽트 발생 ↓ ISR이 printf() 호출 ↓ 내부 버퍼 상태 충돌 → 출력 깨짐 또는 하드폴트 ``` **ISR 안에서 피해야 할 것들:** - `printf`, `malloc`, `free` 등 재진입 불안전 함수 - 뮤텍스 없이 공유 데이터 구조 수정 - 블로킹 대기 루프 (`while (flag == 0) {}`) - 다른 ISR 호출 (직접 함수 포인터로 부르는 것 포함) --- ## 원칙 3 — 인터럽트 플래그 클리어 ISR 시작 또는 끝에서 해당 주변장치의 인터럽트 플래그를 **반드시 클리어**해야 합니다. 클리어하지 않으면 ISR이 무한 반복됩니다. ```c // STM 타이머 ISR 예시 (TC37x) IFX_INTERRUPT(stm0Sr0ISR, 0, ISR_PRIORITY_STM0) { // 플래그 클리어 — 다음 인터럽트를 위해 반드시 필요 IfxStm_clearCompareFlag(&MODULE_STM0, IfxStm_Comparator_0); // 다음 비교값 갱신 (주기적 인터럽트) IfxStm_increaseCompare(&MODULE_STM0, IfxStm_Comparator_0, STM_TICKS_1MS); // 실제 처리 g_tick1ms++; } ``` --- ## TC37x — IFX_INTERRUPT 매크로 iLLD에서 ISR을 등록할 때 사용하는 매크로입니다. ```c IFX_INTERRUPT(함수명, 코어번호, 우선순위번호) ``` ### 내부 동작 ```c // IFX_INTERRUPT 매크로 확장 예 (개념적) #define IFX_INTERRUPT(isr, vectabNum, prio) \ void __interrupt(prio) __vector_table(vectabNum) isr(void) ``` - `__interrupt(prio)` : TriCore 전용 ISR 속성, SRPN 지정 - `__vector_table(vectabNum)` : 어느 코어의 벡터 테이블에 배치할지 지정 - 컴파일러가 자동으로 컨텍스트 저장/복원 코드를 삽입 ### 실제 사용 예 ```c // Cfg_Irq.h 에 우선순위 정의 #define ISR_PRIORITY_STM0_SR0 10 #define ISR_PRIORITY_ASCLIN0_TX 20 #define ISR_PRIORITY_ASCLIN0_RX 30 // ISR 구현 파일 #include "Cfg_Irq.h" // STM0 비교 인터럽트 — CPU0, 우선순위 10 IFX_INTERRUPT(stm0Sr0ISR, 0, ISR_PRIORITY_STM0_SR0) { IfxStm_clearCompareFlag(&MODULE_STM0, IfxStm_Comparator_0); IfxStm_increaseCompare(&MODULE_STM0, IfxStm_Comparator_0, STM_TICKS_1MS); g_tick1ms++; } // ASCLIN0 TX 인터럽트 — CPU0, 우선순위 20 IFX_INTERRUPT(asclin0TxISR, 0, ISR_PRIORITY_ASCLIN0_TX) { IfxAsclin_Asc_isrTransmit(&g_asc); } // ASCLIN0 RX 인터럽트 — CPU0, 우선순위 30 IFX_INTERRUPT(asclin0RxISR, 0, ISR_PRIORITY_ASCLIN0_RX) { IfxAsclin_Asc_isrReceive(&g_asc); } ``` --- ## ISR 등록과 SRC 설정의 관계 `IFX_INTERRUPT` 매크로는 **벡터 테이블 등록**만 처리합니다. SRC 레지스터의 SRPN, TOS, SRE 설정은 별도로 해야 합니다. iLLD를 사용하면 모듈 초기화 함수 (`IfxXxx_initModule`) 내부에서 자동 처리됩니다. ``` IFX_INTERRUPT 매크로 → 벡터 테이블에 ISR 함수 주소 등록 모듈 초기화 (iLLD) → SRC 레지스터 SRPN/TOS/SRE 설정 두 가지 모두 필요 ``` --- ## ISR 실행 시간 측정 방법 (TC37x) STM 타이머를 이용해 ISR 진입/종료 시간을 측정할 수 있습니다. ```c volatile uint32 g_isrDuration; IFX_INTERRUPT(someISR, 0, ISR_PRIORITY_SOME) { uint32 start = STM0_TIM0.U; // 진입 시각 // ... ISR 처리 ... g_isrDuration = STM0_TIM0.U - start; // 소요 사이클 } ``` --- ## 정리 | 규칙 | 이유 | |------|------| | ISR은 짧게 | 다른 인터럽트 지연 방지 | | 플래그 세트 + 메인 루프 처리 | ISR 길이 최소화 | | 재진입 불안전 함수 금지 | 상태 충돌 방지 | | 인터럽트 플래그 클리어 | ISR 무한 반복 방지 | | IFX_INTERRUPT 매크로 | TC37x TriCore 전용 ISR 등록 방식 |
// COMMENTS
Newest First
ON THIS PAGE