UART, SPI, I2C Basic

Seungyun Lee·2025년 11월 22일

Comm_Accel(UART/SPI/I2C)

목록 보기
1/15
post-thumbnail

통신이란?

기본적으로 통신은 데이터를 주고받는 행위들을 의미한다.
그렇다면 어떻게 통신을 분류할 필요성이 있다. 통신을 분류하는 여러 기준점들이 있다.

  • 직렬/병렬
  • 단방향/양방향
  • 유선/무선
  • 동기식/비동기식
  • 베이스밴드/브로드밴드
  • 아날로그/ 디지털
  • 기저대역/대역통과
  • 선형/비선형

....
정말 다양한 기준을 통해서 통신을 나눌 수 있다. 본문에서는 이러한 모든 기준을 다루기 어렵기 때문에 제목처럼 해당 통신들을 분류할 수 있는 기준을 직렬 vs 병렬의 기준으로 분류하는 방식을 소개하려 한다.

직렬 VS 병렬

직렬 통신 : 데이터를 직렬의 데이터로 보내는 형태를 의미

병렬 통신 : 데이터를 병렬의 데이터로 보내는 형태를 의미

병렬의 데이터의 경우 서로 다른 선을 통해 데이터를 보내기 때문에 타이밍의 문제가 생길 수 있으며, 선과 포트가 많아 짐에 따라 비용이 당연히 더 비싸질 수밖에 없다. 쉽게 말해서 비용은 높아지고 신뢰성을 직렬보다는 낮아지게 된다. 그렇다면 우리는 이러한 통신 방법을 적절하게 활용할 줄 알아야 한다.

만약 내가 구성하고 있는 통신의 형태에 따라서 각 통신의 단점을 커버할 수 있는 방식을 활용해야 한다. 쉽게 말해서 비용이 충분하고 통신의 거리가 짧다면 병렬 통신이 당연히 좋은 선택지가 될 수 있다.

그러나 통신의 거리가 멀어지고 정확성을 요구하는 통신의 경우 직렬 통신이 올바른 선택일 수 있다. 이렇게 우리는 어떤 통신이 우리에게 필요한지 고심을 해야 한다. (물론 현 트렌드는 직렬 통신을 주로 많이 활용하고 있다.)

사전지식

1) 직렬 통신의 데이터 전송

직렬 통신은 기본적을 1바이트 데이터를 6개의 비트로 쪼개 한번에 1BIT씩 통신 선로를 통해 전송을 하는 방식이다. 이때 8개의 비트 범위를 식별하기 위해서 Start, End Bit를 추가해 총 10Bit의 데이터를 송수신하게 된다. (물론 이런, Start, End Bit를 활용하지 않고 패리티 비트를 활용해 데이터의 범위를 식별하는 방식도 있다.)

2) Baud Rate - BPS

Baoud Rate는 사실상 보내는 데이터의 속도를 의미한다고 생각하면 된다. 이때, 수신 측과 송신 측의 Baud Rate를 일치시켜에 데이터의 혼동이 없어진다. (쉽게 이해해 보면, 보내는 속도와 읽는 속도가 다르다면, 데이터가 엉켜질 수 있다는 의미다.)

3) 동기 통신 vs 비동기 통신

통신에서의 동기/비동기는 clk의 유무로 판단한다. 동기의 경우 clk신호를 활용하고 비동기의 경우 clk신호를 활용하지 않는다는 점에서 있다. 직렬 통신에서는 CLK 신호를 통해서 데이터의 범위를 시별 할 수도 있다.

비동기 통신은 동기를 맞추기 위한 별도의 Clock 신호 없이 데이터를 주고 받는 방법이다. Clock 신호가 없기 때문에 송신자는 한 바이트의 데이터를 전송하기 직전에 통신의 시작을 알리는 시작 비트 (start bit)를 먼저 보내 데이터의 전송이 시작된다는 것을 수신자에게 알린다. 시작 비트를 보낸 다음부터 데이터를 한 비트씩 보내고 마지막에는 통신의 끝을 알리는 정지 비트 (stop bit)를 보내 통신이 끝났음을 알린다. 시작 비트는 논리 ‘0’이며 정지 비트는 논리 ‘1’이다.

