Sonji-log

[SensorHIL] Ep 1. 개발시작 및 목업 돌려보기 본문

개발일지_SensorHIL/개발일지

[SensorHIL] Ep 1. 개발시작 및 목업 돌려보기

Sonji 2026. 8. 31. 11:36

만들게 된 이유

하드웨어 개발에서 가장 큰 스트레스는 정상 동작하는 실물이 있어야 개발 및 테스트가 제대로 진행된다는 점이다.
심지어 모든 실물이 갖추어져 있다고 하더라도, 정말 예상치 못한 부분에서 문제가 언제 어떻게 터질 지 모른다는 점도 마찬가지다.

가뜩이나 AI 코딩의 생산성이 어마어마한 지금, 이런 병목을 가만 둘 수가 없었다.
그래서, 간략하게나마 "모든 하드웨어가 정상적으로 동작한다고 가정할 때, 통신 혹은 알고리즘 등의 원활한 개발을 위해" 센서를 모사하는 에뮬레이터를 만들어보기로 했다.

 

회사에서 진행하는 Embedded Project에는 STM32가 UART로 외부 농도 Sensor 값을 읽는 기능이 있다. 실제 제품의 세부 내용보다는, Sensor Request와 Response를 처리하는 Firmware 통신 부분을 먼저 Test 대상으로 잡았다.

 

예를 들어, STM32에서 UART 센서를 사용하는 코드를 작성한다고 가정해보자.

보통 아래 순서로 동작한다.

STM32
→ Sensor Request 전송
→ Sensor Response 수신
→ Frame 및 CRC 검사
→ 측정값 사용

이 코드를 실제로 확인하려면 센서, 케이블, 전원, UART 변환 장치가 모두 필요하다.

센서가 아직 준비되지 않았거나 사용할 수 있는 센서 수량이 부족하다면, 코드를 작성하더라도 실제 응답을 받아보기 어렵다.
(경험상 일반적으로 보드가 센서보다 배송이 많이 빠른 편이다)

센서가 있더라도 CRC가 잘못된 응답이나 Timeout을 원하는 시점에 반복해서 만들기도 어렵다.

그래서 PC가 센서 대신 응답하도록 만들었다.

STM32
→ Sensor Request
→ PC Fake Sensor
→ Sensor Response
→ STM32 Parser

PC는 실제 UART로 연결된다.

따라서 STM32 입장에서는 상대가 실제 센서인지 PC 프로그램인지 구분할 필요가 없다.

 

Q1. Unit Test에서 UART 함수를 Mocking하면 되는 것 아닌가요?

A1. Parser와 CRC 계산만 확인한다면 Unit Test로도 가능하다. 하지만 실제 UART에서 발생하는 partial read, timeout, 이전 데이터 잔류, HAL receive state까지 확인하려면 실제 STM32와 UART를 포함해야 한다. SensorHIL은 Unit Test를 대체하기보다 Unit Test에서 빠지는 실제 통신 경로를 확인하기 위해 만들었다.

첫 구현 대상 - DS4 계열 유해가스검출 Sensor

DS4 계열 유해가스검출 Sensor는 회사 내 프로젝트에서 STM32와 연동해야 했던 UART 방식의 농도 Sensor다. ASCII 한 글자인 C를 받으면 ppm 단위의 농도값과 CRC를 문자열로 돌려준다.

첫 번째 구현 대상은 이 DS4 Sensor의 농도 조회 명령 C다.

DS4의 모든 명령을 구현하지 않고, 요청부터 parser까지 한 번에 확인할 수 있는 최소 범위만 구현했다.

Request  : C
HEX      : 43

Response : :0.100ppm,54316\r\n
HEX      : 3A 30 2E 31 30 30 70 70 6D 2C 35 34 33 31 36 0D 0A

Response는 아래 요소로 구성된다.

:          Frame 시작
0.100      농도값
ppm        단위
,          CRC 계산 범위의 마지막 byte
54316      Decimal ASCII CRC
\r\n       Frame 종료

CRC core는 CRC-16/Modbus를 사용한다.

본문 :0.100ppm,의 계산 결과는 0x2CD4다.

DS4에서는 두 byte의 표현 순서를 바꾼 0xD42C를 만들고, 이를 decimal 값인 54316으로 붙인다.

CRC-16/Modbus(':0.100ppm,') = 0x2CD4
DS4 byte presentation       = 0xD42C
Decimal ASCII               = 54316

PC의 buildDs4CResponse()는 농도값을 소수점 아래 세 자리로 만든 다음 CRC와 CRLF를 붙인다.

STM32 parser는 frame, 숫자, ppm, comma, CRC를 순서대로 검사한다.

성공한 값은 milli-ppm 정수로 저장한다.

