1. 하드웨어 설계
개발 보드에는 CH340E 칩이 통합되어 있습니다. CH340E는 USB를 직렬 포트(RS232/RS485/TTL)로 변환하는 저비용 솔루션으로, 마이크로컨트롤러 개발과 임베디드 시스템에서 널리 사용됩니다. TYPE-C 인터페이스를 통해 데이터 케이블을 연결하면 개발 보드와 직렬 통신이 가능합니다. CH340E는 PA22와 PA23 핀에 연결되어 있습니다.
PA22와 PA23은 L1306의 UART0 핀이지만, PA23은 기준 전압 및 BSL 직렬 핀으로도 사용됩니다. 기본적으로 직렬 통신 핀으로 설정되어 있으며, 기준 전압으로 사용하려면 R24(0Ω) 저항을 제거해야 합니다.
2. 소프트웨어 설계
2.1 프로그래밍 개요
- UART_0 관련 파라미터 매크로 정의
- UART_0 기본 설정
- 직렬 포트 인터럽트 서비스 함수
- printf 함수 재정의
- 메인 함수 테스트
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);
}
}