[Embedded] Communication Protocol (1)
웹은 HTTP 기반으로 통신한다.
HTTP 만 쓰는건 아니긴 함. HTTP 위에 Websocket도 올려서 쓰고.. gRPC 쓰기도 하고.. Thrift 쓰기도 하고..
다만 웹에서의 웬만한 통신 프로토콜은 모두 HTTP 기반임.
웹은 물리 계층이 추상화되어 모든 웹 통신은 결국 TCP/IP -> 이더넷/Wi-Fi 패킷으로 내려간다.
그리고 물리적 전송은 OS및 NIC 드라이버가 알아서 처리해줌. 그러니 개발자는 HTTP 위에서 뭘 할지만 고민하면 됨.
임베디드는 물리 계층을 직접 다루니 웹에서의 통신과는 좀 다름.
같은 PCB 보드 위 칩 간 통신은 SPI
PC와 보드 사이 케이블은 UART
핀이 부족하니 절약해야 한다. 센서를 여러 개 묶는건 I2C
자동차 전체는 차동 신호가 필요하니 CAN
등등...
임베디드 통신 프로토콜은 하드웨어 스펙이 곧 프로토콜이 된다.
몇 V를 1로 정의할 지 부터가 프로토콜의 일부.
칩 A와 B가 서로 통신한다는 건, 칩 사이에 전선을 깔고 0과 1을 흘려보내는 것.
그러니 칩 설계자는 세 가지를 결정해야 한다.
1. 전선을 어떻게 사용할지? (Duplex)
전선은 쓰임이 명확해야 한다. 보내기만 하거나 받기만 하거나 둘 다하거나..
보내는 선과 받는 선을 따로 사용해도 좋지만, 하나로만 사용하려면 순서를 꼭 지켜야 함.
UART는 Tx/Rx 를 두 개 사용한다. (Full Duplex)
I2C는 SDA 한 개를 사용한다. (Half Duplex)
2. 0/1 전압의 타이밍을 어떻게 맞출지?
전선에 전압이 흐른다고 하자. 그리고 송신측이 전압을 보낸다.
수신측은 매 칸이 1비트라고 알아야 해독할 수 있고, 칸에 대한 정의도 필요하다. (bit time = 1/baud rate)
박자 신호선을 따로 깔아서 이 선이 High가 될 때 마다 비트 하나를 읽으라고 할 수 있고, (SPI I2C)
박자선 없이 1초에 n비트로 보낸다고 약속할 수도 있다. (UART)
3. 칩이 여러 개면 누구에게 보내야 할지?
칩 A가 B C D 세 개의 칩과 통신해야 할 때, B C D는 따로 전선을 깔아야 한다.
이러면 A는 누구에게 보낼지 알기 쉽지만, 전선이 3배로 늘어난다. (UART)
B C D 모두 같은 전선에 매달고 특정 신호로 어떤 칩을 호출할 지 정하는 것도 가능하다. (I2C)
앞에서 간단히 봤듯.. UART는 Clock Line 없이 baud rate를 약속하고 Start bit 동기화 + 오버샘플링을 활용해 비동기 통신을 구현하는 가장 오래된 직렬 통신 프로토콜이다.
PC COM 포트 (RS-232) 에 정말 많이 사용됨.
USB에 밀려서 PC (Personal Computer) 에서는 안쓰지만 임베디드에서는 표준으로 사용된다.
전선을 두개만 깔아도 되니 단순하고, 등장한지 굉장히 오래된 프로토콜이니 레퍼런스도 많음.

