CS/Embedded System

[실습] Interrupt & SysTick timer

WakaraNai 2021. 12. 7. 15:50
728x90
반응형

Interrupt Controller

MSP432P4111에서 제공하는 Cortex-M4의 처리방식을 보자

nested vectored interrupt controller (NVIC)로 interrupt를 처리

interrupt 안의 interrupt를 처리 가능

 

프로그래밍 코드로 제어 가능

-> (핀마다 다르게 내맘대로 가능)

multiplexed, shared interrupt를 지원

-> (공유되는 핀들이 microprocessor로 들어와서 interrupt 발생 시)

 

 

 

Interrupt Vector Table

microprocesser(up)에 interrupt가 오면

ISR의 위치를 찾아서 처리

 

function point array

  • s1버튼이 눌렸을 때 S1의 ISR의 위치를 찾을 수 있도록 function pointer가 저장되어 있어야 함
  • 각 ISR이 array의 index로 지정되어 있음

Register ISR for interrupt

  • 프로그래머는 반드시 vector table에 ISR과 register를 작성해야 함(등록)
  • function pointer의 주소를 vector table의 해당 위치에 써넣음

Handling interrupt in uP

  • vector table에 등록된 interrupt의 코드로 건너가서 실행하고 옴

 

 

Interrupt Vector Table for External Devices in MSP432

통신장치나 타이머가 내장되어 있음

물론 내부적으로 타이머 칩과 회로로 연결되어 있음

 

외부 interrupt는 I/O port p1-p6으로 라벨링되어있음 (버튼)

포트 6개 각 8개 핀 총 48개 핀

너무 많으니 한 포트의 1번 핀이 interrupt를 발생하면

이를 포트 내에서 공유하여

p1에서 multiplexed, shared된 interrupt라고 말함

 

s1버튼을 처리하는

interrupt service routine 작성하고

vector table에 등록하기

 

1. vector table 생성하기 : 각 항목에 function point를 지정

 

 

2. Default dummy interrupt handler

기본적으로 interrupt는 아무 일도 안하고 기다리게 하기 위해 

default handler는 텅 비어있음 (dummy)

 

 

3. ISR function (Handler) 선언

PORT1_IRQHandler를 부르면 알아서 Default Handler가 실행됨

weak 키워드는

같은 이름의 함수를 작성해버렸을 때

약하게 정의한 default handler 대신에

당신이 작성한 함수가 실행되도록 해줌


[실습1] Polling 대신 interrupt로 버튼을 처리해보자

1번 핀을 0으로 설정하여 P1.0을 가리킴  (11111101)

P1->OUT=BIT1로하여 pull up모드 - (S1 버튼은 VCC에 연결되기 때문)

나머지 검은색 명령어가 interrupt 를 연결하는 명령어

 

Interrupt Edge Select register (IES)

IES의 BIT1을

0으로 하면 LOW TO HIGH transition

1로 하면 HIGH TO LOW transition

 

Interrupt pending/flag register (IFG)

P1포트 자체로 share하여 interrupt가 들어오기에

s1 버튼인지 s2 버튼인지 구별하는 과정이 필요

 

처음에는 모든 flag를 0으로 초기화

flag는 어떤 장치에서 발생했는지도 알 수 있고

현재 interrupt를 처리하고 있는지도 알 수 있음

 

00000010 이면 1번 핀에 interrupt를 발생했음을 앎

00000000으로 interrupt처리가 끝났음을 알림

 

 

 

Interrupt Enable register (IE)

 

+) Masking/Unmasking Interrupt

= 2 stage multiplexed interrupt delivery

masked를 하면 interrupt가 발생했는지 볼 수 없게 함

1) 각 핀의 interrupt는 Digital I/O controller에 의해 masked or unmasked

2) 각 I/O의 interrupt는 masked됨

 

 

NVIC Enable Interrupt

32bit에서 35번 핀을 표현하기 위해…

0bit가 32번으로 시작하여 3 자리에 1이 쓰여야 함 


 

버튼 입력 후 일정 시간이 지나야 할 때

기다리는 동안 아무것도 하지 않는 것이 아니라

조금씩 하기 위해

interrupt를 사용

 

 

특정 시간동안 기다리거나

주기적으로 해야하는 일이 있을 때

몇 초 뒤에 어떤 일을 시작해야하는지

외부 장치를 시간에 따라 제어해야할 때

timer 사용

+) for(int i=0;i<10000;i++); 처럼 억지로 delay를 넣는 식으로 하면

나중에 실행시간 + delay로 인해 정확히 동시간대에 tick하는 것처럼 안 됨

그래서 timer를 쓰는 게 좋음

 

SysTick timer

운영체제를 사용하고자 하는 시스템이라면

운영체제에 제공할 타이밍이 있을 때 사용

24bit의 단순체계. 

10->...->0->10 이기에

감소하다가 다시 올리는 식으로 반복해서 사용

 

reload value register에 count 값을 설정

초단위로

해당 시점이 한 주기에서 어느정도 흘렀는지

1->0일 때 system interrupt 설정도 가능

24bit로 범위는 0x00000000 ~ 0x00ffffff

 

예로 reload value를 1000이라고 하면

1000 / (100*1000000) = 0.0001 sec = 10usec마다 count down

 