통신의 시작을 뜻하는 시작 비트를 받으면 수신자는 이 때부터 미리 약속한 통신 속도에 맞추어 데이터를 한 비트씩 읽어 들이기 때문이다. 직렬 통신에서의 통신 속도는 보통 bps (bits per second)라는 단위로 표현하는데 이 단위는 초당 전송되는 비트 수를 나타낸다. 몇 bps의 속도로 통신할 것인가가 정해지면 한 비트의 시간 폭이 결정된다. 통신 속도를 알고 있어야만 시작 비트를 받은 수신자가 그 이후 데이터를 한 비트씩 읽어 들이는 속도를 결정할 수 있다. PC의 직렬 포트에 사용되는 RS-232 표준은 비동기 통신 프로토콜의 대표적인 예다.

4) RS-232 / RS-422 / RS-485

기본적으로 직렬 비동기식 통신을 UART 통신이라고 부른다. 이때 UART에서 나오는 신호는 보팅 TTL 신호 레벨을 갖기 때문에 노이즈에 약하고, 통신거리에 제약이 있다. 따라서 이러한 TTL 신호를 입력받아 노이즈에 강하고 통신거리를 길게 해 주기 위해 인터페이스 IC를 호 라용 하는데 이런 대표적인 예시가 RS-232, RS-433, RS-485라고 이해하자.

Bit Rate(BPS) and Baud Rate

Bit Rate = BPS (Bit Per Second)

  • 초당 얼마나 많은 데이터 비트 ( 0 or 1)를 전송할 수 있는지 표시 (비트 전송 속도를 의미)
    ex) 3000 bps = 3000 bit / second  = 1초 당 3000 개의 비트를 보낸다는 말.

Baud Rate (보레이트 / 비동기 통신에서 많이 사용됨 )

  • 초당 얼마나 많은 심볼을 전송할 수 있는지 표시 ( 심볼 전송 속도를 의미)
  • 심볼( Symbol ) : 물리적인 단위, 하나 이상의 비트( bit )를 포함 ( 2개 이상의  bit로 존재할 수 있다.) 
    ex) 1000 baud rate = 1초에  1000개의 심볼을 보낸다는 말.
    1초 1/1000 = 심볼의 1개당 1ms
    1초 10 / 1000 = 심볼의 1개당 10ms

UART

Universal Asynchronous Receiver/Transmitter
UART는 비동기 통신에 필요한 이런 직렬-병렬 데이터 변환 작업을 자동으로 해주는 하드웨어 장치이다. 그렇기 때문에 비동기 통신을 해야 한다면 UART가 꼭 필요하다고 할 수 있다. PC에는 16550이라는 이름의 UART IC가 사용되는데 이처럼 UART가 독립된 제품으로 판매되기도 하지만 거의 대부분의 마이크로컨트롤러는 내부에 하나 이상의 UART를 가지고 있다. CPU는 UART 레지스터에 값을 쓰거나 레지스터 값을 읽는 방법으로 간단하게 비동기 통신을 진행할 수 있다.

신호선

TX : 내가 보내는 데이터
RX : 상대가 보내는 데이터

핵심 개념

UART는 비동기(Asynchronous) 방식
→ 즉, 시계(clock)를 공유하지 않음
→ 대신 Start bit / Stop bit로 프레임 경계를 맞춤.

UART 데이터 프레임 구조

[Start Bit][Data 8비트][Parity(optional)][Stop Bit 1~2]

예시: 8-N-1
8 data bits
No parity (오류발생 여부를 검사하기 위해 추가하는 비트)
1 stop bit

동작 과정

TX 라인은 평상시에 High(1)
데이터 보낼 때 Low(0) → Start bit
LSB부터 8비트 전송
패리티 비트가 있으면 계산 후 전송
Stop bit로 1을 내보내며 프레임 종료
수신기 측은 Start bit Falling Edge를 감지해서
자기 클럭으로 샘플링해 비트를 읽어.

FPGA 설계 포인트

정확한 baud rate generator 필요 (ex: 115200bps)
Oversampling (보통 8x 또는 16x)으로 Start bit 안정 검출
RX는 노이즈 때문에 mid-bit sampling 필요
TX/RX FIFO 넣으면 안정적

장점

  • 구조가 단순해 설계가 매우 쉽다
  • 클럭 공유 필요 없음
  • 긴 거리 통신에 강함

단점

  • 속도가 느림 (최대 1~2Mbps 정도)
  • framing 오버헤드가 많음
  • 다중 Slave 연결 불가

I2C

