기술 가이드

SPI 모드 0·1·2·3 구분: CPOL·CPHA와 샘플 에지 검증

SPI 타이밍 그림에서 유휴 클록과 샘플 에지를 읽고 네 모드를 C 예제로 검증합니다.

목차

SPI 통신에서 값이 한 비트 밀리거나 모두 0x00으로 읽히면 클록 속도를 낮추기 전에 CPOL과 CPHA를 먼저 확인해 보세요. 센서 데이터시트의 타이밍 그림은 흔히 “mode 1” 대신 유휴 클록 레벨과 샘플링 에지로 조건을 표시합니다. Linux 커널의 SPI 개요와 Raspberry Pi Pico SDK의 SPI 헤더를 기준으로 네 가지 모드를 읽는 방법을 정리합니다.

1. 그림에서 모드 읽기

CPOL은 칩 선택(CS)이 활성화되기 전 SCK의 유휴 레벨입니다. CPOL=0이면 LOW에서 시작해 첫 에지가 상승, CPOL=1이면 HIGH에서 시작해 첫 에지가 하강입니다. CPHA는 데이터를 샘플링하는 에지입니다. CPHA=0은 첫 에지, CPHA=1은 두 번째 에지에서 샘플링합니다. 모드 번호는 2 × CPOL + CPHA로 구합니다.

모드 CPOL CPHA 유휴 SCK 첫 에지 샘플 에지
0 0 0 LOW 상승 상승
1 0 1 LOW 상승 하강
2 1 0 HIGH 하강 하강
3 1 1 HIGH 하강 상승

예를 들어 타이밍 그림에서 SCK가 LOW로 쉬고 두 번째 에지에서 데이터를 읽는다면 CPOL=0, CPHA=1, 즉 모드 1입니다. 이때 송신 쪽은 샘플 에지보다 앞서 데이터가 안정되도록 바꾸어야 합니다. 모드 0과 2처럼 CPHA=0인 경우 첫 에지 전에 첫 비트가 유효해야 한다는 점을 놓치기 쉽습니다. 디바이스별 setup/hold 시간은 반드시 해당 데이터시트를 따릅니다.

2. 네 모드를 PC에서 확인하는 C 예제

아래 코드는 하드웨어 전송을 대신하지 않는 에지 선택 표 검사입니다. spi_modes.c로 저장하고 gcc -std=c11 -Wall -Wextra -Werror spi_modes.c -o spi_modes로 빌드해 실행하세요. 네 모드의 유휴 레벨과 샘플 에지를 출력하고 assert로 표와 대조합니다.

#include <assert.h>
#include <stdio.h>

static const char *edge(int rising) { return rising ? "rising" : "falling"; }

int main(void) {
for (int mode = 0; mode < 4; ++mode) {
const int cpol = (mode >> 1) & 1;
const int cpha = mode & 1;
const int leading_rising = !cpol;
const int sample_rising = cpha ? !leading_rising : leading_rising;
printf("mode %d: idle=%s, leading=%s, sample=%s\n", mode,
cpol ? "high" : "low", edge(leading_rising), edge(sample_rising));
assert(mode == 2 * cpol + cpha);
assert(sample_rising == (mode == 0 || mode == 3));
}
puts("PASS: four SPI modes");
return 0;
}

예상 출력:

mode 0: idle=low, leading=rising, sample=rising
mode 1: idle=low, leading=rising, sample=falling
mode 2: idle=high, leading=falling, sample=falling
mode 3: idle=high, leading=falling, sample=rising
PASS: four SPI modes

3. RP 계열 MCU에 적용

Pico SDK의 spi_set_format(spi0, 8, SPI_CPOL_0, SPI_CPHA_1, SPI_MSB_FIRST)는 8비트, 모드 1, MSB 우선 예시입니다. spi_init()과 GPIO의 SPI 기능 설정 뒤에 호출하고, 디바이스가 요구하는 모드로 인자를 바꾸세요. 이 호출의 인자 이름과 값은 공식 Pico SDK SPI 헤더의 spi_set_format 정의에서 확인할 수 있습니다. 모드를 바꾼 뒤에도 장치의 최대 SCK 주파수, CS의 극성, CS setup/hold 시간, 비트 순서를 별도로 맞춰야 합니다.

Linux spidev라면 SPI_IOC_WR_MODE와 SPI_MODE_0~SPI_MODE_3을 사용합니다. 커널의 사용자 공간 SPI 문서는 read()와 write()를 나누면 두 호출 사이에 CS가 해제될 수 있다고 설명합니다. 명령과 응답 사이에 CS를 유지해야 하는 디바이스는 SPI_IOC_MESSAGE(N)처럼 하나의 메시지로 전송하세요.

4. 로직 애널라이저로 점검

  1. CS가 활성화되기 직전 SCK의 유휴 레벨을 보고 CPOL을 정합니다. 활성화된 순간의 첫 변화가 첫 에지입니다.
  2. 데이터시트의 샘플 표시가 첫 에지인지 두 번째 에지인지 확인해 CPHA를 정합니다. MOSI와 MISO를 각각 같은 기준으로 확인하세요.
  3. 예상한 값과 다르면 CS 유지 구간, 8비트 단위, MSB/LSB 순서, 전원·배선, SCK 속도를 차례로 점검합니다. 0x00이나 0xFF만 보인다고 모드 오류로 단정할 수는 없습니다.

PC 예제는 네 모드의 논리 관계만 검증했습니다. 실제 센서와 MCU 사이의 파형, setup/hold 시간, 전압 호환성은 실측하지 않았습니다. 참고: Linux SPI 개요, Linux spidev API, Pico SDK SPI 헤더.

관련 글

댓글

첫 댓글을 남겨 보세요.

관리자 확인 후 게시됩니다.

처리 중입니다...

잠시만 기다려주세요.