0.100 ppm  → 100 milli-ppm
12.345 ppm → 12345 milli-ppm

 

Q2. PC와 STM32가 같은 CRC 코드를 공유하면 관리하기 쉽지 않나요?

A2. 관리 자체는 쉬워진다. 하지만 CRC 코드에 오류가 있을 경우 PC와 STM32가 같은 오류를 공유할 수 있다. 잘못된 frame을 만들고도 서로 정상이라고 판단할 가능성이 생긴다. 현재는 PC encoder와 STM32 parser가 CRC를 각각 구현하고, 알려진 byte 예제로 결과만 비교한다.

Fault Injection

정상 응답만 확인해서는 오류 처리와 복구를 알 수 없다.

PC Sensor Model에 아래 fault를 추가했다.

Invalid CRC

정상 response를 만든 다음 CRC의 마지막 숫자만 변경한다.

Normal : :0.100ppm,54316\r\n
Fault  : :0.100ppm,54310\r\n

다른 field는 정상으로 유지한다.

STM32가 framing error가 아닌 CRC mismatch로 분류하는지 확인하기 위함이다.

Timeout

PC는 유효한 C 요청을 읽지만 response byte를 하나도 보내지 않는다.

COM Port는 계속 연결되어 있다.

STM32는 500 ms response deadline이 끝난 뒤 Timeout으로 처리한다.

Malformed Frame

완성된 frame에서 규칙 하나만 변경한다.

Missing Prefix    : 0.100ppm,36356\r\n
Invalid Value     : :ABCppm,61151\r\n
Missing Delimiter : :0.100ppm17300\r\n

각 fault는 한 시점에 하나만 사용한다.

여러 field를 동시에 망가뜨리면 parser가 어떤 규칙 때문에 실패했는지 구분하기 어렵기 때문이다.

Timeout 이후 복구

Timeout을 구현한 뒤, fault를 해제하더라도 첫 정상 frame을 바로 처리하지 못할 수 있다는 문제가 있었다.

늦게 도착한 byte나 HAL RX 상태가 다음 transaction에 남을 수 있기 때문이다.

STM32 client는 timeout/error 직후와 다음 request 직전에 아래 항목을 정리한다.

  • UART error flag
  • HAL receive state
  • Peripheral RX data
  • Software receive buffer

복구 기준은 Fault를 Normal로 바꾼 뒤 다음 polling에서 바로 정상 response를 parse해야 한다.

실제 시험에서는 Invalid CRC에서 parse error count가 증가했다.

Timeout 시험 한 번에서는 request 20회가 response 12회와 timeout 8회로 구분됐다.

Fault를 해제한 뒤에는 Reset 없이 HAL_OK, 농도 100 milli-ppm, CRC 54316으로 돌아왔다.

위 숫자는 한 실행에서 나온 누적값이다. Test의 고정 expected 값은 아니다.

Sensor Simulator와 Sensor Tester의 차이

SensorHIL은 실제 가스 농도를 만들지 않는다.

따라서 아래 항목을 검증하지 않는다.

  • Accuracy
  • T90
  • Drift
  • 온도, 습도, 압력에 따른 실제 센서 특성

현재 확인하는 항목은 아래와 같다.

  • UART Request/Response
  • Frame 누적 수신
  • 문법 및 CRC 검사
  • Timeout과 오류 분류
  • 오류 이후 통신 복구

즉, 센서 자체의 성능을 시험하는 장비가 아니라 센서를 사용하는 Firmware의 통신과 robustness를 확인하는 HIL이다.

결론

  • 실제 센서가 없어도 PC가 UART Sensor 역할을 대신할 수 있다.
  • 첫 구현은 DS4 C 명령 하나로 범위를 제한했다.
  • 정상 응답뿐 아니라 CRC, Timeout, Malformed fault를 재현했다.
  • Timeout 이후에는 UART와 software buffer를 정리해야 다음 정상 통신이 가능했다.
  • SensorHIL은 센서 Accuracy가 아니라 Firmware의 통신과 복구를 확인한다.

코멘트

처음에는 DS4 응답 문자열만 만들어 보내면 될 것이라고 생각했다.

실제로 STM32와 연결해보니 CRC 계산보다 Timeout 이후 RX 상태를 정리하는 부분이 더 까다로웠다.

PC에서 정상 frame을 보냈다는 사실만으로 STM32가 정상 처리했다고 판단할 수도 없었다. 이 문제 때문에 이후 별도의 DUT Observation UART와 자동 판정 구조를 추가했다.

새 Sensor 명령을 추가할 때도 명령 수를 먼저 늘리기보다, Request부터 오류 복구까지 한 경로를 먼저 확인하는 방식은 유지할 예정이다.