I2C의 경우 UART와는 다르게 동기식 직렬 통신 방법이다. 이때 데이터를 전송하는 선 이외에 CLK신호를 주는 선이 따로 존재하며 데이터를 전송하는 선이 1개이기에 한 번에 송수신을 동시에 진행하지 못한다. UART와 다르게 하나의 하드웨어(Master)와 여러 하드웨어(Slave)에 연결할 수 있으며, 이때도 데이터를 전달하는 선은 1개뿐이라 여러 개와 연결되어 있어도 통신은 하나씩 해결해야 한다.

I2C (Inter-Integrated Circuit) 버스는 마이크로프로세서와 저속 주변 장치 사이의 통신을 위한 용도로 Philips에서 개발한 규격인데 두 가닥의 선을 사용하므로 TWI (Two Wire Interface)라고도 불리고 있다.
I2C 버스는 양방향 오픈 드레인 선인 SCL (serial clock)과 SDA (serial data)로 이루어져 있으며 Master-Slave 형태로 동작한다. SCL은 통신의 동기를 위한 Clock용 선이고 SDA는 데이터용 선이다. Master는 SCL로 동기를 위한 Clock을 출력하며 Slave는 SCL로 출력되는 Clock에 맞추어 SDA를 통해 데이터를 출력하거나 입력 받는다. 단지 SDA 한 선으로만 데이터를 주고 받기 때문에 I2C 버스는 반이중 (half duplex) 통신만 가능하다. SCL 선과 SDA 선은 모두 오픈 드레인므로 두 선에는 각각 풀업 저항을 연결해 주어야 한다.

신호선

SCL : 클럭
SDA : 데이터
두 선만 사용 → 매우 간단.

핵심 개념

I2C는 동기식 + 멀티-마스터 지원 + open-drain 방식 통신이야.

Open-drain이란?

High(1)을 직접 출력하지 않고
Low(0)만 직접 만든다
High는 풀업 저항으로 올라감
→ 그래서 Bus에 여러 장치가 붙어도 충돌이 없음

I2C 데이터 프레임

[Start]
[Slave Address 7bit] [R/W bit]
[ACK]
[Data 8bit]
[ACK]
...
[Stop]

ACK: Acknowledgement
NACK: Negative Acknowledgement
ACK는 데이터 수신측에서 패킷을 올바르게 받았다는 뜻으로,
다음으로 필요한 패킷의 번호(받은 패킷 번호 + 1)와 함께 보내진다.
NAK는 받은 패킷에 오류가 있다거나 잘못된 순서로 받았다는 뜻으로,
문제가 있는 패킷의 번호와 함께 보내진다.
Slave 또는 Master가 한 비트를 Low로 당겨서 ACK 표시.

특별한 기능

여러 Slave 연결 가능 (7bit 주소 → 128개)
여러 Master도 가능
버스에 느린 Slave가 있으면 Clock Stretching 가능
→ Slave가 SCL을 Low로 잡고 “잠깐만!” 하는 것

FPGA 설계 포인트

Open-drain 출력 구현 (FPGA에서는 tri-state로 구현)
Start/Stop condition 생성 정확히
Start: SDA 1→0, SCL=1
Stop: SDA 0→1, SCL=1
ACK 처리
SCL clock divider 구현
Slave 주소 디코딩
I2C는 구조가 단순해 보이지만
실제 구현은 UART/SPI보다 더 복잡함.

장점

선 2개로 여러 장치 연결 가능
주소 기반 통신
배선이 가장 단순

단점

속도 느림 (100kHz~400kHz, Fast Mode 1MHz 정도)
프로토콜 복잡, 엣지 조건 까다로움
Open-drain이라 노이즈에 약한 편


SPI

Serial Peripheral Interface
SPI의 경우 I2C의 업그레이드 버전이라고 생각하면 편하다. I2C의 경우 데이터 선이 하나뿐이었다면, SPI는 송신(MOSI), 수신(MISO) 2가지의 데이터 통신 선을 가지고 있다. 따라서 송신을 하면서 받을 수 있다. 그러나 I2C와의 차이점이라면 여러 개의 Master를 가질 수 없다는 점이다.

신호선

SCLK : 마스터가 제공하는 클럭
MOSI : Master Out Slave In
MISO : Master In Slave Out
SS(n) : Slave Select (Chip Select=cs_n),

  • cs_n = 0 -> 슬레이브 선택
  • cs_n = 1 -> 슬레이브 선택해제

총 4선(마스터 기준)
Slave 여러 개면 SS만 여러 개 필요.

핵심 개념

