센서는 멀쩡한데 보드가 못 알아듣는다 · 클럭 없는 직렬 — UART · 이론
글자는 오는데 읽을 수가 없다
한 줄 요약
UART 에는 클럭 선이 없습니다. 그래서 양쪽이 같은 비트 시간을 믿고 있어야 하고, 그 믿음이 깨지면 프레임 뒤쪽부터 무너집니다.
왜 이게 필요했나
센서 하나가 3초마다 한 줄씩 측정값을 보냅니다. 터미널에는 알아볼 수 없는 글자가 찍히는데, 길이는 맞고 줄바꿈도 제때 옵니다. 센서를 바꿔도 같고 케이블을 바꿔도 같습니다. 이런 모양은 거의 언제나 속도의 문제입니다. 배선이 끊겼으면 아무것도 안 오고, 잡음이면 가끔 깨지지, 매번 같은 자리에서 같은 식으로 깨지지는 않습니다.
UART 가 이런 고장에 취약한 이유는 설계가 그렇게 돼 있기 때문입니다. 선이 하나뿐이라 "지금이 비트 경계" 라고 알려 줄 방법이 없습니다. 보내는 쪽은 자기 시계로 비트를 늘어놓고, 받는 쪽은 자기 시계로 자릅니다. 두 시계가 같다는 보장은 어디에도 없습니다. 있는 것은 프레임마다 한 번씩 위치를 맞출 기회, 시작 비트뿐입니다.
어떻게 동작하나
쉬고 있을 때 선은 높습니다. 보낼 것이 생기면 한 비트 시간 동안 낮추는데, 이것이 시작 비트입니다. 받는 쪽은 이 하강 모서리를 보고 시계를 맞춥니다. 이어서 데이터 비트가 낮은 자리부터 나오고, 설정에 따라 패리티 비트가 하나 붙고, 마지막에 한 비트 이상 높은 정지 비트로 끝납니다. 8N1 이라고 부르는 설정은 데이터 8비트, 패리티 없음, 정지 1비트를 뜻합니다.
받는 쪽이 하는 일은 단순합니다. 시작 모서리에서 (k + 0.5) 비트 시간 떨어진 곳을 k번 비트로 읽습니다. 비트 칸 한가운데를 고르는 이유는 모서리에서 가장 멀기 때문입니다.
시작 d0 d1 d2 d3 d4 d5 d6 d7 정지 ────┐ ┌─────┐ ┌─────────────────┐ ┌──────── └─────┘ └───────────┘ └─────┘ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 표본은 언제나 칸의 한가운데이 구조가 오차 예산을 정합니다. 8N1 에서 마지막으로 읽는 자리는 정지 비트, 곧 시작 모서리에서 9.5 비트 시간 떨어진 곳입니다. 여기서 칸을 벗어나지 않으려면 누적 오차가 0.5 비트 안에 있어야 하므로, 두 시계가 허용하는 차이는 0.5 ÷ 9.5, 약 5.3 % 입니다. 이 숫자는 규격에서 옮겨 적은 것이 아니라 프레임 구조에서 바로 나옵니다. 그래서 어긋남은 프레임 앞쪽이 아니라 뒤쪽부터 드러납니다. 앞 비트는 아직 여유가 남아 있으니까요.
임베디드에서 이 오차가 생기는 가장 흔한 경로는 잡음이 아니라 분주비입니다. 펌웨어가 12 MHz 를 가정하고 분주비를 잡았는데 보드에 올라간 수정 진동자가 11.0592 MHz 라면, 같은 분주비로 나오는 보율은 9600 × 11.0592 ÷ 12 = 8847.36 Bd 입니다. 8 % 를 넘으므로 위의 예산을 벗어납니다. 이 코스의 포착 파일이 정확히 그 상황이고, 파형에서는 비트 경계가 프레임 안에서 점점 밀리는 모양으로 나타납니다.
여기서 두 가지 안전장치가 등장합니다. 프레이밍 오류는 정지 비트 자리가 낮게 읽혔다는 뜻입니다. 속도가 어긋나면 마지막 자리가 가장 먼저 틀어지므로 잘 걸립니다. 패리티는 1의 개수를 홀수 또는 짝수로 맞춰 두는 방법이라, 비트가 홀수 개 뒤집혔을 때만 걸립니다. 짝수 개가 뒤집히면 그대로 통과합니다. sigrok 의 UART 해독기 문서도 이 둘을 각각 parity error 와 frame error 로 구분해 다룹니다([문서](https://sigrok.org/wiki/Protocol_decoder:Uart)).
고치는 쪽은 의외로 쉽습니다. 포착 파일 안에 답이 있습니다. 프레임을 쉬지 않고 이어 보냈다면 모든 모서리가 같은 비트 격자 위에 있으므로, 어느 두 모서리 사이든 정수 개의 비트 시간입니다. 가장 짧은 간격으로 거친 값을 잡고, 기준선을 늘려 가며 그 정수를 다시 반올림하면 정밀도가 올라갑니다. 한 번에 전체 길이로 하면 안 됩니다 — 거친 값의 오차에 비트 개수를 곱한 값이 0.5비트를 넘는 순간 반올림이 엉뚱한 정수를 고릅니다.
현장에서 만나는 모습
"글자가 깨진다" 는 신고를 받으면 먼저 묻습니다. 매번 같은 자리가 깨지는가, 아니면 무작위인가. 같은 자리라면 속도이고 무작위라면 전기적인 문제입니다. 그리고 프레이밍 오류 카운터가 올라가는지 봅니다. 올라가면 타이밍, 안 올라가는데 값이 이상하면 더 나쁜 쪽입니다 — 검출되지 않은 손상입니다.
패리티를 켜 두고 "이제 안전하다" 고 말하는 설계 문서를 종종 봅니다. 이 코스의 8E1 포착에서 11개 프레임 중 10개가 틀렸는데 패리티와 프레이밍이 잡아낸 것은 8개였습니다. 3개는 아무 표시 없이 틀린 값으로 통과했습니다. 패리티는 "문제가 있다" 는 신호이지 "문제가 없다" 는 보증이 아닙니다.
다음 실습에서 할 것
포착 파일 세 편을 받습니다. 정상 한 편, 클럭이 어긋난 것 두 편입니다. 임계값 함수와 프레임 해독기를 직접 쓰고, 표본을 솎아 가며 판독이 무너지는 지점을 찾고, 어긋난 포착에서 실제 비트 시간을 되재어 읽히는 문장을 되살립니다. 마지막에는 패리티가 무엇을 잡고 무엇을 놓쳤는지 숫자로 셉니다.