프로그래밍/STM32

[STM32] EXTI(External Interrupt) 제어

Beginner:) 2023. 9. 24.
320x100

먼저 나의 환경은 Ubuntu 20.04, NUCLEO-F411RE 사용 중

Tool은 CMake를 통해 빌드하여 VSCode로 Debug 한다.

2023.09.10 - [프로그래밍/STM32] - [STM32] STM32CubeMX로 CMake설정하기

2023.09.03 - [프로그래밍/STM32] - [STM32] cmake build(feat .bin, .elf, .hex 추출)

2023.09.03 - [프로그래밍/STM32] - [STM32] VSCode 에서 STM32 디버깅하기(.vscode)

 

1. EXTI 설명

외부 인트럽트(EXTI)를 사용해 보자.

먼저 관련 문서

stm32f411xE_Reference_manual.pdf
9.72MB

 

먼저 아래의 문서를 보면 EXTI에 대한 event mapping이 되어있는데,

요약하자면 EXTI0은 PA0~PH0 핀 중 하나를 선택하여 사용할 수 있다.

마찬가지로 EXTI1은 PA1~PH1 핀 중 하나를 선택하여 사용할 수 있다.

 

주의할 점은 동시에 불가능하다. 애초에 MX에서 PA0을 EXTI핀으로 설정하고 PB0을 EXTI핀으로 설정하면 PA0핀의 설정이 지워진다.

 

여기서 특이한 것은 EXTI5~9와 EXTI10~15는 같은 각각 하나의 Address가 지정되어 있다.

EXTI0~4까지는 하나의 핀에 하나의 함수가 연결되는데, EXTI5~9의 5개 핀이 하나의 함수에, EXTI10~15의 6개 핀에 하나의 함수가 연결되어 있다.

즉 EXTI5번부터는 함수에서 어떤 인터럽트가 호출되었는지 구분해줘야 한다.

 

 

2. EXTI 설정

cubeMX에 들어가 PA0을 GPIO_EXTI0으로 설정한다.

 

또한 EXTI10~15를 확인하기 위해 PC10~PC15를 EXTI로 연결해 준다.

 

NVIC(Nested Vectored Interrupt Controller)에서 EXTI line0 interrupt가 생겼을 것이다. enable을 체크해 주고

EXTI line[15:10] interrupts 또한 enable을 체크해 준다.

 

 

이후 Generate Code를 클릭한다.

 

3. EXTI 코딩

"STM32/Core/Src/stm32f4xx_it.c" 경로로 이동하면 아래의 소스코드가 있을 것이다.

EXTI0_IRQHandler 함수는 하나의 핀과 연결된 반면, EXTI15_10_IRQHandler 함수는 6개의 핀과 연결되어 있는 것을 볼 수 있다.

 

void EXTI0_IRQHandler(void)
{
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}

void EXTI15_10_IRQHandler(void)
{
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10);
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_15);
}

 

 

하지만 결국 마지막은 HAL_GPIO_EXTI_IRQHandler의 하나의 함수이다.

EXTI[number]_IRQHandler를 사용하면 따로 관리를 해도 되지만 지금은 테스트만 하는 것으로 굳이 하진 않겠다.

 

HAL_GPIO_EXTI_IRQHandler 함수를 살펴보면 해당 핀이 SET하게 되면 clear 후 콜백함수를 호출한다.

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
    HAL_GPIO_EXTI_Callback(GPIO_Pin);
  }
}

 

아래는 콜백함수이다. __weak란 같은 이름인 함수가 발견되었을 때, __weak가 붙은 함수의 우선순위를 뒤로 해달라는 뜻으로 간단하게 사용자 재정의가 가능한 함수라고 생각하면 된다.

아래와 같이 재정의를 하고 RUN을 한다.

__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  UNUSED(GPIO_Pin);
}
uint8_t getGPIOPinAddressToNum(uint16_t pin){
    uint8_t num = -1;
    switch(pin)
    {
        case GPIO_PIN_0:
            num = 0;
            break;
        case GPIO_PIN_1:
            num = 1;
            break;
        case GPIO_PIN_2:
            num = 2;
            break;
        case GPIO_PIN_3:
            num = 3;
            break;
        case GPIO_PIN_4:
            num = 4;
            break;
        case GPIO_PIN_5:
            num = 5;
            break;
        case GPIO_PIN_6:
            num = 6;
            break;
        case GPIO_PIN_7:
            num = 7;
            break;
        case GPIO_PIN_8:
            num = 8;
            break;
        case GPIO_PIN_9:
            num = 9;
            break;
        case GPIO_PIN_10:
            num = 10;
            break;
        case GPIO_PIN_11:
            num = 11;
            break;
        case GPIO_PIN_12:
            num = 12;
            break;
        case GPIO_PIN_13:
            num = 13;
            break;
        case GPIO_PIN_14:
            num = 14;
            break;
        case GPIO_PIN_15:
            num = 15;
            break;
    }

    return num;
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  LOG("intterupt %d pin!", getGPIOPinAddressToNum(GPIO_Pin));
}

 

그럼 아래와 같이 pin이 출력이 된다.

다만, PC11을 누르지 않아도 출력이 되고 PA0도 스위치를 누르지 않았는데 0이 출력되는 것을 보면 플로팅 때문인 듯하다. 

플로팅이더라도 이렇게 자주일어나진 않을 텐데;;; 어쨌건 귀찮으니 풀다운 설정은 하지 않는다.

 

2022.03.22 - [0. 이론] - 플로팅(Floating)현상이란?

 

플로팅(Floating)현상이란?

플로팅 현상이란 "떠 있다"라는 뜻으로 아무것도 연결되어있지 않아 전압을 모르는 상태이다. 사실 나는 아무것도 연결이 되어 있지 않은 상태라면 0V라 생각했지만 아니었다. 마치 C언어에서 변

park-duck.tistory.com

 

 

자, 그럼 PA0은 하나뿐이니 GPIO_PIN_0만 들어오는 것을 볼 수 있다.

 

왜냐하면 스위치가 눌러졌을 때  EXTI0_IRQHandler 함수가 실행되어 HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0)을 통해 GPIO_PIN_0이 전달될 테니. 

 

그렇다면 EXTI10_15는 어떨까?

귀찮아서 PC15만 스위치를 연결하고 HAL_GPIO_EXTI_IRQHandler에 로그를 출력해 보았다.

확인해 보면

1. HAL_GPIO_EXTI_IRQHandler 10, 11, 12, 13을 출력

2. interrupt 13pin!을 출력

3. HAL_GPIO_EXTI_IRQHandler 14, 15를 마저 출력

하는 것을 볼 수 있는데

 

요약하자면 

PC10~15중 하나의 인터럽트가 일어나게 되면 HAL_GPIO_EXTI_IRQHandler함수에서 PC10~15중 SET이 되어있는 핀을 찾고 callback함수를 요청하는 것이다.

 

다시 한번 말하지만 0~4번 핀들은 하나의 핀이기 때문에 EXTI[number]_IRQHandler 함수에서 즉시 함수를 구현해도 되지만 

5~9번 핀과 10~15번 핀은 함수를 통해 어떤 핀이 인터럽트를 줬는지 확인을 해야 한다.

5~15번 핀 중 찾을 필요가 없다면 얘기가 달라지지만... 

 

HW에는 잘 모르는 편이라 참고만 하시고 피드백은 환영...

 

반응형

댓글