승코딩당당당

[TC275] 인터럽트로 LED Blinking과 멈추기 본문

개발/임베디드

[TC275] 인터럽트로 LED Blinking과 멈추기

승코딩당당당 2026. 2. 20. 16:08

 

AURIX TC27x 보드에서 ERU(External Request Unit) 기반 인터럽트를 이용해 LED의 blinking을 제어하는 프로그램이다. 기본 동작은 while 루프에서 파란 LED(P10.2)와 빨간 LED(P10.1)를 P10_OMR 레지스터로 지속적으로 토글하여 깜빡이게 하고, 버튼(P02.0, P02.1)이 눌리면 인터럽트가 발생해 blinking을 멈추거나 다시 시작하도록 구성하였다.

 

인터럽트 서비스 루틴(ISR)에서는 LED를 직접 제어하지 않고, 전역 변수 g_blinkOn을 토글하여 현재 blinking 상태만 변경한다. 메인 루프는 이 플래그 값을 확인해 1일 때만 LED를 토글하고, 0이면 아무 동작도 하지 않는다. 이를 통해 인터럽트는 상태 제어, 메인은 실제 동작 수행이라는 역할 분리가 이루어진다.

 

ERU 설정에서는 각 스위치를 서로 다른 ERS 채널에 연결하고, Falling edge에서 이벤트가 발생하도록 설정한 뒤, 해당 이벤트를 CPU0 인터럽트로 라우팅하였다. 이 코드는 OMR 레지스터를 이용한 안전한 GPIO 토글과 인터럽트 기반 이벤트 처리 구조를 함께 학습할 수 있는 예제이다.

 


 

코드

/**********************************************************************************************************************
 * \file Cpu0_Main.c
 * \copyright Copyright (C) Infineon Technologies AG 2019
 * 
 * Use of this file is subject to the terms of use agreed between (i) you or the company in which ordinary course of 
 * business you are acting and (ii) Infineon Technologies AG or its licensees. If and as long as no such terms of use
 * are agreed, use of this file is subject to following:
 * 
 * Boost Software License - Version 1.0 - August 17th, 2003
 * 
 * Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and 
 * accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute,
 * and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the
 * Software is furnished to do so, all subject to the following:
 * 
 * The copyright notices in the Software and this entire statement, including the above license grant, this restriction
 * and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all 
 * derivative works of the Software, unless such copies or derivative works are solely in the form of 
 * machine-executable object code generated by a source language processor.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE 
 * COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN 
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
 * IN THE SOFTWARE.
 *********************************************************************************************************************/
#include "Ifx_Types.h"
#include "IfxCpu.h"
#include "IfxScuWdt.h"

#define PCn_2_IDX 19
#define P2_IDX 2
#define PCn_1_IDX 11  // P02.1
#define P1_IDX 1
#define PCn_0_IDX 3   // P02.0
#define P0_IDX 0

#define EXIS0_IDX 4
#define FEN0_IDX 8
#define REN0_IDX 9
#define EIEN0_IDX 11
#define INP0_IDX 12
#define IGP0_IDX 14

#define EXIS1_IDX 20
#define FEN1_IDX  24
#define EIEN1_IDX 27
#define INP1_IDX  28
#define IGP1_IDX  30

#define SRE_IDX 10
#define TOS_IDX 11

volatile uint8 g_blinkOn = 1;  // LED blink on/off state flag

void initERU(void);

IFX_INTERRUPT(ISR0, 0, 0x10);
void ISR0 (void)
{
    // P10_OUT.U = 0x1 << P2_IDX;

    // P10_OMR.U = (1 << (P2_IDX + 16)) | (1 << P2_IDX);

    g_blinkOn ^= 1;
}

IFX_INTERRUPT(ISR1, 0, 0x20);
void ISR1 (void)
{
    // P10_OMR.U = (1 << (P1_IDX + 16)) | (1 << P1_IDX);

    g_blinkOn ^= 1;
}

IfxCpu_syncEvent cpuSyncEvent = 0;

void initLED(void);
void initGPIO(void);

void core0_main(void)
{
    IfxCpu_enableInterrupts();

    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!
     * Enable the watchdogs and service them periodically if it is required
     */
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());

    /* Wait for CPU sync event */
    IfxCpu_emitEvent(&cpuSyncEvent);
    IfxCpu_waitEvent(&cpuSyncEvent, 1);

    initGPIO();
    initERU();

    while(1)
    {
        if (g_blinkOn)
        {
            // 파란 LED(P10.2), 빨간 LED(P10.1) 동시에 토글
            P10_OMR.U =
                (1 << (P2_IDX + 16)) | (1 << P2_IDX) |   // P10.2 토글
                (1 << (P1_IDX + 16)) | (1 << P1_IDX);    // P10.1 토글

            for (int i = 0; i < 10000000; i++)  // delay
            {
                __nop();
            }
        }
    }
}

void initLED(void){
    P10_IOCR0.U &= ~(0x1F << PCn_2_IDX);
    P10_IOCR0.U |= 0x10 << PCn_2_IDX;
}

void initGPIO(void) {
    // PC2.0 button
    P02_IOCR0.U &= ~(0x1F << PCn_0_IDX);
    P02_IOCR0.U |=  (0x02 << PCn_0_IDX);

    // PC2.1 button
    P02_IOCR0.U &= ~(0x1F << PCn_1_IDX);
    P02_IOCR0.U |= 0x02 << PCn_1_IDX;

    // PC10.2 blue led
    P10_IOCR0.U &= ~(0x1F << PCn_2_IDX);
    P10_IOCR0.U |= 0x10 << PCn_2_IDX;

    // PC10.1 red led
    P10_IOCR0.U &= ~(0x1F << PCn_1_IDX);
    P10_IOCR0.U |= 0x10 << PCn_1_IDX;
}