baud rate가 9600 일 때, 1비트를 전송하는데 104µs 정도가 걸린다.
"P"는 0x50이니 1040µs 이니 1ms정도가 걸림.
1960년대에 도입된 프로토콜이다 보니 그 당시 시프트 레지스터에서 가장 쉽게 뽑을 수 있는 레지스터인 LSB 부터 사용한다.
Start bit는 low이고 Stop bit는 high이다.
시작을 알아채고 다음 Start bit가 low로 떨어지는걸 감지하기 위해서..
일단 두 칩의 baud rate가 9600bps라고 약속하더라도, 양쪽의 시계가 정확하게 같지 않다.
각 칩은 오실레이터로 시간을 측정하지만 이것도 미세하게 다름. 이 오차는 시간이 흐를수록 누적된다.
한 비트가 104µs니까 비트의 중앙에서 읽는게 가장 안전하다.
가운데를 정확하게 타게팅하기 위해 오버샘플링을 활용함.
수신측은 클럭을 baud rate의 16배로 돌린다. 16배 확대해서 보면 정확하게 찍을 수 있음.
보드 안에서 칩 두 개가 1cm 거리로 통신할 때, 케이블이 짧으면 외부 노이즈가 거의 없으니 작은 전압으로도 구분된다.
다만 보드와 PC가 5m 케이블로 통신할 때는 형광등, 모터, 인터넷이 케이블에 노이즈를 유도시키니 데이터가 깨질 수 있음.
노이즈는 일정한 크기로 들어오고, 신호의 전압 폭이 노이즈보다 훨씬 크면 노이즈가 무력해진다.
그러니 전압 폭을 더 넓게 가져가면 해결할 수 있음.
RS-232 표준은 -12V ~ +12V 큰 전압 폭을 사용한다.
RS-232 : 외부 통신 표준
UART : 칩 내부의 비동기 통신 모듈
USART : UART + 동기 모드
UART는 모듈이고 RS-232가 프로토콜이다. 둘이 합쳐져야 PC와 통신할 수 있음.
지금까지는 UART를 살펴봤고 이제 SPI를 살펴보자.
SPI는 Clock Line 하나를 더 쓰는 대신, UART의 여러 트릭을 사용하지 않는다.
단순한 동기 통신 방식을 사용함.
둘 다 같은 문제를 해결하려고 했음. 비트 타이밍을 어떻게 맞춰야 할 지?
UART는 Clock Line이 없으니 baud rate, Start bit, 오버샘플링 등 여러 트릭이 필요했던거고
SPI는 Clock Line 하나 쓰는식으로 해결함.
양쪽 시프트 레지스터가 동시에 한 비트씩 자리를 바꾼다고 생각하면 됨.
SCK : 마스터가 만드는 Clock
MOSI : Master Out, Slave In (마스터가 보내는 데이터)
MISO : Master In, Slave Out (마스터가 받는 데이터)
CS : 슬레이브의 선택 (low로 떨굼)

매 클럭마다 반드시 양방향으로 1비트씩 교환해야 하고, 마스터가 뭐라도 보내야 클럭이 발생한다.
클럭은 마스타만 생성하고 슬레이브에게 공급할 수 있다. 슬레이브는 로그 박자에 맞춰서 Shift만 수행함.
마스터가 SCK를 Toggle하는 속도가 곧 통신 속도임. 미리 약속해야 하는 baud rate가 없다.
마스터는 슬레이브를 여러 개 가질 수 있고, 그 중 누구를 깨울지는 CS 핀을 low로 떨어뜨리는 방식으로 선택한다.
슬레이브가 N개 있으면 CS Pin도 N개 필요함. Pin이 부족하다는게 문제..
I2C는 SPI의 Pin 비용을 해결하기 위해 도입됐다.
마스터가 선택하는 슬레이브를 물리 Pin에서 논리 주소로 옮기고, Data Line을 공유하는 트릭으로 핀을 2개로 줄인다.
SPI 에서는 슬레이브 N개를 붙이려면 핀이 3 + N 개 필요하다.
슬레이브마다 CS 핀이 필요했고, CS 대신 7-bit 주소를 붙여주는 방식으로 해결함.
MOSI + MISO 두 개의 데이터선은 SDA 선 하나를 양방향으로 공유하도록 설정한다.

모든 칩은 같은 2개의 선에 매달려있다.
Open-drain + Pull-up 으로 여러 칩이 한 개의 Line을 공유한다.
I2C는 각 칩의 출력을 low만 만들 수 있는 회로로 설계한다. high를 못 만드는 대신 Pull-up 저항을 사용함.
라인에 항상 약하게 high를 끌어올리고 있고, 아무도 안 건드리면 기본적으로 high를 유지하는 방식임.

