베어메탈에서 운영체제로: 임베디드 개발 초점을 바꾼 이유
"베어메탈 시대" 회고
임베디드 소프트웨어와의 첫 만남은 2008년, 2학년이던 제가 8051 칩으로 프로그래밍을 배우면서 시작되었습니다. 컴퓨터 공학을 전공해 대부분의 코드가 PC에서 돌아가던 저에게, 프로그램이 베어메탈 보드에서 직접 실행되는 것을 보는 것은 획기적인 경험이었습니다. 첫 사이클링 램프 펌웨어가 완벽하게 작동하던 순간을 아직도 기억합니다. 하지만 베어메탈 프로젝트를 더 많이 다룰수록 더 많은 과제가 드러났습니다.
베어메탈 개발의 주요 난제
동시성
베어메탈 펌웨어에서 단일 while (1) 루프에 거의 모든 트랜잭션 로직이 들어갑니다. 한 루틴이 지연 함수를 호출하면 CPU가 그 지연에 갇혀 다른 모든 작업이 대기해야 합니다. 이 직렬 실행은 CPU 사이클을 낭비하고 동시성을 심각하게 제한합니다.
모듈성
모든 함수가 단일 루프에 뭉쳐 있으면 높은 응집도와 낮은 결합도를 달성하기 어렵습니다. 의존성이 긴밀해져 코드 리팩토링이나 대규모 프로젝트 확장이 어렵습니다. 예를 들어:
- 함수들이 끝없는 루프에 뒤섞여 있어 명확한 모듈 경계 설정이 불가능합니다.
- 워치독 타이머 근처에서 지연 함수를 사용하려면 신중한 타이밍이 필요합니다. 잘못 계산된 지연은 워치독 리셋을 유발해 복잡성을 더합니다.
생태계 제약
많은 고급 소프트웨어 구성요소는 하위 수준 OS에 의존합니다. 몇 가지 예:
FreeModbus 기반 오픈소스 프로젝트를 다양한 플랫폼(베어메탈 보드 포함)에 포팅하려 했습니다. 하지만 각 보드마다 필요한 모든 기능을 처음부터 구현하기엔 너무 복잡해 현재 제 Modbus 스택은 베어메탈 시스템에서 실행되지 않습니다. - Realtek, TI, MediaTek 같은 주요 SDK는 OS 위에서만 작동하며 펌웨어 소스 코드를 공개하지 않아 순수 베어메탈 환경에서 사용할 수 없습니다.
실시간 요구사항
산업 제어 시스템은 정밀한 타이밍을 요구합니다. 기계 액추에이터는 엄격한 순서를 따라야 합니다. 모든 로직이 단일 루프에 압축되면 실시간 동작 보장이 거의 불가능해 시스템 장애와 안전 위험을 초래합니다.
재사용성
기능이 특정 하드웨어에 강하게 결합되어 있어 새 플랫폼마다 코드를 다시 작성해야 합니다. 이는 중복 작업을 초래하고 제품 개발을 늦춥니다.
운영체제의 이점
2010년경 STM32 MCU가 인기를 얻으면서 RT-Thread를 실험하기 시작했습니다. 지난 10년간 RT-Thread를 광범위하게 사용하며 임베디드 개발을 어떻게 변화시키는지 체감했습니다.
모듈성
RTOS는 펌웨어를 각자의 실행 컨텍스트를 가진 독립적인 스레드로 나눕니다. 이 분리는 자연스럽게 모듈성을 높이고 유지보수를 단순화합니다.
동시성
스레드가 sleep()을 호출하거나 양보하면 스케줄러가 자동으로 다른 준비된 스레드에 제어권을 넘겨 CPU 활용도와 전체 시스템 동시성을 향상시킵니다.
실시간 보장
RTOS는 결정론적 스케줄링을 제공합니다. 작업에 우선순위가 있고 커널이 높은 우선순위 작업이 낮은 우선순위 작업을 선점하도록 보장합니다. 이 내장된 실시간 동작은 안전 중요한 애플리케이션에 필수적입니다.
개발 효율성
OS는 세마포어, 이벤트 플래그, 메일박스, 링 버퍼, 연결 리스트 등 통합된 API 세트를 제공해 개발자가 저수준 배관 작업이 아닌 애플리케이션 로직에 집중할 수 있게 합니다.
소프트웨어 생태계
Linux와 RT-Thread 모두 하드웨어 세부사항을 추상화하는 디바이스 드라이버 프레임워크를 구현합니다. 엔지니어는 드라이버를 한 번 작성해 여러 보드에 배포할 수 있어 플랫폼별 코드를 획기적으로 줄입니다. 이 생태계는 공유도 장려합니다. 저는 정기적으로 GitHub에 오픈소스 구성요소를 공개하고, 전 세계 동료들이 기여하며 활기찬 협업 커뮤니티를 형성합니다.
결론
베어메탈에서 RTOS로의 전환은 모듈화되고 동시적이며 실시간에 안전한 코드 작성 능력을 확장했습니다. 또한 재사용 가능한 구성요소가 번성하고 개발자들이 하드웨어 경계를 넘어 협업할 수 있는 더 풍부한 생태계를 열었습니다.