임베디드/임베디드 레시피

ISR구현

twoweeks-within 2025. 1. 7. 10:37

 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