문의 EN
기술 노트

임베디드 소프트웨어, 개념에서 양산까지

임베디드 소프트웨어는 코드가 동작하는 것만으로 끝나지 않습니다. 정해진 하드웨어에서, 정해진 시간 안에, 10년 넘게 문제없이 돌아야 하고, 수천 대를 같은 품질로 만들 수 있어야 합니다. 개발 과정에서 무엇을 언제 결정해야 하는지 순서대로 정리했습니다.

읽는 시간 약 9분

1임베디드 소프트웨어란

임베디드 소프트웨어는 기기 안에 들어가 그 기기 하나만을 위해 동작하는 프로그램입니다. 같은 프로그램이라도 PC 프로그램과는 전제가 다릅니다.

구분PC 프로그램임베디드 소프트웨어
하드웨어어떤 PC에서 돌지 모른다정해진 보드 하나에서만 돈다
시간조금 늦어도 결과가 맞으면 된다정해진 시간 안에 반응해야 한다 (실시간성)
자원메모리와 저장 공간이 넉넉하다메모리가 수십~수백 KB인 경우가 많다
수명몇 년마다 새로 설치한다한 번 출하하면 10년 이상 쓰이기도 한다
문제가 생기면사용자가 다시 실행한다다시 켜 줄 사람이 없는 곳에 있을 수 있다

실시간성은 "빠르다"는 뜻이 아닙니다. 모터를 멈추라는 신호에 1초 뒤 반응한다면, 결과가 맞아도 틀린 동작입니다. 임베디드 소프트웨어의 정확성에는 시간이 포함됩니다.

실무 기준

처음 설계할 때 "이 기기는 아무도 다시 켜 줄 수 없는 곳에 있다"고 가정합니다. 그러면 워치독(멈춘 프로그램을 자동으로 다시 시작시키는 회로)과 전원 이상 뒤의 복구 동작을 처음부터 넣게 됩니다.

2OS는 왜 필요한가

작은 기기는 OS 없이 만드는 경우가 많습니다. 이 구조를 슈퍼 루프라고 부릅니다. main 함수 안의 무한 반복문이 할 일을 차례로 확인하고, 급한 일은 인터럽트(하드웨어가 프로그램 흐름을 잠시 끊고 알리는 신호)로 처리합니다. 구조가 단순하고, 메모리를 적게 쓰고, 동작을 예측하기 쉽습니다.

문제는 할 일이 늘어날 때 생깁니다. 반복문 안의 작업 하나가 길어지면 나머지 작업이 모두 늦어집니다. 통신 데이터를 처리하는 동안 버튼 반응이 느려지는 식입니다. 이를 피하려고 긴 작업을 잘게 쪼개다 보면 상태 변수가 늘고, 타이밍 조건이 코드 전체에 흩어져 고치기 어려워집니다.

RTOS(실시간 운영체제)는 이 문제를 구조로 해결합니다.

  • 작업 분리: 기능별로 작업(태스크)을 나누어 각자 독립된 코드로 작성합니다.
  • 우선순위: 급한 작업에 높은 우선순위를 주면, 낮은 작업이 실행 중이어도 스케줄러가 급한 작업을 먼저 실행합니다(선점).
  • 타이밍: 주기 실행, 시간 제한이 있는 대기, 작업 사이의 데이터 전달(큐, 세마포어)을 OS가 제공합니다.

대가도 있습니다. 작업마다 스택 메모리가 필요하고, 여러 작업이 같은 자원을 쓸 때 충돌을 막는 설계가 필요합니다. 낮은 우선순위 작업이 자원을 쥐고 있어 높은 작업이 기다리는 우선순위 역전 같은, OS 없는 구조에는 없던 문제도 생깁니다.

실무 기준

할 일이 두세 가지이고 주기가 단순하거나, 대부분의 시간을 잠자며 배터리로 오래 버텨야 하는 기기라면 OS 없이 가는 편이 낫습니다. 반대로 "통신을 처리하는 중에도 다른 기능의 응답 시간을 지켜야 하는가?"라는 질문에 "예"라면 RTOS를 씁니다.

그림 1. 슈퍼 루프는 작업을 차례로 실행하므로 한 작업이 길어지면 모두 늦어집니다. RTOS는 우선순위에 따라 급한 작업을 먼저 실행하고, 작업끼리는 큐로 데이터를 주고받습니다.

3무료로 쓸 수 있는 OS

상용 OS 못지않게 쓰이는 무료 OS가 여럿 있습니다. 성격이 서로 달라 "가장 좋은 OS"보다 "이 제품에 맞는 OS"를 고르는 것이 중요합니다.

