본문 바로가기
Robot/MCU

Cortex-M3 Peripheral : Nested Vectored Interrupt Controller (NVIC)

by lifeseed 2013. 10. 2.

 

※ 아래의 내용은 직접 작성한 내용이며, 경어를 사용하지 않았습니다.

읽으시는동안 불편하시더라도 이해 부탁드립니다.

 

0. 시작하기 전에

Cortex-M3 는 공통적으로 사용된다고 생각되는 Peripheral 을 Core에서 제공한다.

Nested Vectored Interrupt Controller

System Control Block

System Timer (SysTick)

그리고 마지막으로 Memory Protection Unit인데, MPU는 Optional로 지원이 되지 않는 Chipset도 있다.

 

이와 관련해서 참조해야할 문서가 있다.

ARM에서 제공하는 Cortex-M3 Device Generic User Guide와 Cortex-M3 Techenical Reference Manual 이다.

그리고 ARM에서 제공하는 기능들을 ST에서 정리하여 배포하는 Cortex-M3 Programming Manual이 있다.

 

이번 강좌에서는 NVIC에 대한 기본적인 컨셉 및 컨트롤 방법에 대해 알아보도록 하자.

 

1. NVIC 기본 컨셉

 

 

Cortex-M3 NVIC의 기본 컨셉 관련하여 정리한 그림이다.


Core에서 기본적으로 제공하는 16개의 exception handler를 제외한 chip vendor에서 제공하는 peri에 대한 interrupt처리를 컨트롤한다고 이해하시면 조금은 쉽게 다가갈 수 있다.

 

NVIC는 단순하게 설명하면, Chip vendor가 제공하는 Peripheral이 Interrupt가 발생되어 Cortex-M3 Core로 알려주면 Core에서 Interrupt Handler를 호출할지, 무시할지, 혹은 어떤 순서로 호출할지 등을 결정하는 역할을 한다.

 

Interrupt 발생 여부를 ISER, ICER Register를 통해서 결정하며, 각 Interrupt의 Priority를 인위적으로 IP를 통하여 변경할 수 있다.

 

Cortex-M3는 총 240개의 Interrupt를 NVIC로 컨트롤 할 수 있다.

 

다음은 Cortex-M3에서 제공하는 Excetpion Handler Table이다.

 

 offset

IRQ Num 

 exception handler

 4 x 0

 

 stack pointer

 4 x 1

 

 reset handler

 ...

 

 ...

 4 x 15

 

 system timer handler

 4 x 16

0

 EXT_IRQ0 handler

 4 x 17

 EXT_IRQ1 handler 

 ...

 

  ...

 4 x 255

239 

 EXT_IRQ239 handler

 

offset은 vector table에서 각 handler의 주소가 위치한 offset 값이며, address size가 4byte이므로, 4 x n 이라는 표현을 써 전체적으로 몇 번째에 위치한 handler인지 IRQ Num과 비교 가능하도록 표기 하였다. 

 

CMSIS에서는 NVIC를 컨트롤하는 인터럽트 number를 17번째 handler에 해당하는 즉 chip vendor가 제공하는 첫번째 interrupt를 IRQ number 0번으로 할당한다.

이렇게 고려할 때 NVIC register 를 직관적으로 Control 할 수있게 된다.

 

2. NVIC Register


1) ICTR

 몇개의 Interrupt가 NVIC에 연결되었는지 확인 할 수 있다.

 

2) ISER, ICER

Peripheral에서 Interrupt가 발생되었을 때, 실제 Core에서 Interrupt Handler가 호출되도록 설정

ICER은 그 반대로 Interrupt Handler가 호출되지 않도록 함.

ISER, ICER은 32bit Register가 8개 존재하며, 각 Bit에 의해 Interrupt가 enable, disable된다.

ISER0의 LSB 부터 1.의 Table에 정의된 IRQ_Num 0 부터 239번까지 할당된다.

 

다음은 IRQ_Num 에 따른 Register 할당 Map이다.

 

3) IPR

Interrupt의 Priority를 설정할 수 있다.

32Bit Register가 60개 존재하며 각 Interrupt를 위하여 8Bit가 할당된다. 즉 Priority는 0~255 범위내에서 변경가능하며, 0이 가장 높은 Priority를 가진다.

 

3. NVIC 구동 방법

Priority 설정은 우선 논외로 하고 Interrupt Handler가 호출되기 위해 필요한 동작을 알아본다.

1) Interrupt가 발생되기를 원하는 Chip Vendor의 Peripheral 을 Interruptable mode로 설정한다.

2) Interrupt Handler가 Vector table에 등록되어 있는지 확인 한다. IRQ_Num + 16 번째 등록되어야 한다.

3) NVIC의 IPR Register의 IRQ_Num에 해당하는 영역에 Priority를 설정한다. 

4) NVIC의 ISER Register의 IRQ_Num에 해당하는 Bit를 Set한다.

 

위와 같이 설정하면 Peripheral에 Interrupt가 발생하면 Interrupt Handler가 호출된다.

 

아래 그림은 STM32f10x 의 MD chipset 에 정의된 IRQ Number의 일부이다.

 

Core에서 기본적으로 제공하는 Handler의 IRQ Number는 음수값으로 정의되어 있으며, ST에서 제공하는 IRQ number들이 0 부터 정의되어 있다.

 

예를 들어 STM32F10x MD 계열의 chip에서 USART1 의 Interrupt를 처리하기 위해서는 다음과 같은 준비 작업이 필요하다.  참고로 USART1의 IRQ number는 37 이다.

A. UART_Handler 함수 등록 (일반적으로 Compile시 미리 등록하지만 다음과 같이 등록할 수도 있다.) 한다.

unsigned int vector_table_start_addr = *(unsigned int *)0xE000ED08 ;

// cf) 0xE000ED08 : System Control Block의 VTOR Registor로 Handler Vector Table 의 시작 주소를 가리킨다.

*(unsigned int *)(vector_table_start_addr + (16+37)x4 ) = UART_Handler;

//  cf) UART_Handler는 Vector Table에서 (16+37) x 4 의 offset 에 위치한다.

 

B. UART를 Interruptable Mode로 설정한다.

C. NVIC의 IPR을 설정한다.

*(unsigned char *)(0xE000E400+37) = prio; 

 

D. NVIC를 Enable한다.

unsigned int offset = (unsigned int)(37/32)*4;

unsigned int bitpos = (unsigned int (37%32);

 

*(unsigned int *)(0xE000E100+offset) |=  (1<<bitpos);

 

cf) Disable 할 경우는 다음과 같이 처리한다.

unsigned int offset = (unsigned int)(37/32)*4;

unsigned int bitpos = (unsigned int (37%32);

 

*(unsigned int *)(0xE000E100+offset) &=  ~(1<<bitpos);

 

4. CMSIS

ARM에서 제공하는 Library인 CMSIS에서는 Ver3.20을 기준으로 Core_cm3.h 에 다음과 같은 함수 및 Register 구조체를 제공한다.

1) Register 구조체

 

2) API

코드의 내용은 이미 구동방법에서 언급된 사항이라 크게 덧 붙일 내용은 없다.

단 Priority설정시 IRQn이 0보다 작은 경우가 포함되어 있는데, 이는 Core에서 제공하는 Execption Handler들의 Priority를 바꾸는 동작으로 System Control Block 강좌에서 설명하도록 하겠다.