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
- systick control and status
- count down을 반복할 지(ENABLE) 한 번만(TICKINT) 할 지
- systick reload value register : 몇 초마다의 몇을 설정, 1초에 몇 번?
- 초기화 과정을 통해 SystemCoreClockUpdate()하면
- “system_msp432p4111.c” uint32_t global data 변수 값을 조정
- systick current value register
- handler 찾아서 실행
- systick calibration value register (read-only)
- 현재 시간 확인 또는 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
'CS > Embedded System' 카테고리의 다른 글
Real-Time Operating Systems - Semaphore (0) | 2021.12.07 |
---|---|
Programming Devices - LCD, S1&S2 btn, Joystick (0) | 2021.12.07 |
SW Architecture - RR, Interupt, func-queue scheduling, RTOS (0) | 2021.12.07 |
[실습] User Button Initialization & State Machine (0) | 2021.10.13 |
I/O Devices - Polling & Pull-up resistor (0) | 2021.10.13 |