Raspi3 OS 만들기위해 Interrupt코드를 구현하면서 헷갈리는 부분이 있다. 먼저 이해한 내용을 정리하면
1. ARM Interrupt
기본적으로 라즈베리파이역시 Broadcom의 ARM기반 chipset으로 ARM Interrupt 즉 IRQ, FIQ의 모드를 따라 구현되어있다.
인터럽트 모드는 크게 2가지 IRQ, FIQ가 되고 FIQ의 경우 n번의 거침없이 곧 바로 연결되는 인터럽트로 좀 더 빠른 우선순위 높은 인터럽트 처리를위해 사용되는 모드이다.
우선은 Interrupt개발을 위해 FIQ는 재껴두고 IRQ에 대해서 고민해보자
인터럽트를 실행하기 위해서는 기본적으로 User, Kernel 모드 등 다양한 모드에서 동작중인 OS가 인터럽트신호를 감지하게 되고 이를 Trigger로 하여 IRQ 모드로 진입하게 된다.
그리고 위와같은 이루어진 ARM의 6가지 모드는 공유하는 레지스터도있지만 각자 다른 레지스터를 사용한다.
가장 먼저 IRQ 모드 진입전에 IRQ모드로 진입할 수 있도록 상태레지스터에 I를 의미하는 bit를 set해준다. 이는 IRQ 모드를 지원한다는 의미이기 때문에 init과정에서 set이필요하다.
이후 인터럽트 신호를 받게되면 PC 레지스터에 0x18(IRQ 모드)로 진입하기위한 준비를 한다.
그리고 IRQ모드로 진입하게 되는데 이 때 위에서언급한 내용과같이 이전 모드와 IRQ모드에서 공유해서사용하는 레지스터의 경우 정보가 날아가지않게 백업이 필요하다.
즉 0x18 주소로 무조건 오는것을 이용하여 해당 주소에서 레지스터 백업 과정과 인터럽트 핸들러 function 으로 jump해주는 코드를 작성한다.
인터럽트 핸들러에서는 IRQ번호에맞게 해당 핸들러 function으로 점프해주면된다.
그럼 정상적으로 handler함수가 실행되고 다시 돌아와서 레지스터 백업된 내용을 돌려받고 원래 모드로 돌아가게 된다.
2. Linux Interrupt
위 ARM의 기본적인 인터럽트 동작에 대한 내용을 이해하고나면 Linux Kernel에 Interrupt 구현부분을 주목해볼 수 있다.
Linux kernel을 보면 IRQ 값들은 이미 모두 정의가 되어있다. (Linux Kernel내 broadcom2835(raspi) 코드를 보면 9번은 USB이고 이런식으로 정의가 쭉 되어있음)
그리고 request_irq를 통해서 핸들러를 해당 임의의 IRQ에 사용자 임의로 연결할 수 있고 이렇게 연결된 IRQ 인터럽트가 실행되면 사용자가 연결한 function이 핸들러함수로 실행된다.
만약 안드로이드 등의 OS와 마찬가지로 Linux 기반의 OS를 만든다면 위 Linux Kernel Interrupt구문을 참조할 수 있다.
이렇게 되면 내가 임의의 GPIO 값에 인터럽트 핸들러를 작성한다고 할 때 gpio_request를 통해서 임의의 GPIO의 IRQ번호를 획득하고 이렇게 얻은 값을 바탕으로 request_irq를 진행하여 핸들러를 등록할 수 있다.
단 이렇게 되면 Linux Kernel에서 기본적으로 등록된 IRQ에 대해서만 인터럽트를 실행할 수 있을 것이다.
(우선 이게 맞는지 모르겠음..)
3. 직접 만든다면?
만약 내가 Linux Kernel을 이용하지않고 직적 핸들러나 IRQ를 등록한다면 어떻게 될까?
handler를 등록하는 방법은 arm특징을이용하여 0x18(IRQ모드 시작지점) 에 내가 원하는 logic을 추가하여 임의의 핸들러가 동작하게끔 구현할 수 있다.
하지만 여기서 내가 궁금한 부분은 IRQ의 등록부분이다.
IRQ 모드로 진입한다는 것은 이미 IRQ번호대로 인터럽트가 정의되어있다는 것이다. 즉 예를들어 GPIO n번핀으로 HIGH신호가 오면 IRQ 2번이다 이런식으로 모두 정의가 되어있는것이고 이후 pulse변화를 감지해서
IRQ 모드로 진입하고 인터러븥 핸들러를 실행하기 떄문이다.
결과적으로 내가 직접만든다면 어떻게 IRQ 정의를 진행할 수 있는지 의문이다. 이를 위해서는 내가 어떤 PIN에서 어떤 Pulse(High, Low, Rising, Falling)에 따라 IRQ n번이 동작한다고 정의를 해야하는데 이부분을 어떻게 구현해야하는지 모르겠다.
기본적으로 BCM2835 datasheet을 보면 default로 정의된 ARM peripheral interrupt가 존재하긴하지만 대부분의 interrupt IRQ 번호 GPU IRQ의 경우 정의가 되어있지 않은것으로 보여진다. 그럼 어떻게 정의해야하는것일까?..
(이 부분을 계속해서 고민하고 검색하고 있지만 아직 답을 찾지는 못하고 있다..)
'OS > Firmware Project' 카테고리의 다른 글
[MOON OS] Moon OS Project (4) - GPIO(2) (0) | 2022.09.28 |
---|---|
[MOON OS] Moon OS Project Check point (0) | 2022.01.01 |
[MOON OS] Moon OS Project (2) - GPIO (0) | 2021.09.20 |
[MOON OS] Moon OS Project (1) - Barebone code (0) | 2021.08.21 |
[OS] Firmware Project (8) - Event (0) | 2021.08.02 |