OS성격이런 때 고른다
FreeRTOS커널 중심의 작고 단순한 RTOS. 지원하는 MCU가 가장 많은 편이다작은 MCU, 기존 코드에 작업 분리만 더하고 싶을 때
Zephyr커널, 드라이버, 네트워크·무선 통신 스택, 빌드 체계를 함께 갖춘 통합형 RTOS네트워크 기능이 많고 여러 보드를 한 코드로 지원할 때. 익히는 데 시간이 든다
RT-Thread커널에 파일시스템, 네트워크, USB 같은 구성 요소를 골라 붙이는 RTOS파일시스템·USB 같은 기능을 함께 쓰는 중간 규모 기기
NuttXPOSIX(유닉스 계열 표준 인터페이스)를 따르는 RTOS리눅스식 프로그래밍 방식을 MCU에서 쓰고 싶을 때
Eclipse ThreadX소형 MCU용 실시간 운영체제. 현재 오픈 소스로 공개되어 있다쓰려는 칩의 개발 환경이 ThreadX를 함께 제공할 때
임베디드 Linux메모리 관리 장치(MMU)가 있는 프로세서와 수십 MB 이상의 메모리가 필요한 범용 OS화면, 복잡한 네트워크, 파일 처리가 많은 장치. 부팅 시간과 실시간성, 소비 전력을 따로 따져야 한다

라이선스도 함께 봐야 합니다. 앞의 다섯 RTOS는 상업 제품에 쓰기 쉬운 라이선스(MIT 또는 Apache 2.0)를 씁니다. Linux 커널은 GPL이라 배포할 때 소스 공개 같은 조건이 따릅니다.

실무 기준

OS를 고를 때는 기능 목록보다 먼저 "쓰려는 칩의 제조사가 이 OS를 공식 지원하는가", "필요한 주변장치 드라이버가 이미 있는가"를 확인합니다. 드라이버를 새로 만드는 시간이 OS 기능 차이보다 훨씬 큰 경우가 많습니다.

4개발이 끝난 뒤 어떻게 검증하는가

기능이 동작하는 것을 확인했다고 검증이 끝난 것은 아닙니다. 현장에서 문제가 되는 것은 대부분 "가끔", "오래 쓰면", "특정 조건에서" 생기는 오류입니다.

  1. 단위 시험: 함수나 모듈을 하나씩 떼어 입력과 결과를 확인합니다. 하드웨어 의존 부분을 분리해 두면(7장) 보드 없이 PC에서도 시험할 수 있습니다.
  2. 하드웨어 연동 시험: 실제 보드에서 주변장치, 통신, 전원 동작을 확인합니다.
  3. 장시간 시험: 며칠에서 몇 주 동안 계속 돌립니다. 메모리 누수, 카운터 넘침, 드물게 겹치는 타이밍 문제는 이렇게 해야 드러납니다. 예를 들어 1ms마다 늘어나는 32비트 카운터는 약 49.7일 만에 0으로 돌아갑니다. 이때 시간 계산이 틀어지는 코드는 짧은 시험으로는 찾을 수 없습니다.
  4. 경계·이상 조건 시험: 전원이 순간적으로 끊기거나, 통신선이 빠지거나, 잘못된 데이터가 들어오거나, 온도가 한계에 가까울 때 기기가 어떻게 행동하는지 봅니다. 목표는 "고장 나지 않음"이 아니라 "안전하게 멈추고 스스로 회복함"입니다.
  5. 정적 분석: 코드를 실행하지 않고 도구로 검사해 초기화하지 않은 변수, 배열 범위 초과, 위험한 형 변환 같은 잠재 오류를 찾습니다.

실무 기준

출시 뒤 가장 늦게 발견되고 가장 비싼 문제는 장시간 시험과 이상 조건 시험에서 나옵니다. 일정이 빠듯할수록 이 두 가지를 먼저 계획에 넣습니다.

5양산이 목적이면 왜 하드웨어 설계부터 고려해야 하는가

시제품 몇 대는 손으로 만들 수 있습니다. 수천 대를 같은 품질로 만들려면 양산 공정이 설계에 들어가 있어야 합니다. 이 결정은 대부분 회로와 기판 단계에서 끝납니다.

  • 펌웨어 기록 단자: 기판마다 펌웨어를 넣어야 합니다. 기록용 단자를 검사 지그의 핀이 닿기 쉬운 위치에 패드로 두면, 커넥터를 꽂지 않고 여러 대를 한 번에 기록할 수 있습니다.
  • 검사 포인트: 전원 전압, 주요 신호를 측정할 지점을 기판에 미리 둡니다. 없으면 불량이 나도 원인을 좁히기 어렵습니다.
  • 고유값 기록: 일련번호, 통신 주소, 보정값처럼 기기마다 다른 값을 언제, 어디에, 어떻게 기록하고 이력으로 남길지 정합니다.
  • 부품 수급과 단종: 수명이 긴 부품, 대체품이 있는 부품을 고릅니다. 단종 통보는 양산이 한창일 때 옵니다.
  • 검사 시간과 생산 단가: 대당 검사 시간이 곧 비용입니다. 한 대에 1분을 줄이면 1만 대에서 약 167시간이 줄어듭니다. 펌웨어에 검사용 명령을 처음부터 넣어 두면 지그가 기능을 빠르게 확인할 수 있습니다.

