Embedded/TC275 Lite Kit

Port 설정과 GPIO 제어 (Infineon AURIX TC275)

배드배드임베디드 2021. 12. 20. 02:40

안녕하세요 여러분. 히치하이커입니다.

 

오늘은 TC275 Microcontroller의 Port 설정과 GPIO Control을 하여 TC275 Lite Kit의 LED를 제어해 보도록 할게요.

 

참, 우리는 아직 User Manual이 없는 상태니 다운로드를 해보죠.

User Manual은 아래 Infineon 공식 홈페이지에서 다운로드할 수 있어요.

자료가 필요할 때마다 링크를 찾아볼 예정이니 즐겨찾기를 하면 편할 것 같아요.

 

https://www.infineon.com/cms/en/product/microcontroller/32-bit-tricore-microcontroller/32-bit-tricore-aurix-tc2xx/aurix-family-tc27xt/

 

AURIX™ Family – TC27xT - Infineon Technologies

 

www.infineon.com

 

Downloads

 

두 개의 파일이 있는데 날짜가 최신인 파일을 저장하고 열어보면 무려 5063페이지의 문서가 우리를 반겨요.

 

MCU에 대한 이해와 Peripheral에 대한 폭넓은 지식도 중요하지만, 임베디드 소프트웨어 개발자에게 필요한 능력 중 하나는 방대한 양의 Datasheet과 User Manual에서 원하는 정보를 빠르게 얻는 것이라고 생각해요. 그러기 위해서는 많은 Datasheet과 User Manual을 접해보는 것이 중요한 것 같아요. 각 칩 벤더들이 제공하는 문서의 스타일도 다 다르기 때문이에요.

 

Peripheral은 GPIO, GTM, CCU6, ADC, CAN, SPI 등 수많은 기능으로 나누어져 있는데 이러한 기능을 사용하기 위해서는 반드시 Port 설정을 올바르게 해 주어야 해요.

 

그럼 User Manual 13장으로 가볼까요?

 

Port Pin General Structure

 

Port Pin은 그림과 같이 Port Slice와 Pad로 구성되어 있어요. 왼쪽에 Register 정보에 따라 Port의 사용 용도와 출력이 결정되는 구조에요.

그럼 중요한 Register 몇 개만 짚고 넘어갈까요?

 

OMR (Output Modification Register)

  • Output Modification Register는 Port Pin의 State High/Low로 변경할 수 있는 register에요. 아래 테이블에 따라 High / Low / Toggle을 할 수 있어요. 

Output Modification Register Setting

 

PDR (Pad Driver Mode Register)

  • Pad의 Drive Strength를 설정할 수 있는 Register에요. Peripheral 설정 시 가끔 사용할 Register에요.

 

IN (Input Register)

  • Port Pin의 Intput 상태를 알 수 있는 Register에요.

 

IOCR Register (Input/Output Control Register) 

  • Port pin의 Input/Output 설정 및 해당 Pin을 어떠한 용도로 사용할 지 설정하는 Register에요.
    Input으로 사용할 때는 I/O Control Select[PCxx Bit]를 0XXXXB로 설정하면 되고, Output으로 사용할 때는 아래 Table을 참고하여 사용하고자 하는 기능에 대한 설정을 하면 돼요. Output 설정 시 4번째 Bit는 Don't Care로 나오지만 Push-Pull 또는 Open-Drain을 설정할 수 있는 Bit에요.
    Port Pin별로 지원하는 Alternative 기능은 다르니 꼭 User Manual에서 확인을 하고 설정을 해주어야 해요!

Port Functions

 

자, 그럼 이제 GPIO를 Control 하여 TC275 Lite Kit에 내장된 LED1과 LED2를 Toggling 해봐요.

LED1은 P00.5 (Port00, Pin5), LED2는 P00.6 (Port00, Pin6)이네요!

TC275 Lite Kit Board View

 

HighTec Development Platform을 실행시키고 우리가 이전에 만든 Project로 가볼게요.

예제 Project에서 제공한 LED 제어 코드는 TC275 Lite Kit과 다른 Pin을 사용하기 때문에 아래와 같이 코드를 변경해야 해요.

 

<port_types.h>

/* PORT OUTPUT control for TC275 LITE KIT */
typedef enum
{
    BOARD_LED_P00_5 = 0,
    BOARD_LED_P00_6,
    BOARD_NUM_LEDS
} BOARD_TC275_LITE_KIT_LED;

/* PORT OUTPUT control for TC275 LITE KIT */
typedef enum
{
    BOARD_LED_NO_CHANGE      = 0,
    BOARD_LED_OFF            = 1,
    BOARD_LED_ON             = 2,
    BOARD_LED_TOGGLE         = 3,
} BOARD_TC275_LITE_KIT_LED_SET;

 

<bsp_boards.c>

void bsp_board_tc275_led_InitAll(BOARD_TC275_LITE_KIT_LED_SET set)
{
    int i;
    for (i=0; i < BOARD_NUM_LEDS; i++)
        bsp_board_tc275_led_Init((BOARD_TC275_LITE_KIT_LED) i, set);
}

void bsp_board_tc275_led_Init(BOARD_TC275_LITE_KIT_LED led, BOARD_TC275_LITE_KIT_LED_SET set)
{
    bsp_uc_port_SetGPIO(board_tc275_led[led].port, board_tc275_led[led].index, (UC_PORT_OUTPUT_e) set);
    bsp_uc_port_EnableOutput(
        board_tc275_led[led].port, board_tc275_led[led].index, 0, UC_PORT_PL_LEVEL_AL, UC_PORT_PD_SPEED_3);
}

