CS/Embedded System

SW Architecture - RR, Interupt, func-queue scheduling, RTOS

WakaraNai 2021. 12. 7. 00:01
728x90
반응형

Software architecture for Embedded System

event handler : 어떠한 이벤트가 발생했을 때 이를 처리하는 코드를 수행하는 것

software architecture는 이벤트 감지 방법 및 호출 방법에 따라 달라짐


Architecture 1: Round-Robin

== polling 방식

순서대로 (우선순위)

특정 이벤트 발생 여부를 감지하고

발생 시 event handler를 실행

 

장점 : simplicity(딱 일 하나), no shared data, no ISRs (interrupt service routine)

 

 

저항을 재는 코드가

전압을 재는 코드 위에 있어서

event handler는 자신의 차례가 올 때까지 기다려야 함..

 

다시 확인하고 싶다면

나머지 모든 경우를 확인하고 자신의 차례로 올때까지 기다려야 함

최악의 경우는 한 차례 반복을 다 거치는 경우

 아니면 유난히 느린 이벤트에 걸리거나,,,

응답 시간도 점점 길어지게 됨.

임베디드 시스템은 실시간성을 보장해야 하는데ㅠ

또 하다보면 이벤트 핸들러를 추가해야할 때도 있을 텐데ㅠ

 

디지털 멀티미터처럼

입력 개수와 이벤트 수가 적고

응답 시간이 큰 제약 사양이 아닐 때 Round Robin 사용

(ex - 전자렌지, 오븐)

 

 

<응답 시간을 줄이는 방법!>

중요한 것은 매번 다시 검사하는 식으로

 

단점

  • 최악의 경우 전체 반복문 시간만큼 걸림 ( ISR을 따로 두어도 마찬가지)
    • 하나의 이벤트를 중복 확인하는 것도 event 가지 수가 적을 때만 가능하지..
  • 매 event마다 응답 시간이 최악임.  하나라도 아주 긴 processing에 걸리면..
  • system이 취약해짐. 새로운 event handler를 추가하다 다른 event를 놓치는 deadline이 발생할 수 있음

Interrupt

Basics

interrupt : Processor는 하고 있던 일을 잠시 멈추고 event를 처리 후 이어서 진행

ISR : interrupt service routine

 

장점: 이벤트의 처리 시간, delay는 일정함 (멈추고 바로 하니까)

 

multitasking system에 우선순위 대로 실행되어야 할 때는 interrupt는 필수

중요한 코드를 먼저 실행할 수 있도록 하기 때문

poll loop보다 소프트웨어 복잡도가 훨씬 적어짐

 

ex) CPU context를 둠으로써 하드웨어의 준비를 기다림 - 어셈블리어로 구현

 

 

Interrupt 발생 요인

  • I/O 장치에서 데이터 도착
  • I/O 장치에 이전에 보낸 요청이 끝났을 때
  • sensor 값이 바뀌었을 때
  • 사용자의 action (press btn)
  • 에러 및 결함 감지
    • external to CPU (hw specific)
    • internal to CPU (exception)
  • timer expiration (매 60초마다 무슨 일을 하고 싶을 때)
  • power failure

 

Interrupts : HW+SW

HW side

simple model에서는

  • interrupt가 발생하면
  • HW는 current task에 대해 information을 저장한다
  • interrupt service routine : 각 핀 별로 이벤트 발생 시 실행되어야 할 코드를 호출
    • 그럼 어디에 있는 어떤 ISR를 찾는 걸까?
      • SW가 그 정보를 HW에게 제공

 

Hardware에서의 문제라면...

  • delay in responding
  • saving state
    • ISR은 함수 형태로 구현됨 (이 함수의 정보가 state)
    • interrupted SW는 register를 저장할 수 없기에 ISR이 모두 저장한다
  • Finding correct routine
    • ISR 시작 주소에 대한 테이블 : interrupt vector table
    •  interrupt number or level을 인덱스로

 

 

<CPU가 interrupt 발생 요인을 “찾는 방법”>

연결된 모든 interrupt에 있는 ISR를 확인하기

CPU에는 데이터핀 뿐만 아니라 interrupt pin(line)도 여러 개 달려 있음

해당  interrupt pin(line)에 맞는 ISR을 ISR 테이블에서 찾아서 이벤트 발생

 

<nested interrupt 처리>

덜 중요한 interrupt가 실행 중인데 아주 중요한 interrupt가 들어오면

hold하고 그걸 처리

즉시 중지하지는 않음 - 약간의 지연을 둠

그만큼 ISR와 Handler를 문제 없이 작성하는 것은 쉽지 않음

 

I/O with Interrupt

BUSY-WAIT LOOP : 계속 들어왔는지 확인하니 비효율적 (poll)

interrupt request signal : I/O 장치가 프로세서에게 준비되었다고 알리는 방식을 쓰자

 

엄청난 양의 계산을 하고

주기적으로 결과를 화면에 출력해야 할 때

그럼 sw는 compute와 display에 대한 routine을 가지고 있어야 함

display해야 할 때 compute i번째까지 완료하고( hold하고) display를 수행

이 때 display는 interrupt service routine.

temporary location에 i번째 위치를 저장

 

interrupt-acknowledge signal이 processor로부터 device로 감