void initERU() {
    //**********ERS2 -> ERU0 -> ISR0 (Blue LED)**********
    SCU_EICR1.U &= ~(0x7 << EXIS0_IDX);
    SCU_EICR1.U |= 0x1 << EXIS0_IDX;

    // SCU_EICR1.U &= ~(1 << FEN0_IDX);   // Falling edge 끄고
    // SCU_EICR1.U |=  (1 << REN0_IDX);   // Rising edge 켜기
    SCU_EICR1.U |= 1 << FEN0_IDX;
    SCU_EICR1.U |= 1 << EIEN0_IDX;

    SCU_EICR1.U &= ~(0x7 << INP0_IDX);

    SCU_IGCR0.U &= ~(0x4 << INP0_IDX);
    SCU_IGCR0.U |= 0x1 << IGP0_IDX;

    // SRC (Service Request Control) Setting
    SRC_SCU_SCU_ERU0.U &= ~0xFF;
    SRC_SCU_SCU_ERU0.U |= 0x10;

    SRC_SCU_SCU_ERU0.U |= 1 << SRE_IDX;
    SRC_SCU_SCU_ERU0.U &= ~(0x3 << TOS_IDX);

    //**********ERS3 -> ERU1 -> ISR1 (Red LED)**********
    SCU_EICR1.U &= ~(0x7 << EXIS1_IDX);
    SCU_EICR1.U |=  (0x2 << EXIS1_IDX);

    SCU_EICR1.U |= 1 << FEN1_IDX;
    SCU_EICR1.U |= 1 << EIEN1_IDX;

    SCU_EICR1.U &= ~(0x7 << INP1_IDX);  // INP1 = 0 → OGU1
    SCU_EICR1.U |= 0x1 << INP1_IDX;

    SCU_IGCR0.U &= ~(0x3 << IGP1_IDX);
    SCU_IGCR0.U |=  0x1 << IGP1_IDX;

    SRC_SCU_SCU_ERU1.U &= ~0xFF;
    SRC_SCU_SCU_ERU1.U |=  0x20;        // PRI = 0x20

    SRC_SCU_SCU_ERU1.U |=  1 << SRE_IDX;
    SRC_SCU_SCU_ERU1.U &= ~(0x3 << TOS_IDX);
}

 


 

핵심 부분

1. 전역 플래그 g_blinkOn 추가

volatile uint8 g_blinkOn = 1;  // LED blink on/off state flag

 

  • 전역 변수 g_blinkOn을 추가해서 LED를 깜빡일지 말지를 결정하는 상태 플래그로 사용
  • volatile을 붙인 이유는, 이 변수가 인터럽트(ISR)와 메인 루프에서 동시에 접근되기 때문
    • 컴파일러가 최적화 과정에서 레지스터에만 값 캐싱해두고 메모리에서 다시 안 읽어오는 걸 막기 위함
    • volatile이 없으면 ISR에서 값을 바꿔도 메인 루프가 그 변화를 못 보고 계속 이전 값만 읽는 상황이 생길 수 있음.

 

2. ISR 동작 방식 변경

IFX_INTERRUPT(ISR0, 0, 0x10);
void ISR0 (void)
{
    // 예전: P10_OMR로 Blue LED 토글
    // P10_OMR.U = (1 << (P2_IDX + 16)) | (1 << P2_IDX);

    g_blinkOn ^= 1;
}

IFX_INTERRUPT(ISR1, 0, 0x20);
void ISR1 (void)
{
    // 예전: P10_OMR로 Red LED 토글
    // P10_OMR.U = (1 << (P1_IDX + 16)) | (1 << P1_IDX);

    g_blinkOn ^= 1;
}
  • 두 ISR 모두 공통적으로 g_blinkOn ^= 1;만 수행.
    • ^= 1은 0 ↔ 1 토글 연산.
  • 즉, 어느 버튼을 눌러도 “깜빡임 상태(on/off)를 전환”하는 트리거 역할만 수행하고,
    실제 LED 제어는 메인 루프에서 처리하게끔 책임을 분리했음

 

3. 메인 루프에서 LED 토글 & 딜레이 담당

while(1)
{
    if (g_blinkOn)
    {
        // 파란 LED(P10.2), 빨간 LED(P10.1) 동시에 토글
        P10_OMR.U =
            (1 << (P2_IDX + 16)) | (1 << P2_IDX) |   // P10.2 토글
            (1 << (P1_IDX + 16)) | (1 << P1_IDX);    // P10.1 토글

        for (int i = 0; i < 10000000; i++)  // delay
        {
            __nop();
        }
    }
}
  • 메인 루프에서 g_blinkOn이 1일 때만
    • Blue / Red LED를 동시에 토글하고
    • NOP 루프를 이용해서 소프트웨어 딜레이를 줌 → 사람 눈에 깜빡이는 효과
  • g_blinkOn == 0이면
    • LED는 마지막 상태를 유지하고, 더 이상 토글/딜레이를 수행하지 않음 → 깜빡임 정지

 


 

결과

언제 스위치를 누르냐에 따라 LED가 켜진 상태에서 멈출 수도 있고, 꺼진 상태에서 멈출 수도 있다.

인터럽트로 LED Blinking과 멈추기_결과.gif
10.93MB