void bsp_board_tc275_led_Set(BOARD_TC275_LITE_KIT_LED led, BOARD_TC275_LITE_KIT_LED_SET set)
{
    bsp_uc_port_SetGPIO(board_tc275_led[led].port, board_tc275_led[led].index, (UC_PORT_OUTPUT_e) set);
}

 

shared_main.c의 TimerMulticoreIsrHandler() 함수명을 보아 말 그대로 Multi-Core ISR Handler인 것으로 보이네요! bsp_uc_core_GetCurrentCore() 함수를 통해 현재 Core를 받아오는 것으로 보니 각 Core 별로 수행하는 동작을 구분해야 할 것 같아요.

아래와 같이 Core로 구분을 하고, Core0로 인한 ISR Handler가 호출될 때만 LED를 Toggling 하도록 구현을 해 보았어요. 추가로, Toggling을 통한 Input Register 정보도 같이 확인할 수 있도록 지역 변수를 Static으로 설정했어요.

 

<shared_main.c>

void TimerMulticoreIsrHandler(void)
{
    /* Use BSP API to get current CoreId */
    static uint32_t coreId = (uint32_t)0;
    static uint8_t pinState = (uint8_t)0;

    coreId = bsp_uc_core_GetCurrentCore();
    /* Get Core dependent Time period */
    uint32_t corePeriod = (coreId + 1) * TIMER_BASE_PERIOD;

    /* Interrupt Action based on current CoreId */
    if(coreId == CORE_0)
    {
        bsp_board_tc275_led_Set((BOARD_TC275_LITE_KIT_LED) BOARD_LED_P00_5, BOARD_LED_TOGGLE);
        bsp_board_tc275_led_Set((BOARD_TC275_LITE_KIT_LED) BOARD_LED_P00_6, BOARD_LED_TOGGLE);
        /* pinState = bsp_uc_port_GetGPIO(0, 6); */
    }
    else if(coreId == CORE_1)
    {
        /* TBD */
    }
    else
    {
        /* TBD */
    }
    bsp_uc_stm_ReloadChannel(coreId, corePeriod);
    bsp_uc_stm_ClearChannelIsrFlag(coreId);
}

 

이렇게 구현을 하고 Build 후 Debugging 환경으로 넘어가 프로그램 Flash를 하면 LED1, LED2가 Toggling 하는 것을 확인할 수 있어요! 끝!

 

 

 

 

이 아니라 이제 마지막으로 Input Register 정보를 읽어와 현재 Pin 상태를 알아볼게요.

User Manual에 따르면 Input Register의 Base 주소는 0xF003A024에요.

 

Port Input Register

 

bsp_uc_regdefs.h 헤더에 있는 #define UC_PORT_IN_REG(port, index) 을 사용하여 Input Register의 정보를 얻어올 수 있어요. Input Register 정보를 읽어오는 코드를 아래와 같이 구현을 해서 다시 실행시키면,

 

bsp_uc_regdefs.h

 

<bsp_uc.c>

uint8_t bsp_uc_port_GetGPIO(uint32_t port, uint32_t pinIndex)
{
    uint32_t input = 0;
    input = ((UC_PORT_IN_REG(port,pinIndex)));
    return (uint8_t)(input & (1<<pinIndex)) >> pinIndex;
}

 

아직까진 이상한 점이 없어 보이죠?

하지만 TimerMulticoreIsrHandler() 함수의 주석 처리된 부분을 풀고 실제로 해당 코드가 돌게 되면 Input Register의 이상한 값이 출력될 거예요.

디버깅을 통해 나중에 알아낸 점은, Input Register의 Base 주소 0xF003A024번지가 아닌 0xF003A018번지 값을 Return 한다는 거예요.

 

기존의 헤더 파일은 Input Register의 Offset 값이 +24로 되어 있는데, 실제로 Input Register의 주소는 0x24의 Offset을 가지고 있어요. 다른 주소번지의 값을 Return하기 때문에 헤더 파일을 아래와 같이 바꿔 주었어요. 분명히 제공하는 헤더 파일인데 뭔가 억울하네요... 나중에 Register 주소가 잘 설정되어 있는지 하나하나 확인을 해야 할 것 같아요!

 

<bsp_uc_regdef.h>

/* ======== IN register ======== */
#ifndef UC_PORT_IN_REG_UC_SPECIFIC
#define UC_PORT_IN_REG_BASE(port,index)     (vuint32_t *) (UC_PORT_BASE                 \
                                                + (0x1000 * (uint32_t)(port / 10))      \
                                                + (0x0100 * (port % 10))                \
                                                + 0x24)
#define UC_PORT_IN_REG(port,index)  		( * UC_PORT_IN_REG_BASE(port,index) )
#endif /* UC_PORT_IN_REG_UC_SPECIFIC */

 

이제 정상 동작하네요! Input Register의 값을 확인하고 싶은 경우, ISR Handler에 Breakpoint를 걸면 LED의 동작에 맞춰서 Toggling 하는 것을 확인할 수 있어요.

 

Port 관련해서는 필요한 정보가 있을 때마다 업데이트를 할게요.

오늘도 긴 글 읽어주셔서 감사합니다.

다음에 봐요!

 

진짜 끝!