liminfo

UART Reference

UART 시리얼 통신 레퍼런스

25개 결과

UART Reference 소개

UART 레퍼런스는 임베디드 시스템에서 가장 기본적인 직렬 통신 프로토콜인 범용 비동기 수신-송신기(Universal Asynchronous Receiver-Transmitter)를 위한 검색 가능한 치트 시트입니다. 완전한 UART 프레임 구조(시작 비트, 5-9 데이터 비트, 선택적 패리티, 1-2 정지 비트), 9600부터 921600까지의 표준 보레이트, 오류 검출을 위한 패리티 비트 계산, STM32 HAL과 Arduino 플랫폼의 초기화 코드를 다룹니다.

이 레퍼런스는 기본설정, 전송, 수신, 흐름제어, DMA, 디버깅의 6개 카테고리에 걸쳐 25개 이상의 항목을 체계적으로 정리합니다. 전송 섹션은 STM32 폴링(HAL_UART_Transmit), 인터럽트 방식(HAL_UART_Transmit_IT), printf 리다이렉트, Arduino의 Serial.print()와 Serial.write()를 다룹니다. 수신 섹션은 폴링, 인터럽트, 가변 길이 패킷을 위한 IDLE 라인 감지, 연속 데이터 수신을 위한 링 버퍼 구현을 상세히 설명합니다.

기본 송수신 외에도 RTS/CTS 신호를 이용한 하드웨어 흐름 제어, 소프트웨어 XON/XOFF 흐름 제어, MAX232 레벨 시프팅이 포함된 RS-232 전압 레벨, 장거리 다중 노드 네트워크를 위한 RS-485 반이중 차동 신호, 일반 및 순환 모드의 DMA 전송, HAL_UARTEx_ReceiveToIdle_DMA를 사용한 효율적인 가변 길이 수신을 위한 DMA+IDLE 조합, 보레이트 오차 계산, 로직 분석기 디버깅 기법, 일반적인 UART 문제와 해결 방법의 종합 목록을 다룹니다.

주요 기능

  • UART 프레임 구조: 시작 비트, 데이터 비트(5-9), 패리티(None/Even/Odd), 정지 비트(1-2)와 기본값 8N1
  • STM32 HAL API: 콜백 패턴을 포함한 송수신 모두의 폴링, 인터럽트, DMA 모드
  • Arduino Serial 인터페이스: Serial.begin() 설정, 텍스트용 Serial.print()/println(), 바이너리용 Serial.write()
  • DMA 전송 모드: 일반, 순환, 반전송 콜백, 가변 길이 패킷을 위한 DMA+IDLE
  • 흐름 제어: 버퍼 관리를 위한 RTS/CTS 하드웨어 핸드셰이킹과 XON/XOFF 소프트웨어 프로토콜
  • 물리 계층 표준: MAX232를 사용한 RS-232 전압 레벨, 다중 노드 버스를 위한 RS-485 차동 신호
  • 데이터 손실 없는 인터럽트 기반 연속 수신을 위한 링 버퍼 구현
  • 디버깅 가이드: 보레이트 오차 계산, 로직 분석기 파형 분석, 일반적인 UART 문제 체크리스트

자주 묻는 질문

UART 설정에서 8N1이란 무엇인가요?

8N1은 가장 일반적인 UART 설정으로 8 데이터 비트, 패리티 없음(None), 1 정지 비트를 의미합니다. 필수 시작 비트와 합쳐 각 바이트 전송에 10비트 주기가 필요합니다. 115200 보레이트에서는 초당 약 11,520바이트를 전송할 수 있습니다. 8E1(8 데이터 비트, Even 패리티, 1 정지 비트) 같은 다른 설정은 약간의 처리량 감소를 대가로 오류 검출을 추가합니다.

폴링, 인터럽트, DMA 수신 모드의 차이점은 무엇인가요?

폴링(HAL_UART_Receive)은 데이터 도착이나 타임아웃까지 CPU를 차단하여 간단한 애플리케이션에만 적합합니다. 인터럽트 모드(HAL_UART_Receive_IT)는 바이트 수신마다 콜백을 트리거하여 바이트 사이에 CPU를 해방하지만 바이트마다 ISR 오버헤드가 발생합니다. DMA 모드(HAL_UART_Receive_DMA)는 CPU 개입 없이 데이터를 메모리로 직접 전송하여, CPU가 다른 작업을 해야 하는 고속 또는 연속 데이터 스트림에 이상적입니다.

