[컴퓨터구조 요약 정리] 15. SW for SoC 4

Embedded June·2021년 5월 21일
1
post-thumbnail

15.1. 인터럽트 처리 과정

  1. 현재 수행중인 프로그램을 일단 중지한다.
  2. 현재 수행중인 프로그램에 대한 정보(context)를 어딘가 (register, PCB)에 저장해둔다.
  3. 인터럽트 벡터 테이블 (IVT)에서 인터럽트의 종류와 그에 따른 handler (service routain)를 결정한다.
  4. Handler를 수행한다.
  5. 2번 과정에서 저장해둔 정보를 다시 restore해서 돌아온다.
  6. 1번 과정에서 멈췄던 부분부터 다시 프로그램을 수행한다.

Event-based processing

  • Polling 방식 - 처리될 때 까지 기다린다. Main task를 진행할 수 없을 수도 있다는 단점이 있다.
  • Interrupt 방식 - 인터럽트의 핸들러 (ISR)를 저장하고 있다가 수행할 수 있을 때 수행한다.

15.2. 인터럽트 HW 구성

image-20210520163035181

  • 인터럽트는 다양한 source (peripheral)로부터 발생할 수 있다.

  • 인터럽트를 최대한 빨리 처리해주기 위해 HW 에서는 위와같이 다단계 구조를 채택하고 있다.

  • 인터럽트의 종류에 따라 지나가는 HW가 달라질 수 있다. 일반적인 모든 인터럽트는 NVIC에서 관리하나, 일부 sleep mode에서 wake 시켜주는 인터럽트 같은 경우는 Wakeup Interrupt Controller (WIC)라는 곳에서 관리하는 모습을 확인할 수 있다.

  • 발생 가능한 인터럽트의 종류에 따라 처리 가능한 핸들러 (ISR)를 벡터 형태로 정의하고 있는데, 이를 interrupt vector table이라고 부른다. 여기에는 인터럽트의 종류와 ISR의 시작 주소가 저장돼있다.

  • image-20210520163657159

15.3. 인터럽트 HW 적인 요소

  • Peripheral (source)이 인터럽트를 발생시키는 원리에 대해서 알아보자.
  • NVIC는 32가지 인터럽트 source를 지원한다. 인터럽트를 32개 지원한다는 의미가 아니라 최대 32개의 인터럽트 발생 가능 peripheral이 연결될 수 있다는 뜻이다. 각 source는 NVIC의 IRQ라는 register가 관리하며 IRQ0 ~ IRQ31까지 있다.
  • 각 source에 대한 인터럽트는 사용자가 다양하게 직접 설정할 수 있다.
    • ISER register에서 해당하는 bit를 set/reset 함으로써 IRQn에 해당하는 source의 interrupt를 enable 할 수 있다.
    • ICER register에서 해당하는 bit를 set/reset 함으로써 IRQn에 해당하는 source의 interrupt를 disable 할 수 있다.
  • 주는 놈에 대한 세팅이 가능하다면, 받는 놈에 대한 세팅도 가능하다.
    • NVIC에 있는 PRIMASK register 값을 건들이면, MCU가 인터럽트를 받지 않게끔 설정할 수 있다.
    • 보통 시스템 상에서 정말 중요한 critical section을 수행하기 전에 IRQ를 disable하고, 해당 영역을 수행하고 다시 IRQ를 enable 할 때 사용한다.
  • 우리는 이전 수업에서 각 포트의 각 핀을 담당하는 pin control register(PCR)에 대해서 배웠다. PCR에는 IRQC라는 4-bit 공간을 통해 인터럽트가 발생할 조건을 설정할 수 있다.
    • image-20210520164453380
    • IRQC 설정도 앞서 배운 CMSIS에 정의된 API로 쉽게 설정할 수 있다.
    • PORTA->PCR[~~] = PORT_PCR_IRQC(9) | PORT_PCR_MUX(1) 이런 식으로 말이다.
  • 각 포트에는 인터럽트의 상태 정보를 저장하기 위한 register가 있는데, interrupt status flag register (ISFR)이라고 부르며, 현재 포트에 발견된 인터럽트와 관련된 정보가 저장된다.
  • 동시에 2개 이상의 인터럽트가 발생했을 때, 인터럽트 사이의 우선순위(Priority)를 결정할 수 있다.
    • Priority number가 작은 것이 더 높은 우선순위를 가진다.
    • 몇몇 exception이나 interrupt는 고정된 우선순위를 가진다. (i.e, reset, hard fault …)
    • NVIC는 8가지 priority register를 가지고 있지만, 위와 같이 고정된 우선순위가 있기 때문에 최대 4가지 source에 대한 우선순위를 관리할 수 있다. 각 우선순위 level은 0, 64, 128, 192 중 하나를 선택할 수 있다.