SPI는 동기식(Synchronous) 통신
→ 마스터가 SCLK를 만들고
→ 양쪽은 SCLK 엣지에서 MOSI/MISO를 읽거나 써.

동작 구조

마스터가 SS = Low 로 구동
SCLK을 발생
각 엣지에서 MOSI, MISO로 비트 교환(Full-Duplex 가능)
끝나면 SS High

SPI 모드 (0~3)

어느 에지에서 보낼지, 어느 에지에서 받을지, 그리고 SCLK가 idle일 땐 0인지 1인지
이게 디바이스마다 다를 수 있어서,그걸 통일하기 위해 만든 게 CPOL, CPHA
CPOL: “클럭이 쉴 때 0이냐 1이냐”
CPHA: “첫 번째 에지에서 데이터를 볼 거냐, 두 번째 에지에서 볼 거냐”

CPOL (Clock Polarity) – SCLK의 “기본 레벨”

CPOL = SCLK의 idle 레벨

  • CPOL = 0 → SCLK가 기본적으로 0 (Low)
  • CPOL = 1 → SCLK가 기본적으로 1 (High)
    cs_n이 1일 때(슬레이브 선택 안 된 상태) 또는 데이터가 없어서 쉬고 있을 때
    SCLK 라인을 어디에 두느냐를 정하는 거야.

CPOL = 0 (Mode 0 또는 1)

SCLK:  ──────┐    ┌─────┐    ┌─────┐────
             └────┘     └────┘     └──  (idle=0)

CPOL = 1

SCLK:  ─────┐     ┌────┐     ┌────┐─────
           └──────┘    └──────┘          (idle=1)

CPHA (Clock Phase) – “첫 에지에서 할 일”

CPHA는 “첫 번째 유효 클럭 에지에서 데이터를 볼 건지, 보낼 건지” 를 정해.
여기서 말하는 “첫 번째 에지”:

  • cs_n이 0으로 내려간 이후,
  • idle 레벨에서 벗어나는 첫 번째 에지 (leading edge)

CPHA = 0

  • 첫 번째 에지에서 샘플 (데이터를 “읽는다”)
  • 두 번째 에지에서 데이터 변경 (shift)

CPHA = 1

  • 첫 번째 에지에서 데이터 변경 (shift)
  • 두 번째 에지에서 샘플

이렇게 “첫 에지 vs 두 번째 에지 중 어디에서 샘플링할지” 를 정하는 비트라고 보면 됨.

ModeCPOLCPHAIdle샘플링(edge)데이터 변경(edge)
000Lowrisingfalling
101Lowfallingrising
210Highfallingrising
311Highrisingfalling
  • CPOL = 0 → idle = Low, 유효한 클럭은 High 쪽으로 갈 때
  • CPOL = 1 → idle = High, 유효한 클럭은 Low 쪽으로 갈 때
  • CPHA = 0 → 첫 번째 에지에서 sample(Read)
  • CPHA = 1 → 두 번째 에지에서 sample(Read)

타이밍 예시 (Mode 3 = CPOL=1, CPHA=1)

  • idle: SCLK = 1
  • leading edge: falling (1 → 0)
  • trailing edge: rising (0 → 1)

Mode 3에선:
데이터 변화(shift)는 falling에서
샘플링은 rising에서 한다 (CPHA=1이니까 “두 번째” 에지에서 sample)

SCLK:   -^-_-^-_-^-_-^-
        ↑   ↑   ↑
        |   |   └─ rising edge (sample)
        |   └──── falling edge (shift)
        └ idle=1

Master와 Slave는 반드시 같은 (CPOL, CPHA) 설정을 써야 한다.

  • Master: Mode 0, Slave: Mode 3 → 통신 깨짐
  • 그래서 데이터시트에 보통 “SPI Mode 0” 또는 “CPOL=0, CPHA=1” 이런 식으로 명시해 줌.

FPGA 설계 포인트

CLK divider로 SCLK 생성
Shift register로 MOSI/MISO 구현
SS (Chip Select) 타이밍 정확히
CPOL, CPHA 모드 구현 가능하게 설계

장점

아주 빠름 (수 MHz~수십 MHz, FPGA는 100MHz 이상도 가능)
Full-duplex 가능
프로토콜 단순

단점

선이 많음
다중 슬레이브 연결 시 SS 핀이 많이 필요
거리 길어지면 노이즈 취약

profile
Design Verification engineer

0개의 댓글