STM32 인터럽트 시스템 이해하기

인터럽트 시스템

인터럽트란 메인 프로그램 실행 도중에 특정 조건(인터럽트 소스)이 발생했을 때 CPU가 현재 실행 중인 프로그램을 일시적으로 중단하고 해당 인터럽트 처리 프로그램을 실행하는 메커니즘이다. 처리完成后 이전에中断된 위치로 돌아와 계속 프로그램을 실행한다.

인터럽트 우선순위

여러 개의 인터RUPT 소스가 동시에 요청될 경우, CPU는 각 인터럽트의 긴급 정도를 평가하여 더 중요한 인터럽트를 먼저 처리한다.

인터럽트 중첩

하나의 인터럽트 처리 중 더 높은 우선순위를 가진 새로운 인터럽트가 발생하면, CPU는 현재 인터럽트 처리를 중단하고 새로운 인터럽트를 처리한 후 이전 인터럽트로 복귀한다.

NVIC 기본 구조

NVIC(Nested Vectored Interrupt Controller)은 STM32의 인터럽트 관리 시스템이다. CPU를 의사로 비유하면, NVIC은 진료 대기 시스템이고, EXTI, TIM, ADC, USART 등은 환자이다. 각 환자의 긴급 상황에 따라 우선순위가 결정된다.

NVIC 우선순위 그룹

서브 우선순위(Sub Priority): 대기 중인 환자 중 긴급한 환자가 먼저 진료를 받는 순서이다.

선점 우선순위(Preemption Priority): 더 긴급한 환자가 현재 진료 중인 환자를 중단시키고 먼저 진료받을 수 있다. 진료完成后 Previously中断된 환자를 다시 진료한다.

EXTI 개요

EXTI(External Interrupt)는 외부 신호를 감지하여 인터럽트를 생성하는 모듈이다.

  • 특정 GPIO 핀의的电平变化를 모니터링
  • 신호 변화 발생 시 NVIC에 인터럽트 요청 전송
  • 트리거 방식: 상승 엣지/하강 엣지/양쪽 엣지/소프트웨어 트리거
  • GPIO 지원: 모든 GPIO 핀 (동일 핀 번호 중복 사용 불가)
  • 채널: 16개 GPIO_Pin + PVD 출력, RTC 알람, USB 후크, 이더넷 후크
  • 응답 방식: 인터럽트 응답/이벤트 응답

EXTI 기본 구조

EXTI는 외부 신호를 입력받아 NVIC으로 인터럽트 신호를 전달하는 구조를 가진다.

AFIO 복용 IO 포트

AFIO(Alternate Function Input/Output)는 포트의 대체 기능 선택과 재설정을 담당한다.

  • 복용 기능 핀 재매핑
  • 인터럽트 핀 선택

회전 인코더介绍

회전 인코더는 위치, 속도 또는 회전 방향을 측정하는 장치이다. 축이 회전할 때 회전 속도와 방향에 해당하는矩形파 신호를 출력한다. 신호의 주파수와 위상을 분석하여 회전축의 속도와 방향을 파악할 수 있다.

유형: 기계 접점식/홀 센서식/광학식

설계 권장사항

인터럽트 핸들러 내부에서는 복잡한 함수를 호출하지 않는 것이 좋다. 대신 플래그 변수를 설정하고, 메인 함수나 다른 함수에서 해당 플래그를 확인하여 처리하는 방식으로 구현하는 것이 바람직하다.

코드 구현

설정 흐름

  1. 클록 활성화
  2. AFIO 클록 활성화
  3. GPIO 설정
  4. EXTI 라인에 사용할 GPIO 핀 선택
  5. EXTI 설정
  6. NVIC 우선순위 그룹 구성
  7. NVIC 설정
  8. 인터럽트 핸들러에 사용자 코드 작성

인터럽트 구성 코드

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

GPIO_InitTypeDef portConfig;
portConfig.GPIO_Mode = GPIO_Mode_IPU;
portConfig.GPIO_Pin = GPIO_Pin_14;
portConfig.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &portConfig);

GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);

EXTI_InitTypeDef extiConfig;
extiConfig.EXTI_Line = EXTI_Line14;
extiConfig.EXTI_LineCmd = ENABLE;
extiConfig.EXTI_Mode = EXTI_Mode_Interrupt;
extiConfig.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&extiConfig);

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

NVIC_InitTypeDef nvicConfig;
nvicConfig.NVIC_IRQChannel = EXTI15_10_IRQn;
nvicConfig.NVIC_IRQChannelCmd = ENABLE;
nvicConfig.NVIC_IRQChannelPreemptionPriority = 1;
nvicConfig.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&nvicConfig);

인터럽트 핸들러 구현

void EXTI15_10_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line14) == SET)
    {
        if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0)
        {
            encoderCounter++;
        }
        EXTI_ClearITPendingBit(EXTI_Line14);
    }
}

6월 24일 00:14에 게시됨