15.4. 인터럽트 SW 적인 요소

작성한 코드의 일부 동작을 인터럽트를 사용해야겠다고 결정한 뒤 ISR을 만들게 된다.

  • ISR은 input arguments가 없다. 따라서 main code의 variable을 수정하기 위해서는 해당 variable이 global (static) type 이어야 한다.
  • ISR은 return value가 없다. 따라서 ISR에서 어떤 data를 만들어서 main code로 넘겨주는 방법은 위와 같이 global variable을 만지는 것 뿐이다.
  • ISR의 이름은 우리가 마음대로 설정하는 게 아니라 CMSIS에 정의된 vector table에 이미 정의돼있다.

이때 ISR이 다룰 범위를 설정하는 것을 partitioning이라고 한다. Partitioning 방법에는 여러가지가 있는데, ISR은 긴급한 task를 신속하게 처리하기 위한 목적으로만 활용해야 한다는 점을 잊지말자.

image-20210520194339284

위 그림은 ISR이 다루는 범위를 크게 세 가지로 구분해서 예시를 들고있다. 주어진 상황은 MCU와 연결된 LED에 대한 동작을 ISR로 맡길 때 ISR이 다뤄야 하는 범위를 예로 들고 있다.

  1. Short ISR
    • ISR이 MCU와 연결된 switch1 과 2가 눌렸는지 여부만 검사한다.
    • Switch가 눌려서 상태가 변할 경우에 ISR이 수행되고, ISR은 오로지 switch 상태와 관련된 변수값만 update 해주는 역할만 수행한다.
    • LED를 점등하는 역할은 main code가 맡게된다.
  2. Medium ISR
    • g_flash_LED라는 1-byte flag 변수를 update해서 LED를 점등할지 혹은 소등할지 결정한다.
    • g_RGB_delayg_w_delay 변수를 update해서 LED를 점등 또는 소등을 유지할 시간을 결정한다.
    • 여전히 LED를 점등하는 역할은 main code가 맡게된다.
  3. Long ISR
    • LED 점등하는 역할까지 ISR이 맡는다.

ISR이 main code의 variable을 다루기 위해서는 shared variables를 사용해야하므로 static type으로 선언이 돼야한다. Static variable은 코드의 reusability와 readability를 떨어트리는 단점이 있기 때문에 개발자는 performance와 complexity 사이에서 저울질하며 balance가 좋은 partitioning을 하도록 노력해야 한다.

15.5. 정리

위에서 다룬 인터럽트의 HW 적인 요소와 SW 적인 요소를 합쳐서 정리해보자.

image-20210520204123552

인터럽트를 다루기 위해서는 Peripheral, NVIC, Core 세 가지 부분에서 인터럽트에 대해 설정해야 한다.

  • Peripheral에서 interrupt를 가능하게끔 설정해줘야 한다. Peripheral 내에도 register가 있을 것이고, 이를 설정해주는 코드를 만들어놓은 뒤 MCU에게 인터럽트를 걸거나 MCU로부터 인터럽트를 받을 수 있도록 설정해야 한다.
  • NVIC의 IRQ에 대해 설정해줘야 한다. APRC에 있는 IRQC bits를 설정해준다.
  • Core가 인터럽트를 받을지 말지를 결정해줘야 한다. Critical section을 얘기하면서 다뤘다.
void PORTD_IRQHandler(void) {  
	// 스위치 값을 읽는다
	if ((PORTD->ISFR & MASK(SW1_POS))) {	
		if (SWITCH_PRESSED(SW1_POS)) { // flash white
			g_flash_LED = 1;
		} else {
			g_flash_LED = 0;
		}
	}
	if ((PORTD->ISFR & MASK(SW2_POS))) {	
		if (SWITCH_PRESSED(SW2_POS)) {
			g_w_delay = W_DELAY_FAST;
			g_RGB_delay = RGB_DELAY_FAST;
		}	else {
			g_w_delay = W_DELAY_SLOW;
			g_RGB_delay = RGB_DELAY_SLOW;
		}
	}
	// clear status flags 
	PORTD->ISFR = 0xffffffff;
}

profile
임베디드 시스템 공학자를 지망하는 컴퓨터공학+전자공학 복수전공 학부생입니다. 타인의 피드백을 수용하고 숙고하고 대응하며 자극과 반응 사이의 간격을 늘리며 스스로 반응을 컨트롤 할 수 있는 주도적인 사람이 되는 것이 저의 20대의 목표입니다.

0개의 댓글