13.2.1.2.1. UART 기반 통신 시 DMA(Direct Memory Access) 전송 설정과 수신 버퍼(FIFO) 오버런(Overrun) 방지
PX4-Autopilot 생태계의 비행 제어기(Pixhawk 등) 마더보드는 센서, 모터 제어, 텔레메트리, 컴패니언 컴퓨터 통신 등 수많은 데이터 인터페이스를 처리하기 위해 STM32 계열과 같은 고성능 마이크로컨트롤러(MCU)를 채택한다. 이 과정에서 필연적으로 발생하는 병목 현상이 바로 직렬(UART) 입출력 통신의 오버헤드이다. особенно 고빈도(High-rate)의 RTK 보정 데이터(RTCM)와 극초정밀 위상 관측 패킷(UBX/NMEA)을 다룰 때, 구시대적인 인터럽트(Interrupt) 기반의 폴링(Polling) 방식은 CPU 자원을 고갈시키고 시스템 지연을 초래한다.
본 절에서는 이러한 문제를 하드웨어적으로 타파하기 위한 DMA(Direct Memory Access) 기반 UART 파이프라인의 설계 원리와, NuttX RTOS 기반의 PX4 펌웨어 환경에서 수신 버퍼 FIFO(First-In, First-Out) 오버런(Overrun) 현상을 방어하기 위한 소프트웨어적/하드웨어적 버퍼링 메커니즘을 심층 분석한다.
1. DMA(Direct Memory Access)의 동작 원리 및 이점
기본적으로 UART 통신 포트에 한 바이트의 데이터가 도착하면, 수신 레지스터(RXR)에 인터럽트 플래그가 뜬다. 만약 DMA가 없다면, CPU는 즉각 현재 실행 중인 EKF2 필터나 메인 스케줄러의 컨텍스트를 스위칭(Context Switching)하고 UART 인터럽트 서비스 루틴(ISR)으로 점프하여 데이터를 메모리로 복사해야 한다. 초당 수천 바이트가 수신되는 환경에서 이 과정은 전체 비행 제어 시스템의 응답성을 지연시킨다.
DMA 컨트롤러는 CPU의 개입 없이 메모리(RAM)와 주변장치(UART Peripheral) 사이에 직접적인 데이터 전송 고속도로를 뚫어주는 전용 하드웨어 유닛이다.
- CPU 로드(Load) 해방: DMA가 활성화되면 UART 수신기는 바이트가 도착할 때마다 CPU를 귀찮게 하지 않고, DMA 컨트롤러에게 스스로 직접 신호를 보낸다. DMA는 이 데이터를 미리 할당받은 RAM(수신 버퍼) 공간으로 조용히 적재(Direct Copy)한다.
- 블록 전송 종료 인터럽트: DMA 기능은 설정해둔 수신 버퍼 사이즈(예: 멀티-바이트 덩어리)가 꽉 찼을 때만, 혹은 Idle Line (수신 패킷 유입이 멈췄을 때) 조건에서만 단 1회의 인터럽트를 발생시켜 CPU에게 “수신 완료“만 알리면 된다. 이로 인해 CPU 점유율(Overhead)이 드라마틱하게 하락한다.
2. PX4 NuttX 하단에서의 DMA 설정(Config) 과정
Pixhawk 하드웨어 아키텍처에서 DMA 자원은 무한하지 않다. STM32 칩셋의 DMA 컨트롤러 스펙 채널 수에 제약이 있기 때문에, PX4-Autopilot의 보드 구성 파일(Board Configuration)에서 어느 UART 포트에 DMA를 강제 마운트할지 명시적으로 맵핑되어 있다.
// 예시: nuttx/boards/arm/stm32/px4-fmu-v5/src/stm32_serial.c
// 직렬 포트에 DMA 스트림(Stream) 지정 코드 스니펫 예시
#if defined(CONFIG_USART1_RXDMA)
/* DMA 스트림 주소 타겟 설정: UART1_RX -> 메모리 버퍼 */
# define DMAMAP_USART1_RX STM32_DMA_MAP(DMA2, DMA_STREAM5, DMA_CHAN4)
#endif
- 위와 같이
px4_fmu-vX_default등 빌드 타겟의 매크로 옵션에서 특정 포트(주로 메인 텔레메트리나 메인 GPS/RTK 포트)에 DMA-RX 및 DMA-TX를 켜주는(Enable) 코드가 하드코딩되어 동작한다. - 개발자 지침: 만약 사용자가 커스텀 하드웨어를 제작하거나 보조 GPS(Secondary RTK)를 전혀 규격에 맵핑되지 않은 포트(예: 직렬 포트 4, UART6 등)에 연결할 경우, DMA가 꺼져 있어 통신 지연으로 인한 3D Fix 딜레이 현상을 겪기도 한다. 따라서 고대역폭 센서는 반드시 매뉴얼 상 “DMA-Enabled” 포트에 꽂는 것이 설계 제 1원칙이다.
3. FIFO 오버런(Overrun)의 정의와 치명적 결과
UART 하드웨어 자체에는 통상 1바이트 혹은 수 바이트 크기의 극히 작은 하드웨어 수신 버퍼(Hardware FIFO)가 존재한다.
- 오버런 레이스 조건: 데이터가 하드웨어 FIFO에 도착하였으나, 앞선 데이터를 DMA 모듈이 RAM으로 미처 빼내가기도 전에 추가적인 바이트가 외부 안테나로부터 초당 수천 바이트의 속도로 들이닥치는 현상을 말한다.
- 현상 및 결과: 기존의 데이터가 덮어씌워지거나(Overwritten) 누락 분실되면서, RTCM 프레임의 길이 비트(Length Bit)나 헤더(Header)가 어긋난다. 결국 CRC 검증 무결성이 붕괴되어
gps_driver데몬이 전체 다중 프레임(2\text{KB} \sim 3\text{KB})을 폐기(Drop)해 버린다. 이는 RTK Fix 상태를 치명적인 Float 혹은 DGPS 상태로 추락시키는 1등 공신이다.
4. 오버런 방지를 위한 소프트웨어 버퍼링(Buffering) 아키텍처
오버런을 방지하기 위해 PX4 생태계는 하드웨어와 소프트웨어가 결합된 이중 버퍼(Double Buffer) 또는 링 버퍼(Ring Buffer) 기법을 포괄적으로 활용한다.
graph LR
A[RTK UART RX Pin] -->|Baudrate: 115200| B[UART 하드웨어 FIFO 단 (1~8 Bytes)]
B -.->|Hardware Overrun 위험 구역| B
B -->|DMA Direct Copy| C[NuttX 시리얼 \n 링 버퍼(Ring Buffer) \n 통상 1024~4096 Bytes]
C -->|Read() 시스템 콜| D[px4_gps_driver 데몬 내부 \n 사용자 공간 버퍼]
D -->|RTCM Parser| E[EKF2 추정기]
4.1 링 버퍼 (Ring Buffer / Circular Buffer) 크기 최적화
NuttX 레벨에서 각 직렬 포트는 고유의 RX 버퍼 크기를 갖는다. gps_driver가 실행 시 이 포트를 열면(open()), OS 메모리 힙(Heap) 공간에서 직렬 입력을 담아둘 버퍼가 형성된다.
- ZED-F9P 같은 고해상도 수신기의 RTCM 및 UBX 스트림 병합본은 한 한 번의 Epoch(1회 계산 주기)에 1\text{KB}가 쉽게 넘어설 수 있다.
- 따라서 PX4 펌웨어에서는 이 포트를 개방할 때
tcsetattr등의 시스템 함수를 거치며 수신 버퍼 사이즈(RX Buffer Size)를 최소 2048 \sim 4096 \text{ Bytes} 이상으로 동적 확보하는 방어적 로직이 삽입되어야 통신 부하가 높을 때 링 버퍼 오버플로우까지 예방할 수 있다.
4.2 보드레이트(Baud Rate)와 처리 주기의 불균형
CPU 클럭이나 메인 스레드 응답성이 떨어져 read()를 호출하는 주기가 지연되면 오버런이 발생한다.
해결책으로, GPS와 통신하는 Baud rate를 물리적 한계치(예: 460800\text{ bps} 이상)로 올림과 동시에, DMA 인터럽트 발생 트리거 간격을 조정하여 CPU가 더 빠른 주기로 짧게 조각난 데이터를 퍼가게 만드는 아키텍처 조율이 동반되어야 한다.
이와 같이 UART 통신의 DMA 활성화와 FIFO 오버플로우 방어는 고가의 RTK 모듈 성능을 100% 이끌어내기 위해 반드시 성립되어야 할 시스템 아키텍처의 기춧돌(Foundation)이다. 아무리 수학적으로 우수한 항법 모델이라도 제시간에 메모리에 안전하게 도착하지 못한 센서값은 항공기에게 불필요한 노이즈 찌꺼기에 불과함을 명심해야 한다.