timer에게 전달하여 timer 끼리 이 과정을 수행

인식되면 device는 이 interrupt request를 삭제

 

What is shared data problem?

ISR에 의해 shared data가 update되면

불일치성에 유의해야 함 - > interrupt를 잠시 끄고 킴

급한 것만 처리하고, 나머지는 task code에 떠넘겨버림

다시 task가 수행할 때 잠시 저장해둔 것을 꺼내어 완료

 

 

불일치성 예시

하드웨어의 타이머가 매 1초마다 마이크로프로세서에 신호를 보냄

마이크로프로세서는 interrupt을 발생하여 hw로부터 값을읽음

 

온도를 서서히 올리다가 아주 운이 나쁘게 0.00001초 차이로

같아야 하는데, 하나는 80도, 하나는 81로 잘못 읽어서 기계가 멈춤

 

두 값을 직접 읽어온다고 해도 불가능


해결책 : interrupt 키워드 명시 

그래서 두 값을 읽는 순간에는 timer interrupt 장치를 꺼서 막음




Architecture 2 : Round-Robin with Interrupt (1)

polling loop에서

interrupt를 감지하기 위해

ISR이 flag로 표시

 

시간이 중요한 응답의 경우

ISR에서 처리하고

그게 아니라면 handler에서 처리

 

최악의 경우

ISR이라면 중간 우선순위 처리 중에 더 높은 우선순위가 들어오면

두 개 다 걸린 시간을 합쳐서, 즉 나보다 높은 우선순위에 대한 실행시간을 다 합쳐서 계산

handler : 모든 handler에 걸려서  전체를 합하는 경우

 

그럼에도 ISR을 사용하는 경우는

우선순위대로 처리한다는 장점 때문.

다만 ISR과 handler는 데이터를 공유하기 때문에

shared data로 인한 문제점 발생

 

Example : communications bridge(1)

상대편에게 암호화하여 보내어 받으면 복호화는 장치들이 필요

(fromA, fromB, toA, toB)

buffer에 쌓아두고 차례대로 암호화/복호화

제한된 크기의 buffer이기에 data loss 주의 - 그래서 빠르게 처리할 수록 좋음

 

buffer는 큐로 구현

 

그러므로 interrupt 발생할 상황을 구현해둠 (data 도착,  clear link of send)

여기서 ISR은 데이터가 버퍼에 도착했음을 그리고

모두 보냈음을 flag로 설정하여 알림

 

 

 

코드

polling loop : (fromA, fromB, toA, toB) buffer
Interrupt 구현: link 별로 받은 char를 해당 link의 buffer에 append. 전송 시에 ready 상태로 표시

 

Interrupt 구현: buffer에 data가 있다면 꺼냈다가 암호화/복호화 하여 다시 저장

 

 

공유되는 자원에 접근하기 전에 잠시 껐다가 킴. 그동안은 interrupt를 허용하지 않도록 제한


 

Architecture 3: Function-queue scheduling

큐에 새로운 job이 들어왔는데

이전에 있는 것보다 먼저 실행되어야 하는 대상이라면 

기존의 것을 뒤로 밀어내고

방금 넣는 것을 맨 앞에 위치할 수 있도록 옮겨줌

 

 Function Pointer

정의 : pointers. 함수의 주소를 가리키는 변수

여기에 주소 변수 이름만 쓰는게 아니라 

함수의 이름과 그 함수의 리턴값, 입력값과 데이터형도 함께 넘겨줌

 

위의 코드에서 task = get_queue(); 코드가 바로 이 방식으로 동작

큐에 우선순위가 높은 것을 앞으로 땡기기 위해서

 

 



Characteristic of function-queue scheduling

 우선순위 대로 - handler도 우선순위 대로 처리가 가능해짐

최악의 경우라도 이미 수행된 task의 가장 긴 수행시간 만큼만+ ISR 실행시간

(delay = longest task time + execution time for ISRs) 

 

장점: 코드 변경에도 향상되고 안정된 응답 시간을 보임

단점: 복잡성이 올라감. function queue 유지해야 함

 

 


Architecture 3: RTOS real-time os

scheduler에 의해 task를 우선순위대로 처리

우선순위 높은 것이 준비가 되면 CPU를 선점

 

task는 이벤트가 발생하기 전까지 대기

ISR이 task가 block state로 가도록 함

task가 스스로 delay 시간을 가질 수도 있음

 

Characteristic of RTOS

interrupt에도 우선순위 존재

높은 우선순위에 대한 응답시간이 굉장히 빠름

코드를 변경해도 낮은 우선순위 일이 높은 우선순위의 응답시간에 영향을 미치지 않음

 

소프트웨어가 점점 복잡해지고 

runtime overhead가 발생

 


적절한 Architecture를 선택하자!!

요구되는 현재, 미래의 응답 시간을 만족하는 가장 간단한 architecture를 고르자

 

만약 application에 응답 시간이 별로라면 RTOS를 하자

디버깅 기능까지 있으니

 

hybrid architecture 설계를 고려하자 - 예로,

RTOS는 실제로 하나의 task에 대해 poling으로 구현되어 있음

round robin with interrupts - main loop polls slower HW directly

 

728x90
반응형