실무 기준

시제품 기판을 양산 기판으로 바꿀 때 검사 패드와 기록 단자를 추가하면 회로와 기판을 한 번 더 고쳐야 합니다. 양산 검사 설비를 직접 만들어 본 경험으로는, 첫 시제품 회로에서부터 이것들을 넣는 것이 가장 싸게 먹힙니다.

6부트로더와 현장 펌웨어 업데이트

출시 뒤에도 기능을 고치고 더할 수 있으려면 펌웨어를 교체하는 구조가 필요합니다. 보통 메모리를 부트로더(전원이 켜지면 가장 먼저 실행되어 응용 펌웨어를 검사하고 실행하는 작은 프로그램)와 응용 펌웨어 영역으로 나눕니다.

  • 업데이트 경로: 시리얼, USB, 네트워크, 무선 통신 중 제품에 맞는 것을 고릅니다.
  • 중간에 끊겨도 살아나야 한다: 업데이트 도중 전원이 꺼질 수 있습니다. 새 펌웨어를 다른 영역에 받아 검사한 뒤 바꾸거나(이중 영역), 실패하면 이전 펌웨어로 되돌아가게 합니다.
  • 무결성 확인: 받은 펌웨어가 손상되지 않았는지 검사값(CRC)으로 확인하고, 필요하면 전자 서명으로 정품 여부도 확인합니다.
  • 버전 관리: 어떤 기기에 어떤 버전이 들어 있는지 알 수 있어야 현장 문제에 대응할 수 있습니다.

실무 기준

부트로더는 출하 뒤 고칠 수 없다고 보고 설계합니다. 기능은 최소한으로, 시험은 가장 많이 합니다.

7부품 단종에 대비한 계층 구조

제품을 오래 팔다 보면 MCU나 주변 칩이 단종되는 일이 반드시 생깁니다. 이때 펌웨어 전체를 새로 만들지 않으려면 처음부터 하드웨어에 의존하는 부분과 응용 로직을 나눠야 합니다.

  • 하드웨어 추상화 계층(드라이버): 레지스터, 핀, 클록처럼 칩마다 다른 부분. 칩이 바뀌면 이 계층만 고칩니다.
  • 서비스 계층: 통신 규약 처리, 저장, 업데이트처럼 여러 기능이 함께 쓰는 부분.
  • 응용 계층: 제품이 실제로 하는 일. 하드웨어를 직접 만지지 않고 아래 계층의 함수만 부릅니다.

계층 사이를 함수 인터페이스로 정해 두면, 칩을 바꾸거나 OS 없는 구조에서 RTOS로 옮길 때 고칠 범위가 작아집니다. 앞에서 말한 PC 단위 시험도 이 구조 덕분에 가능합니다.

실무 기준

응용 코드에서 레지스터 이름이 보이기 시작하면 이식 비용이 커지고 있다는 신호입니다. 여러 세대의 MCU를 거치며 이식을 반복해 보면, 처음 구조를 잘 나눈 제품은 다음 제품을 절반의 시간으로 만들 수 있습니다.

그림 2. 응용 로직과 서비스는 하드웨어를 직접 다루지 않으므로, 칩이 바뀌어도 하드웨어 추상화 계층만 고치면 됩니다.

8디버깅 도구와 방법

임베디드 기기는 화면이 없거나 작아서 프로그램 안에서 무슨 일이 일어나는지 보기 어렵습니다. 도구를 상황에 맞게 골라야 합니다.

도구하는 일이럴 때 쓴다
JTAG·SWD 디버거실행을 멈추고 변수, 메모리, 레지스터를 본다. SWD는 핀 2개로 연결하는 디버그 방식이다로직 오류, 예외 발생 위치 찾기
로그 출력시리얼 등으로 실행 흐름과 값을 시간과 함께 남긴다멈추면 안 되는 동작, 현장 재현
로직 분석기여러 디지털 신호를 시간 축으로 동시에 보고 통신 내용을 해석한다통신 타이밍, 신호 순서 문제
오실로스코프전압 파형을 본다전원 흔들림, 잡음, 신호 품질

디버거로 실행을 멈추면 타이밍이 바뀌어 문제가 사라지기도 합니다. 통신이나 모터 제어처럼 시간이 중요한 동작은 멈추지 말고 로그와 신호 측정으로 봐야 합니다. 로그도 출력하는 데 시간이 걸리므로, 많이 남길수록 동작이 달라질 수 있다는 점을 기억해야 합니다.

실무 기준

증상이 가끔 나타날수록 로그와 로직 분석기를 함께 걸어 두고 재현을 기다립니다. 원인을 추측해 코드를 고치는 것보다, 증상이 나온 순간의 기록 하나가 더 빨리 답을 줍니다.