Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

꾸준히

인터럽트 본문

RTOS

인터럽트

S210530 2022. 10. 22. 14:50

인터럽트 처리 과정

  1. 인터럽트 컨트롤러를 초기화하고 사용하는 코드를 작성
  2. 실제 인터럽트를 발생시키는 하드웨어와 인터럽트 컨트롤러를 연결
  3. 하드웨어가 인터럽트를 발생시키면 인터럽트컨트롤러로 인터럽트 신호를 보냄
  4. 인터럽트 컨트롤러는 ARM 코어로 인터럽트를 보냄
  5. 펌웨어에서 cpsr의 IRQ 혹은 FIQ 마스크를 끄면 IRQ나 FIQ가 발생했을 때 코어가 자동으로 익셉션 핸들러를 호출
  6. 익셉션 핸들러에서 적절한 인터럽트 핸들러를 호출
  7. 인터럽트 핸들러에서 인터럽트를 처리하면 완료

 

Block Diagram

인터럽트 처리 과정

 

Code

1. 인터럽트 컨트롤러를 초기화하고 사용하는 코드를 작성

static InterHdlr_fptr sHandlers[INTERRUPT_HANDLER_NUM];

// initialize interrupt controller
void Hal_interrupt_init(void)
{
    GicCpu->cpucontrol.bits.Enable = 1;
    GicCpu->prioritymask.bits.Prioritymask = GIC_PRIORITY_MASK_NONE;
    GicDist->distributorctrl.bits.Enable = 1;

    for (uint32_t i = 0 ; i < INTERRUPT_HANDLER_NUM ; i++)
    {
        sHandlers[i] = NULL;
    }

    enable_irq();
}

// interrupt enable
void Hal_interrupt_enable(uint32_t interrupt_num)
{
    if ((interrupt_num < GIC_IRQ_START) || (GIC_IRQ_END < interrupt_num))
    {
        return;
    }

    uint32_t bit_num = interrupt_num - GIC_IRQ_START;

    if (bit_num < GIC_IRQ_START)
    {
        SET_BIT(GicDist->setenable1, bit_num);
    }
    else
    {
        bit_num -= GIC_IRQ_START;
        SET_BIT(GicDist->setenable2, bit_num);
    }
}

// interrupt disable
void Hal_interrupt_disable(uint32_t interrupt_num)
{
    if ((interrupt_num < GIC_IRQ_START) || (GIC_IRQ_END < interrupt_num))
    {
        return;
    }

    uint32_t bit_num = interrupt_num - GIC_IRQ_START;

    if (bit_num < GIC_IRQ_START)
    {
        CLR_BIT(GicDist->setenable1, bit_num);
    }
    else
    {
        bit_num -= GIC_IRQ_START;
        CLR_BIT(GicDist->setenable2, bit_num);
    }
}

// register interrupt handler
void Hal_interrupt_register_handler(InterHdlr_fptr handler, uint32_t interrupt_num)
{
    sHandlers[interrupt_num] = handler;
}

// run interrupt handler
void Hal_interrupt_run_handler(void)
{
    uint32_t interrupt_num = GicCpu->interruptack.bits.InterruptID;

    if (sHandlers[interrupt_num] != NULL)
    {
        sHandlers[interrupt_num]();
    }

    GicCpu->endofinterrupt.bits.InterruptID = interrupt_num;
}

 

* cpsr에 irq, fiq 모드로 적용하기 위한 코드 (위 코드에서 enable_irq())

void enable_irq(void)
{
    __asm__ ("PUSH {r0, r1}");
    __asm__ ("MRS  r0, cpsr");
    __asm__ ("BIC  r1, r0, #0x80");
    __asm__ ("MSR  cpsr, r1");
    __asm__ ("POP {r0, r1}");
}

void enable_fiq(void)
{
    __asm__ ("PUSH {r0, r1}");
    __asm__ ("MRS  r0, cpsr");
    __asm__ ("BIC  r1, r0, #0x40");
    __asm__ ("MSR  cpsr, r1");
    __asm__ ("POP {r0, r1}");
}

void disable_irq(void)
{
    __asm__ ("PUSH {r0, r1}");
    __asm__ ("MRS  r0, cpsr");
    __asm__ ("ORR  r1, r0, #0x80");
    __asm__ ("MSR  cpsr, r1");
    __asm__ ("POP {r0, r1}");
}

void disable_fiq(void)
{
    __asm__ ("PUSH {r0, r1}");
    __asm__ ("MRS  r0, cpsr");
    __asm__ ("ORR  r1, r0, #0x40");
    __asm__ ("MSR  cpsr, r1");
    __asm__ ("POP {r0, r1}");
}

 

2. 실제 인터럽트를 발생시키는 하드웨어와 인터럽트 컨트롤러를 연결

2-1) 익셉션 벡터와 익셉션 핸들러 연결

vector_start:
        LDR PC, reset_handler_addr
        LDR PC, undef_handler_addr
        LDR PC, svc_handler_addr
        LDR PC, pftch_abt_handler_addr
        LDR PC, data_abt_handler_addr
        B   .
        LDR PC, irq_handler_addr
        LDR PC, fiq_handler_addr

        reset_handler_addr:     .word reset_handler
        undef_handler_addr:     .word dummy_handler
        svc_handler_addr:       .word dummy_handler
        pftch_abt_handler_addr: .word dummy_handler
        data_abt_handler_addr:  .word dummy_handler
        irq_handler_addr:       .word Irq_Handler // irq exception handler
        fiq_handler_addr:       .word Fiq_Handler // fiq exception handler
vector_end:

 

2-2) uart 인터럽트와 핸들러 연결

// uart interrupt handler
static void interrupt_handler(void)
{
    uint8_t ch = Hal_uart_get_char();
    Hal_uart_put_char(ch);
}

void Hal_uart_init(void)
{
    // Enable UART
    Uart->uartcr.bits.UARTEN = 0;
    Uart->uartcr.bits.TXE = 1;
    Uart->uartcr.bits.RXE = 1;
    Uart->uartcr.bits.UARTEN = 1;

    // Enable input interrupt
    Uart->uartimsc.bits.RXIM = 1;

    // Register UART interrupt handler (interrupt controller)
    Hal_interrupt_enable(UART_INTERRUPT0);
    Hal_interrupt_register_handler(interrupt_handler, UART_INTERRUPT0);
}

 

3. 익셉션 핸들러에서 적절한 인터럽트 핸들러를 호출

 // irq exception handler
 __attribute__ ((interrupt ("IRQ"))) void Irq_Handler(void)
{
    Hal_interrupt_run_handler();
}

// fiq exception handler
 __attribute__ ((interrupt ("FIQ"))) void Fiq_Handler(void)
{
    while(true);
}


* arm용 gcc의 전용 확장 기능으로써 irq, fiq의 핸들러에 진입하는 코드와 나가는 코드를 자동으로 만들어 줌

__attribute__ ((interrupt ("IRQ"))) void Irq_Handler(void)
__attribute__ ((interrupt ("FIQ"))) void Fiq_Handler(void)

 

4. 인터럽트 처리

static void interrupt_handler(void)
{
    uint8_t ch = Hal_uart_get_char();
    Hal_uart_put_char(ch);
}

 

'RTOS' 카테고리의 다른 글

이벤트와 메시징  (0) 2022.10.22
Task  (0) 2022.10.22
HAL  (0) 2022.10.22
Startup.s  (0) 2022.10.10
FW와 RTOS의 차이  (0) 2022.10.10