ISR: Interrupt가 걸려 IRQ Exceptin이 발생 > IRQ Handler로 Branch > Interrupt 처리
//Exception Vector
AREA INIT_VECTOR, CODE, READONLY // INIT_VECTOR
CODE32 ; 32 bit ARM instruction set.
ENTRY
B Reset_Handler ; 0x0
B Undefined_Handler ; 0x4
B SWI_Handler ; 0x8
B Prefetch_Handler ; 0xC
B Abort_Handler ; 0x10
B Nothing_Handler ; 0x14
B IRQ_Handler ; 0x18 // 여기로 branch
B FIQ_Handler ; 0x1C
IRQ_Handler : Pipe line 때문에 lr -4 해줘야함 , sp : IRQ mode 의 sp 가르킴 > 이전 mode Register 백업해야함
>>
IRQ_Handler
ⓐ SUB lr, lr, #4
ⓑ STMFD sp!, {r0-r12, r14}
// r13 : SPSR 복구 > 이전 Mode SP 는 자동 복구됨
이제 isr_routine 으로
LDR r3, =ISR_ROUTINE // 저장하고 // 이때는 주소가 들어감
LDR r3, [r3] // 이때는 그 주소의 값(주소)이 들어감 " [ ] "
BLX r3 // 이동! : // BLX : Thumb 모드도 호환
> isr_routine 의 주소의 값이 들어감
:
ISR_ROUTINE 주소 보호
레지스터 값 활용의 유연성
동적 ISR 관리 ( Isr 바꿀때 벡터 테이블만 바꿔주면됨)
ex)
void customer_isr (void)
{
send_signal (waiter_task, SRV_SIGNAL)
}
이걸 isr 로 쓰려면
LDR r3, customer_isr
LDR r3, [r3]
BLX r3
이제.. interrupt 처리후 돌어간다면
LDMFD sp!, {r0-r2, pc}^ // SPSR을 다시 CPSR로 복구, lr을 pc에 넣어줌
//LDM , FD : 멀리플 로드 , full descending
>>>>
IRQ_Handler
SUB lr, lr, #4
STMFD sp!, {r0-r12, r14}
LDR r3, =customer_isr
LDR r3, [r3]
BLX r3
LDMFD sp!, {r0-r2, pc}^
// Irq handler 최종 구현
// " ^ " : SPSR을 CPSR로 복원
- CPSR: 지금 내가 무엇을 하고 있는지 기록하는 현재 메모.
- SPSR: 중요한 일이 생겼을 때, 지금 메모를 복사해서 보관한 백업본 ( 인터럽트, 오류 > cpsr 값 저장해둠)
void __irq IRQ_Handler (void) // __irq : C 언어로 하게 해줌 // ARMCC 로 compile
{
customer_isr();
}
IRQ_Handler
STMFD sp!,{r0-r4,r12,lr}
BL customer_isr
LDMFD sp!,{r0-r4,r12,lr}
SUBS pc,lr,#4 // pc 보정을 나중에함
>
SPSR을 CPSR로 보정해 주는 코드는 안 들어감
> 그냥 잘되는지 Test 용
Interrupt Controller : SoC(MCU) 에 있음, 인터럽트 여러개
>
인터럽트 발생> 콜랙터 내부Register 안에 어떤 인터럽트인지확인
ex) 0x8000000 에 내부 Register 라면
void __irq IRQ_Handler (void)
{
uint32 IRQ_NUM;
utin32 *which_irq = 0x8000000;
IRQ_NUM = *which_irq; // 0x8000000 주소로 가서 어떤 Interrupt가 걸렸는 지 값(주소) 확인
ISRVector [IRQ_NUM](); // 가져 온 값으로 해당 ISR 호출
// 함수 포인터 배열 > 각각의 주소를 저장 ( 참조한 주소의 값의 주소), 크기가 IRQ_NUM 만큼
// 배열 : () > ( 참조한 주소의 값의 주소 즉, 포인터값)배열 주소에 해당하는 함수를 호출
// ex)
void (*ISRVector[2])() = {isr_0, isr_1}; > ISRVector[0](); > isr_0 호출
>> 최종 완벽코드
void ISR_Handler (void)
{
uint32 IRQ_NUM;
volatile uint32 *which_irq = (volatile uint32 *)0x8000000; // 휘발성메모리 : cpu종료시 사라짐
IRQ_NUM = *which_irq;
ISRVector [IRQ_NUM]();
}
>> isr_handler 로 interrupt 콜랙터 로가서 그중 해당하는 interrupt 를 호출한뒤 (함수포인터배열)
// 이때 해당 함수의 주소를 호출함
IRQ_Handler
SUB lr, lr, #4
STMFD sp!, {r0-r12, r14}
LDR r3, = ISR_Handler
LDR r3, [r3] // R3에서 그 함수 주소의 값을 저장하고
BLX r3
LDMFD sp!, {r0-r2, pc}^ //복귀
ISRVector : void pointer 함수 type으로 주르르륵 선언해서 씀.
> Vector type ISR
IRQ handler를 길게짜면..
> interrupt 라서 잠깐 해야하는데 cpu 독점
> priority 낮은 tastk > starvation
> watch dog ( Timer )
중첩 == Nesting
interrupt 중 intterupt 가 또 걸림
> 기존 isr 동작을 clear 해주어 다음 interrupt 가 isr 로 진입하게해줌
> 우선순위 부여
ISRVector [IRQ_NUM]();
isrvector > 높은 우선순위
irqnum 함수 포인터배열에는 낮은 순위
>
counter 변수 > 시작 =1 , 끝남 =0
> if (counter == 0 )
{
IRQ 빠져나오고 다음 interrupt 가도록
}
'임베디드 > 임베디드 레시피' 카테고리의 다른 글
Clock Tick ISR (0) | 2025.01.07 |
---|---|
선점형 kernel (0) | 2025.01.07 |
TCB 구조 (0) | 2024.12.18 |
TCB - Task , CS (1) | 2024.12.17 |
선점형 Multitasking (0) | 2024.12.14 |