평상시에는 클럭이 high 인 동안 데이터는 안정되어있음. 그러니 비정상 패턴 자체를 신호로 활용한다.
즉, SCL high 동안 SDA가 바뀌면 데이터가 아니라는걸 인지하고 특별 처리에 들어감.
송신자가 8비트를 보내고 9번째 클럭에 송신자는 SDA에서 떠난다. high 상태를 유지해야 하니까.
수신자가 SDA를 low로 끌어내리고 ACK 요청을 받음. 여기서 SDA가 그대로 high라면 NACK.
Line은 Capacitor 성질이 있어 케이블이 길고 칩이 많이 매달릴수록 채워야 할 양이 커진다.
Pull-up은 저항이니 약하게 채워 라인이 high이 도달하기까지 시간이 오래 걸린다.
빠르게 하려면 라인을 짧게 하거나.. 칩을 적게 하거나인데.. 이건 힘들고
Pull-up을 강하게 해야 함 근데 이것도 힘들다. 어느정도 타협해야 함.
그러니 사실상 100Kbps는 Pull-up에서 가장 안정적인 속도이다.
CAN 은 자동차 환경에서 사용하기 위해 만들어진 프로토콜으로, 앞의 UART SPI I2C와는 설계 철학이 완전히 다르다.
자동차 환경에서는 EMI + ECU + 안전 이 세 가지가 정말 중요하다.
ECU : Electronic Control Unit으로 엔진, 변속기, 브레이크, 에어백, 에어컨 등등
EMI : Electro Magnetic Interference로 전자기 간섭을 의미함
그러니 마스터를 없애고 모든 노드를 동등하게, 그리고 broadcast 통신도 환경에 Fit하게 설계한 통신이 필요함.

일반적인 통신은 전선 1개 + GND로 전압 차이를 확인하지만, CAN은 신호선 2개의 전압 차이를 확인한다.
노이즈는 두 라인에 함께 적용되고, 두 라인이 같은 케이블에 꼬여있으니 외부 EMI는 둘 다 똑같이 끌어올리거나 내려감.
일반 통신은 GND(0V) 대비 전선의 전압으로 0/1을 판단하지만, 외부 노이즈가 끼면 전선의 전압이 흔들린다.
그러니 CAN에서는 GND말고 다른걸 기준선으로 사용함. CANH과 CANL 두 신호선의 상대적 차이를 기준으로 판단한다.
Recessive : 논리 1으로 아무도 건드리지 않은 상태
Dominant : 논리 0으로 누군가 건드린 상태
I2C의 Open-Drain과 유사한 매커니즘으로 동작한다. 하나라도 Dominant를 보내면 해당 라인은 0이 됨.
이 매커니즘덕분에 마스터 없이 통신할 수 있음.
Recessive / Dominant를 충돌 해결에도 사용한다.
모든 노드가 동시에 메세지를 던지면 충돌이 발생하는데, 이더넷에서는 CSMA/CD로 다시 시작하지만 CAN에서는 충돌이 발생하더라도 한 쪽은 그대로 완주하고 다른 쪽만 양보하는 방식을 사용함.
CAN 노드는 자기가 보낸 비트와 실제 라인 상태를 비교한다. 비트 1을 보낸 노드가 라인이 0이면 지고, 비트 0을 보낸 노드가 라인이 0이면 그대로 간다.
즉, 0을 일찍 보내는 노드가 이기는 셈. 그러니 ID가 낮을수록 우선순위가 높음.

CAN의 데이터프레임은 위와 같음.
최대 8바이트이고, CRC 에러 검출으로 깨진 경우 자동으로 재전송한다. 작은 데이터를 자주 보냄.
외부 Transceiver 칩으로 TTL과 차동 간 변환을 수행한다.
CAN은 칩 간 통신이 아니라 시스템 간 통신...
'Computer Science > Embedded Software' 카테고리의 다른 글
| [Embedded] Sensor (0) | 2026.05.13 |
|---|---|
| [Embedded] Communication Programming (0) | 2026.05.12 |
| [Embedded] ARM Assembly (0) | 2026.05.10 |
| [Embedded] General Purpose Input Output (0) | 2026.04.30 |
| [Embedded] Interrupt (0) | 2026.03.31 |
댓글
이 글 공유하기
다른 글
-
[Embedded] Sensor
[Embedded] Sensor
2026.05.13 -
[Embedded] Communication Programming
[Embedded] Communication Programming
2026.05.12 -
[Embedded] ARM Assembly
[Embedded] ARM Assembly
2026.05.10 -
[Embedded] General Purpose Input Output
[Embedded] General Purpose Input Output
2026.04.30