SysTick Register

  1. systick control and status
    1. count down을 반복할 지(ENABLE) 한 번만(TICKINT) 할 지
  2. systick reload value register : 몇 초마다의 몇을 설정, 1초에 몇 번?
    1. 초기화 과정을 통해 SystemCoreClockUpdate()하면
    2. “system_msp432p4111.c” uint32_t global data 변수 값을 조정
  3. systick current value register
    1. handler 찾아서 실행
  4. systick calibration value register (read-only)
    1. 현재 시간 확인 또는 pollin으로 쓰고 싶을 때

 

 

[실습2] Blinking LED Revisited

interrupt를 이용하여 S1버튼을 눌러서 on/off 구현하기

interrupt를 이용하여 S1버튼을 눌러서 on/off 구현하기

보면 main()에 초기화 코드 이후에 아무것도 안 하는 loop가 있음

그리고 main()과 ISR 사이 shared data 없음

// Turn on and off when S1 User button is pressed using
an interrupt
void main(void)
{
  P1->DIR = ~(uint8_t) BIT1;
  P1->OUT = BIT1;
  P1->REN = BIT1;
  P1->IES = BIT1;
  P1->IFG = 0;
  P1->IE = BIT1;
  NVIC->ISER[1] = 1 << ((PORT1_IRQn) & 31);
  
  while(1) {}
}


/* Port1 ISR : Interrupt handler for S1 User button */
void PORT1_IRQHandler(void)
{
  // Toggling the output on the LED
  if(P1->IFG & BIT1)
  	P1->OUT ^= BIT0;

  P1->IFG &= ~BIT1;
}

 

S2 버튼을 눌렀을 때 RGB LED의 빨간색 on/off

주의!! 

S1과 S2 버튼은 PORT1_IRQHandler()를 공유하고 있음

void PORT1_IRQHandler(void)
{
  if(P1->IFG & BIT1)
	  ... // handle S1 button interrupt and clear interrupt for BIT1
  if(P1->IFG & BIT4)
	  ... // handle S2 button interrupt and clear interrupt for BIT4
}

 


Timers in MSP432(Cortex-M4)

총 6+2개 timer

  • TA0, TA1, TA2, TA3는 16bit timer와 counter
  • Timer32는 ARM dual 32bit timer module. 2개의 32bit timer를 포함, 각 2개의 독립적은 16bit timer로 구성됨

SysTick timer

  • embedded system의 OS에서 timing service를 제공하는 system timer로 사용
  • wrap-on-zero counter를 간단하게 24bit로 줄일 수 있는 integrated system timer

 

SysTick Timer 

SysTick이 작동하면

Reload value register 값을 0으로 하나씩 감소

 

SysTick Reload Value Register

24bit counter

(0x00000000 ~ 0x00FFFFFF)

만약 reload 값을 1000으로 input clock을 100Mhz로 했다면

timer는 1000/(100*10^6) = 0.00001sec = 10usec만큼 감소

 

SysTick Current Value Register

read current timer counter

(interrupt를 사용하지 않을 때 timer를 읽는다는 건 poll의 의미로 사용한다는 것?)

 

SysTick Control and Status Register

 

interrupt는 발생할 수도 안 할 수도

  • systick은 systick interrupt handler를 부르는 interrupt를 발생시킬 수도 안 할 수도
  • systick control register 속 TICKINT bit로 결정

한 번만 또는 반복하며 감소함

  • periodic timer의 경우, timer reload value는 reset 또는 원래 값으로
  • systick control register 속 ENABLE bit로 결정

 

<systick timer to activate periodic timer interrupt>

//Register your own SysTick interrupt handler
void SysTick_Handler(void)
{
...
}

int main(void)
{
//Default procedures for SysTick timer
//to activate a periodic timer interrupt

// Enable SysTick Module
SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk |

SysTick_CTRL_ENABLE_Msk;
// Set SysTick period = 0x20000
SysTick->LOAD = 0x20000 - 1;

// Clear the SysTick current value register by writing
// a dummy value
SysTick->VAL = 0x01;

// Enable SysTick interrupt
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;

 

 

 

 

[실습3] 매 100ms마다 Red LED on/off

50ms 키고 50ms 끄기 반복

-> tick value - 50ms

-> SystemCoreClock = 1sec/20 = 50ms (1sec=1000ms)

void SysTick_Handler(void)
{
  P1->OUT ^= BIT0; // Toggle P1.0 LED
}

int main(void)
{
  SystemCoreClockUpdate();
  
  // Configure GPIO
  P1->DIR |= BIT0;
  P1->OUT &= ~BIT0;
  
  // Enable SysTick Module
  SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk |
  SysTick_CTRL_ENABLE_Msk;
  SysTick->LOAD = SystemCoreClock/20 - 1;

  // Clear the SysTick current value register by writing
  // a dummy value
  SysTick->VAL = 0x01;
  
  // Enable SysTick interrupt
  SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;
  
  while (1)
  {
  }
}

 

[실습4] 매 12sec 마다 Red LED on/off

SysTick->LOAD를 

SystemCoreClock/20 에서 SystemCoreClock*6으로 수정

 

근데 이러면 reload value register의 범위인 24bit를 초과 

 

만약 SystemCoreClock = 3Mhz=3*1000000,

즉 3000000ticks/ 6 sec = 18000000으로

tick 최대값인 16777215를 초과

 

그래서 timer prescaler를 이용

longer time period를 지원

 

 

 

정리

 

 

 

Use SysTick interrupts for blinking the Red LED
to the project in Lab Assignment 7
– However, buttons are still handled by polling

728x90
반응형