UART 직렬 통신 구현 및 활용 가이드

1. 하드웨어 설계

개발 보드에는 CH340E 칩이 통합되어 있습니다. CH340E는 USB를 직렬 포트(RS232/RS485/TTL)로 변환하는 저비용 솔루션으로, 마이크로컨트롤러 개발과 임베디드 시스템에서 널리 사용됩니다. TYPE-C 인터페이스를 통해 데이터 케이블을 연결하면 개발 보드와 직렬 통신이 가능합니다. CH340E는 PA22와 PA23 핀에 연결되어 있습니다.

PA22와 PA23은 L1306의 UART0 핀이지만, PA23은 기준 전압 및 BSL 직렬 핀으로도 사용됩니다. 기본적으로 직렬 통신 핀으로 설정되어 있으며, 기준 전압으로 사용하려면 R24(0Ω) 저항을 제거해야 합니다.

2. 소프트웨어 설계

2.1 프로그래밍 개요

  1. UART_0 관련 파라미터 매크로 정의
  2. UART_0 기본 설정
  3. 직렬 포트 인터럽트 서비스 함수
  4. printf 함수 재정의
  5. 메인 함수 테스트

2.2 코드 분석

2.2.1 직렬 포트 관련 파라미터 매크로 정의
/* UART_0 설정을 위한 매크로 정의 */
#define SERIAL_MODULE                                                     UART0
#define SERIAL_IRQHandler                                       UART0_IRQHandler
#define SERIAL_INT_IRQN                                           UART0_INT_IRQn
#define SERIAL_RX_GPIO_PORT                                               GPIOA
#define SERIAL_TX_GPIO_PORT                                               GPIOA
#define SERIAL_RX_PIN                                           DL_GPIO_PIN_22
#define SERIAL_TX_PIN                                           DL_GPIO_PIN_23
#define SERIAL_RX_IOMUX                                        (IOMUX_PINCM23)
#define SERIAL_TX_IOMUX                                        (IOMUX_PINCM24)
#define SERIAL_RX_IOMUX_FUNC                            IOMUX_PINCM23_PF_UART0_RX
#define SERIAL_TX_IOMUX_FUNC                            IOMUX_PINCM24_PF_UART0_TX
#define SERIAL_BAUDRATE                                                  (9600)
#define SERIAL_IBRD_4MHZ_9600                                          (26)
#define SERIAL_FBRD_4MHZ_9600                                          (3)
2.2.2 직렬 포트 설정
// 클럭 설정 구조체
static const DL_UART_Main_ClockConfig gSerialClockConfig = {
    .clockSel    = DL_UART_MAIN_CLOCK_MFCLK,
    .divideRatio = DL_UART_MAIN_CLOCK_DIVIDE_RATIO_1
};

// 통신 파라미터 설정 구조체
static const DL_UART_Main_Config gSerialConfig = {
    .mode        = DL_UART_MAIN_MODE_NORMAL,
    .direction   = DL_UART_MAIN_DIRECTION_TX_RX,
    .flowControl = DL_UART_MAIN_FLOW_CONTROL_NONE,
    .parity      = DL_UART_MAIN_PARITY_NONE,
    .wordLength  = DL_UART_MAIN_WORD_LENGTH_8_BITS,
    .stopBits    = DL_UART_MAIN_STOP_BITS_ONE
};

void SYSCFG_DL_SERIAL_init(void)
{
    // GPIO 핀 기능 설정
    DL_GPIO_initPeripheralOutputFunction(SERIAL_TX_IOMUX, SERIAL_TX_IOMUX_FUNC);
    DL_GPIO_initPeripheralInputFunction(SERIAL_RX_IOMUX, SERIAL_RX_IOMUX_FUNC);
    
    // UART 클럭 설정
    DL_UART_Main_setClockConfig(SERIAL_MODULE, (DL_UART_Main_ClockConfig *) &gSerialClockConfig);
    
    // UART 기본 설정
    DL_UART_Main_init(SERIAL_MODULE, (DL_UART_Main_Config *) &gSerialConfig);
    
    /*
     * 보레이트 설정: 목표 9600 bps
     * 실제 보레이트: 9598.08 bps
     */
    DL_UART_Main_setOversampling(SERIAL_MODULE, DL_UART_OVERSAMPLING_RATE_16X);
    DL_UART_Main_setBaudRateDivisor(SERIAL_MODULE, SERIAL_IBRD_4MHZ_9600, SERIAL_FBRD_4MHZ_9600);

    /* 인터럽트 활성화 */
    DL_UART_Main_enableInterrupt(SERIAL_MODULE, DL_UART_MAIN_INTERRUPT_RX);
    DL_UART_Main_enable(SERIAL_MODULE);
}
2.2.3 직렬 포트 기능 함수
// 단일 바이트 전송 함수
void serial_send_byte(uint8_t data)
{
    while(DL_UART_isBusy(SERIAL_MODULE) == true);
    DL_UART_Main_transmitData(SERIAL_MODULE, data);
}

// 문자열 전송 함수
void serial_send_text(const char* text)
{
    while(*text != '\0')
    {
        serial_send_byte(*text++);
    }
}

// 표준 출력 호환성 설정
#if !defined(__MICROLIB)
#if (__ARMCLIB_VERSION <= 6000000)
struct __FILE
{
    int handle;
};
#endif
FILE __stdout;
void _sys_exit(int x)
{
    x = x;
}
#endif

// printf 출력 리다이렉션
int fputc(int ch, FILE *stream)
{
    while(DL_UART_isBusy(SERIAL_MODULE) == true);
    DL_UART_Main_transmitData(SERIAL_MODULE, ch);
    return ch;
}
2.2.4 직렬 포트 인터럽트 서비스 함수
// 직렬 통신 인터럽트 처리 함수
volatile uint8_t received_data = 0;

void SERIAL_IRQHandler(void)
{
    switch(DL_UART_getPendingInterrupt(SERIAL_MODULE))
    {
        case DL_UART_IIDX_RX:
            received_data = DL_UART_Main_receiveData(SERIAL_MODULE);
            // 수신된 데이터를 에코백
            serial_send_byte(received_data);
            break;
        
        default:
            break;
    }
}
2.2.5 메인 함수 테스트
#include "ti_msp_dl_config.h"
#include <stdio.h>
#include "led_driver.h"
#include "delay_timer.h"
#include "serial_comm.h"

int main(void)
{
    // 시스템 초기화
    SYSCFG_DL_init();
    
    // 주변 장치 초기화
    led_initialize();
    timer_init();
    SYSCFG_DL_SERIAL_init();
    
    // 인터럽트 활성화
    NVIC_ClearPendingIRQ(SERIAL_INT_IRQN);
    NVIC_EnableIRQ(SERIAL_INT_IRQN);
    
    // 메인 루프
    while(1) 
    {            
        led_turn_on();
        printf("LED 켜짐\r\n");
        delay_milliseconds(1000);
        
        led_turn_off();
        printf("LED 꺼짐\r\n");
        delay_milliseconds(1000);
    }
}

태그: UART 직렬통신 임베디드시스템 CH340E 통신프로그래밍

10월 11일 20:56에 게시됨