IDLE 라인 감지는 가변 길이 패킷에 어떻게 작동하나요?

IDLE 인터럽트는 데이터 수신 후 UART 라인이 한 프레임 주기 동안 유휴(데이터 없음) 상태일 때 발생합니다. DMA와 결합하면 최대 버퍼 크기로 DMA 수신을 시작하고, IDLE 인터럽트가 발생하면 DMA 카운터를 읽어 실제로 수신된 바이트 수를 결정합니다. HAL_UARTEx_ReceiveToIdle_DMA가 이 패턴을 래핑하여, 실제 수신 크기와 함께 HAL_UARTEx_RxEventCallback을 호출합니다.

UART에서 깨진 문자가 나타나는 이유는 무엇인가요?

가장 흔한 원인은 송신기와 수신기 간의 보레이트 불일치입니다. 다른 원인으로는 TX-RX 와이어가 교차되지 않은 경우(TX는 RX에, 그 반대도 연결해야 함), 공통 접지 연결 누락, 전압 레벨 불일치(레벨 시프터 없이 3.3V MCU를 5V 장치에 연결), 패리티 또는 정지 비트 설정 불일치가 있습니다. 로직 분석기를 사용하여 와이어의 실제 보레이트와 프레임 형식을 확인하세요.

RS-232 대신 RS-485를 언제 사용해야 하나요?

15미터 이상의 거리, 다중 노드 네트워크, 노이즈가 많은 산업 환경에서 RS-485를 사용합니다. RS-485는 차동 신호(A, B 두 개의 와이어)를 사용하여 우수한 노이즈 내성을 제공하고, 최대 1200미터 케이블을 지원하며, 단일 버스에 32~256개 노드를 허용합니다. 다만 RS-485는 반이중으로, 송수신 모드 전환을 위한 DE(Driver Enable) 핀이 필요하여 소프트웨어 복잡성이 추가됩니다.

STM32에서 printf를 UART로 어떻게 구현하나요?

syscalls.c나 retarget 파일에서 _write() 함수를 오버라이드합니다. _write 내부에서 HAL_UART_Transmit(&huart1, (uint8_t*)ptr, len, HAL_MAX_DELAY)를 호출하면 모든 printf 출력이 UART1로 리다이렉트됩니다. 이를 통해 디버깅에 표준 printf("Temp: %.1f\n", temp)를 사용할 수 있습니다. 프로덕션에서는 printf 호출 중 CPU 차단을 피하기 위해 DMA 전송을 사용하는 링 버퍼를 고려하세요.

링 버퍼란 무엇이고 UART 수신에 왜 필요한가요?

링 버퍼(순환 버퍼)는 head와 tail 포인터가 있는 고정 크기 배열로 순환합니다. UART 수신에서 인터럽트 콜백이 head 포인터 위치에 바이트를 쓰고, 메인 루프가 tail 포인터에서 읽습니다. 이렇게 하면 ISR 타이밍과 처리 타이밍이 분리되어 메인 루프가 일시적으로 바쁠 때 데이터 손실을 방지합니다. 버퍼 크기는 가장 긴 처리 지연 동안의 데이터를 보유할 수 있을 만큼 충분히 커야 합니다.

보레이트 오차는 어떻게 계산하고 허용 범위는 얼마인가요?

실제 보레이트 = PCLK / (16 * USARTDIV)이며, USARTDIV는 분주기 레지스터 값입니다. 오차 백분율은 |실제 - 목표| / 목표 * 100%입니다. 안정적인 통신을 위한 허용 범위는 일반적으로 2% 이내이며, 1% 이하가 선호됩니다. 클럭 주파수, 프리스케일러 설정, 분주기 세분성이 달성 가능한 정확도에 영향을 줍니다. 예를 들어 72MHz 클럭은 USARTDIV = 39.0625로 정확한 115200 보레이트를 달성합니다.