개념
CAN은 왜 다른가
레슨 2의 UART·SPI·I2C는 보드 안의 짧은 연결이었다. CAN(Controller Area Network)은 여러 ECU가 차량 전체에 걸친 두 선(CAN_H, CAN_L)을 공유 하는 버스다. 차동 신호라 잡음에 강하고, 마스터가 없으며, 모든 노드가 모든 프레임을 듣는다. 프레임에는 목적지 주소가 없고 ID 가 있다. ID는 "누구에게"가 아니라 "무슨 내용인가"(예: 0x1A0 = 차속)를 뜻한다.
중재 — ID가 작을수록 이긴다
두 노드가 동시에 송신을 시작하면 ID 비트를 한 비트씩 내보내며 버스를 읽는다. 0(dominant)이 1(recessive)을 이긴다. 자기가 1을 보냈는데 버스가 0이면 진 것이므로 조용히 물러나 나중에 다시 보낸다. 결과적으로 ID 값이 작을수록 우선순위가 높다. 이긴 프레임은 손상 없이 전송되므로 충돌로 대역폭을 잃지 않는다.
테스터에게 중요한 결과는 이것이다. 버스 부하가 높을 때 낮은 우선순위(큰 ID) 메시지는 계속 밀려 지연된다. 브레이크 신호는 늦지 않지만 진단 메시지나 편의 기능 메시지는 수십 ms 늦을 수 있다. 버스 부하율(보통 설계 목표 50~70% 이하)과 큰 ID 메시지의 최악 지연은 측정 대상이다.
클래식 CAN · CAN FD · CAN XL
| 항목 | 클래식 CAN | CAN FD | CAN XL |
|---|---|---|---|
| 페이로드 최대 | 8바이트 | 64바이트 | 2048바이트 |
| 비트레이트 | 최대 1 Mbit/s | 중재 구간은 클래식과 같고, 데이터 구간은 대략 최대 8 Mbit/s | 데이터 구간 대략 10~20 Mbit/s |
| 규격 | ISO 11898-1 | ISO 11898-1 | ISO 11898-1:2024 |
| 쓰임 | 파워트레인·바디·섀시 전통 영역 | 늘어난 신호, 보안 메시지 인증, 플래시 속도 | 존 아키텍처, 이더넷 프레임 터널링 |
ISO 11898-1:2024는 클래식·FD·XL 세 형식을 한 문서에서 정의한다. CAN FD의 핵심은 중재는 느린 속도로, 데이터는 빠른 속도로 보내는 비트레이트 전환(BRS)이다. 그래서 CAN FD 노드와 클래식 CAN 전용 노드가 같은 버스에 있으면 클래식 노드가 FD 프레임을 오류로 보고 오류 프레임을 낸다. 혼합 버스 구성은 시험 대상 이다.
DBC — 바이트를 물리값으로
CAN 프레임의 데이터는 그냥 바이트다. 어느 비트가 무슨 신호인지는 DBC 파일(Vector가 만든 사실상 표준 형식)이 정의한다.
BO_ 416 VehicleSpeed: 8 ESC
SG_ VehSpd : 0|16@1+ (0.01,0) [0|320] "km/h" Cluster,EMS
SG_ VehSpdValid : 16|1@1+ (1,0) [0|1] "" Cluster두 번째 줄을 읽으면 이렇다. 시작 비트 0, 길이 16비트, @1 은 인텔(리틀 엔디언) 바이트 순서, + 는 부호 없음, 스케일 0.01, 오프셋 0, 범위 0~320km/h. 물리값 = 원시값 × 스케일 + 오프셋이다.
DBC 기반 신호 검증의 전형적 결함과 시험은 이렇다.
| 결함 | 증상 | 시험 |
|---|---|---|
| 바이트 순서 불일치(인텔·모토로라) | 값이 엉뚱하게 크거나 저속에서만 맞음 | 0x00FF, 0xFF00처럼 한쪽 바이트만 채운 값을 송신 |
| 스케일·오프셋 불일치 | 모든 값이 일정 비율로 틀림 | 최소·중간·최대 세 점에서 물리값 비교 |
| 부호 처리 오류 | 음수가 큰 양수로 보임 | 음수 온도·역방향 토크 같은 경계 |
| 범위 밖 원시값 | 계기판에 650km/h 표시 | 범위 최대 +1 원시값, 0xFFFF 송신 |
| 무효값 규약 누락 | 센서 고장값(0xFFFF)을 정상값으로 처리 | 무효값·유효 비트 0 송신 시 대체 동작 확인 |
| DBC 버전 불일치 | 송신 ECU와 수신 ECU가 다른 DBC로 빌드 | DBC 해시·버전을 빌드 산출물과 대조 |
이것은 모듈 3 레슨 1의 경계값 분석을 신호마다 반복하는 일이다. 신호가 수백 개이므로 DBC를 읽어 케이스를 자동 생성 하는 스크립트가 실무 표준이다.
주기와 타임아웃 감시
대부분의 CAN 메시지는 주기적으로 보낸다(예: 차속 10ms, 도어 상태 100ms). 수신 ECU는 정해진 시간 동안 메시지가 오지 않으면 타임아웃 으로 판단하고 대체값이나 고장 처리로 넘어가야 한다.
아래 예시에 DTC 가 나온다. 장치가 고장을 감지했을 때 "무엇이 어떻게 잘못됐다" 를 정해진 번호로 남기는 고장 코드다. 정비소에서 진단기를 꽂으면 읽히는 그 코드이고, 이 모듈에서는 고장을 겪었다는 증거가 실제로 남는가 를 보는 시험 항목으로 쓴다.
요구: VehicleSpeed 주기 10ms ±10%, 수신 측은 5주기(50ms) 미수신 시 타임아웃 DTC 기록, 대체값 0 사용
시험 1 주기 측정: 1시간 기록, 최소·최대·표준편차 → 9~11ms 안인가
시험 2 49ms 끊김 → 타임아웃 없어야 함
시험 3 61ms 끊김 → 반드시 타임아웃 DTC, 대체값 사용
시험 4 메시지 재개 → 정상값 복귀, 복구 조건(몇 주기 연속 수신 후)이 요구대로인가경계를 49ms·61ms로 벌린 이유는 타이머 해상도다. 수신 쪽 타임아웃 검사가 10ms 태스크에서 돈다면 실제 판정 시점은 50~60ms 사이에서 흔들린다. 이 구간 안의 끊김은 판정이 매번 달라지므로, 요구가 이 흔들림을 허용하는지 먼저 확인하고 허용 폭 바깥에서 합격·불합격 경계를 잡는다.
오류 카운터와 버스 오프
CAN 컨트롤러는 TEC(송신 오류 카운터) 와 REC(수신 오류 카운터) 를 가진다. 오류가 나면 카운터가 오르고(송신 오류는 +8), 성공하면 내려간다(−1).
| 상태 | 조건 | 동작 |
|---|---|---|
| Error-active | TEC·REC 모두 127 이하 | 정상. 오류 발견 시 능동 오류 프레임 송신 |
| Error-passive | TEC 또는 REC가 128 이상 | 오류 신호를 약하게만 보내고, 송신 전 추가 대기 |
| Bus-off | TEC가 255를 초과 | 버스에서 완전히 이탈, 송신 불가 |
버스 오프는 고장 난 노드가 버스 전체를 망가뜨리지 않게 하는 장치다. 하지만 버스 오프 뒤 어떻게 돌아오는가 는 소프트웨어 설계에 달려 있다. 규격은 128번의 연속 11 recessive 비트를 확인한 뒤 복귀할 수 있게 하고, 그 뒤의 정책(즉시 재시도, 점진적 재시도 간격, 몇 번 이후 포기, DTC 기록)은 요구사항이 정한다.
버스 오프 복구 시험
1. 대상 ECU가 송신 중일 때 CAN_H와 CAN_L을 단락(또는 오류 주입 장비로 비트 파괴)
2. TEC 상승 기록 → 128에서 error-passive, 255 초과에서 bus-off 진입 확인
3. 단락 해제
4. 판정: 요구된 시간 안에 복귀하는가, 복귀 시도 간격이 요구대로인가,
버스 오프 DTC가 기록되는가, 복귀 뒤 신호가 정상인가
5. 단락을 해제하지 않은 상태로 지속 → 재시도가 버스를 계속 방해하지 않는가마지막 항목이 자주 빠진다. 고장 난 노드가 너무 빨리 재시도하면 버스 오프와 복귀를 반복하며 버스 전체를 괴롭힌다.
UDS — 진단 서비스
UDS(Unified Diagnostic Services, ISO 14229-1)는 정비 장비나 테스트 도구가 ECU에 요청하고 응답을 받는 진단 프로토콜이다. CAN 위에서는 ISO 15765-2(ISO-TP)가 긴 메시지를 여러 프레임으로 나눠 운반한다. 요청의 첫 바이트가 서비스 ID(SID)이고, 긍정 응답은 SID + 0x40이다.
| SID | 서비스 | 시험 포인트 |
|---|---|---|
| 0x10 | DiagnosticSessionControl | 기본(0x01)·프로그래밍(0x02)·확장(0x03) 세션 전환, 세션 타임아웃(S3) 후 기본 세션 복귀 |
| 0x11 | ECUReset | 하드·소프트 리셋 후 세션 초기화, 리셋 중 요청 처리 |
| 0x14 | ClearDiagnosticInformation | 전체·그룹 삭제, 삭제 후 고장이 지속되면 다시 기록되는가 |
| 0x19 | ReadDTCInformation | 상태 마스크별 조회, 스냅샷·확장 데이터, DTC 상태 비트 전이 |
| 0x22 | ReadDataByIdentifier | DID별 값·길이, 존재하지 않는 DID |
| 0x27 | SecurityAccess | 시드·키 교환, 잘못된 키 횟수 제한과 지연 타이머 |
| 0x2E | WriteDataByIdentifier | 세션·보안 조건, 쓰기 후 전원 차단 시 보존 |
부정 응답 코드
거부할 때는 7F SID NRC 형태로 응답한다. 부정 응답은 정상 동작의 절반 이므로 긍정 경로만큼 시험한다.
| NRC | 이름 | 유도하는 요청 |
|---|---|---|
| 0x11 | serviceNotSupported | 지원하지 않는 SID |
| 0x12 | subFunctionNotSupported | 없는 세션 번호 |
| 0x13 | incorrectMessageLengthOrInvalidFormat | 길이가 한 바이트 모자란 요청 |
| 0x22 | conditionsNotCorrect | 주행 중 프로그래밍 세션 요청 |
| 0x31 | requestOutOfRange | 존재하지 않는 DID |
| 0x33 | securityAccessDenied | 보안 해제 없이 0x2E 쓰기 |
| 0x35 | invalidKey | 틀린 키 |
| 0x36 | exceededNumberOfAttempts | 틀린 키 반복 |
| 0x37 | requiredTimeDelayNotExpired | 지연 시간 안에 재시도 |
| 0x78 | requestCorrectlyReceived-ResponsePending | 긴 처리(플래시 지우기) 중 응답 대기 |
| 0x7F | serviceNotSupportedInActiveSession | 기본 세션에서 확장 세션 전용 서비스 |
SecurityAccess는 보안 시험이기도 하다. 틀린 키 시도 횟수 제한, 지연 타이머가 리셋으로 우회되지 않는가, 시드가 매번 달라지는가(고정 시드는 재전송 공격에 취약)를 본다.
도구 예시
CANoe(Vector)는 시뮬레이션·자동 시험·진단을 한 도구에서 하는 업계 표준이고, BUSMASTER는 오픈소스 버스 분석 도구다. 스크립트 자동화에는 python-can이 흔하다.
import can
bus = can.interface.Bus(channel="can0", interface="socketcan")
msg = can.Message(arbitration_id=0x1A0, data=[0xFF, 0xFF, 0, 0, 0, 0, 0, 0],
is_extended_id=False)
bus.send(msg) # 원시값 0xFFFF → 무효값 처리 시험도구보다 중요한 것은 무엇을 판정하는가 다. 같은 시험을 어느 도구로 하든 기대 결과는 요구사항과 DBC, UDS 명세에서 온다.
실무에서 왜 필요한가
차량 한 대에 ECU가 수십 개이고, 각 ECU는 다른 협력사가 만든다. 통합 단계에서 드러나는 결함 상당수가 신호 정의 불일치와 통신 이상 처리 다. 한 ECU는 DBC 3.2로, 다른 ECU는 3.1로 빌드되어 있거나, 타임아웃 대체값이 서로 다르거나, 버스 오프 뒤 복귀가 너무 빨라 버스 전체를 흔드는 일이 실제로 일어난다. 진단 서비스는 정비소와 생산 라인에서 쓰이므로, 부정 응답 한 줄이 틀려도 정비 장비가 ECU를 인식하지 못하거나 생산 라인이 멈춘다. CAN과 UDS를 아는 테스터는 이런 결함을 ECU 단독 시험 단계에서 미리 잡는다.
채용시장에서의 위치
자동차 전장 검증 공고에서 CAN·CAN FD·UDS는 거의 필수 키워드이고, CANoe·CANalyzer 사용 경험이 우대 조건으로 자주 붙는다. 면접에서는 "중재가 어떻게 동작하나", "버스 오프 조건과 복구 시험을 어떻게 설계하나", "NRC 0x33과 0x7F의 차이는" 같은 질문이 나온다. 존 아키텍처가 확산되면서 CAN XL과 차량 이더넷을 함께 이해하는 인력 수요도 늘고 있다. 도구 사용법보다 DBC와 UDS 명세를 시험 케이스로 바꿔 본 경험 이 차별점이 된다.