아래 SPI 관련 튜토리얼의 자료를 번역/수정 하였습니다.


비동기식 시리얼 통신의 문제점

TX, RX 핀을 이용해서 동작하는 시리얼(Serial, 이하 UART로 표기) 통신은 비동기식(asynchronous) 으로 동작합니다. 이 말은 통신을 하는 두 장치 사이에 데이터를 보내는 중인지 아닌지 알려주는 별도의 컨트롤러가 없다는 뜻이므로 두 장치는 끊임없이 상대방이 데이터를 보내는지 확인을 해야 합니다. 따라서 UART 통신을 사용하는 장치들은 1초를 몇 개의 간격로 나눠서 데이터를 보낼지(baud rate) 미리 약속해둬야 합니다. 이 간격을 정확하게 지키기 위해서는 통신에 참여하는 양쪽 장치가 같은 클럭(clock)을 사용해야 하는데, 만약 두 장치가 사용하는 클럭이 미세하게 틀리다면 문제가 발생할 수 있습니다.

참고!! 컴퓨터의 내부 동작은 모두 클럭(clock)으로부터 생성되는 신호에 동기화 되어 있습니다. 클럭은 컴퓨터에 부착된 main crystal 에 의해 생성됩니다. 아두이노도 마찬가지.

이 문제를 해결하기 위해서 UART 통신은 매 1 byte 송신을 할 때마다 추가로 start/stop bit 를 추가해줍니다. 명확하게 데이터를 인식할 수 있도록 데이터의 시작과 끝을 표시할 뿐 아니라 클럭이 달라 sync 가 어긋나더라도 start bit를 보고 다시 맞춰줄 수 있습니다. 결과적으로 UART 통신은 아래처럼 1byte 를 전송하게 됩니다.

52ddb2d5ce395f59658b4567

이제 UART 통신이 동작하는건 문제가 없지만 매 1 byte를 전송 할 때마다 start/stop bit 가 생성되고 sync를 다시 맞춰야 하니 오버헤드가 생깁니다. 그리고 송수신을 위해 복잡한 하드웨어 컨트롤러가 필요한 것이 단점입니다. 반면에 동기식 시리얼 통신은 이런 문제에서 자유롭습니다.


동기식 시리얼 통신과 송신

동기식 시리얼 통신은 데이터를 보낼 때 데이터가 전달된다고 알려주는 별도의 클럭(clock) 라인을 사용하는 방법입니다. 클럭 라인을 통신 참여자가 공유함으로써 데이터 라인으로 언제 데이터가 들어오는지 알 수 있도록 해주는 방법입니다. I2C, SPI(Serial Peripheral Interface) 통신이 대표적인 동기식 통신 방법입니다.

즉, 클럭 라인으로 들어오는 rising (low to high) 또는 falling (high to low) 신호를 인식해서 즉시 데이터 라인에서 값을 읽습니다.

52ddb2d8ce395fad638b4567

따라서 UART 통신처럼 통신에 참여하는 장치들이 통신 속도(baud rate)를 공유할 필요도 없고, 클럭을 동일하게 유지해야 할 필요도 없습니다. 그리고 하드웨어도 간단한 shift register 로 구현할 수 있어서 저렴합니다.


데이터 수신

데이터를 전달할 때는 앞서 설명한 방법을 사용하면 되는데 데이터를 수신할 때는 어떻게 해야하나? 하는 의문이 들 수 있습니다. 이 경우 약간 더 복잡한 방식을 사용합니다. 동기식 시리얼 통신 중 SPI(Serial Peripheral Interface) 통신의 경우는 아래와 같이 동작합니다.

52ddb2dbce395fae408b4568

SPI 통신은 오직 한 장치만 클럭 라인에 신호(CLK, SCK, ClocK)를 생성합니다. 클럭 신호를 생성하는 장치를 master 라고 하고, 나머지 통신에 참가한 장치들은 slave 라 부릅니다. SPI는 1:n 통신이 가능하므로 slave 는 1개 이상의 장치가 될 수 있습니다. 대부분의 경우 당신이 사용하는 아두이노(마이크로 컨트롤러)가 마스터가 됩니다.

데이터가 마스터에서 슬레이브로 전달될 때는 MOSI(Master Out / Slave In) 데이터 라인을 사용하며, 이 경우는 앞서 설명한 데이터 전송 방법을 사용합니다. 반대로 슬레이브에서 마스터로 데이터가 전송 될 때는 별도의 데이터 라인인 MISO(Master In / Slave Out) 를 사용합니다. 즉, 클럭(SCK), 데이터 전송(MOSI), 데이터 수신(MISO) 세 개의 라인이 통신에 사용됩니다.

마스터가 데이터를 수신할 때도(아두이노가 데이터를 받을 때) 마찬가지로 클럭 신호가 필요합니다. 그래서 마스터 장치는 클럭 신호를 생성할 때 미리 수신용 클럭 신호도 순서대로 생성합니다. MISO 라인으로 들어오는 데이터를 위한 신호를 미리 생성해주는 겁니다. UART 통신이 아무때고 데이터를 송수신 하는 것과는 전혀 다른다는걸 아실 수 있을겁니다.

이 방식은 꽤 비효율적으로 보일 수도 있지만 일반적인 센세와 통신할 때 그리 큰 문제가 되지 않습니다. 마스터에서 “read data” 라는 명령어를 전송하면 센서는 자신이 전송할 데이터의 크기를 보내주도록 만들면 됩니다. 그러면 이후 데이터 전체를 받기 위한 클럭 신호를 생성하면 됩니다.


슬레이브 장치 선택 (SS, Slave Select)

앞서 언급한 CLK, MOSI, MISO 라인 외에 추가해야 할 라인이 하나 더 있습니다. 바로 SS(Slave Select) 입니다.

SPI 통신은 여러개의 slave 장치가 하나의 마스터에 연결될 수 있다고 했습니다. 즉, SPI 에서 클럭(SCK), MOSI, MISO 라인은 모든 장치가 공유합니다. 따라서 마스터가 데이터를 보내줄 때 이 데이터가 어디로 가는 것인지 알려주는 방법이 필요합니다. SPI에서는 이 문제를 하드웨어적인 신호선(SS) 하나를 더 추가해서 해결합니다.

52ddb2dcce395fed638b4567

동작이 없을 때 이 신호선은 HIGH 상태를 유지하다가 통신이 필요할 때 LOW 로 바꿔줍니다.(active low) 그래서 SS 라인이 센서의 enable/reset 라인과 연결되어 데이터가 필요할 때만 알려주는 방법으로 사용되기도 합니다.


다수의 슬레이브 장치 연결

여러개의 슬레이브 장치를 연결하는 방법은 크게 두 가지가 있습니다.

첫 번째는 각 장치마다 하드웨어적인 신호선(SS)을 할당하는 방법입니다. 이 방법을 사용하면 특정 장치와 통신이 필요할 경우 해당되는 SS 라인을 LOW 로 바꿔주면 됩니다. 이 방법은 직관적이고 단순한 해결책이지만 슬레이브 장치의 수만큼 신호선(SS)이 필요합니다.

50e5d529ce395f2f7a000000

두 번째 방법은 MOSI, MISO 라인을 체인처럼 연결하고 SS 라인을 공유하는 방법입니다. 이렇게 연결하면 SS 라인으로 신호를 보내면 모든 슬레이브 장치들이 통신할 준비를 합니다. 그리고 마스터에서 전송한 데이터가 체인처럼 연결된 데이터 라인을 따라 모든 슬레이브 장치로 전달됩니다. 각 슬레이브 장치는 자신에게 전달된 데이터만 취사 선택해서 사용하고, 자신의 데이터가 아닌 경우 적절히 데이터를 변형해 다음 장치로 넘겨줄 수 있습니다.

50e5d529ce395fd27b000001

이런 연결 방법은 Daisy-chained 라고 부르고 주로 마스터에서 슬레이브로 단 방향 데이터만 사용할 경우 유용합니다. RGB LED strip 같은 장치가 대표적인 예입니다. 데이터가 마스터에서 슬레이브로 단 방향으로만 흐를 경우 마스터의 데이터 수신 라인인 MISO 연결은 생략할 수 있습니다.


SPI 프로그래밍

아두이노를 사용할 경우 shiftIn(), shiftOut() 함수를 이용해서 직접 디지털 핀에 간단한 SPI 동작을 구현할 수 있습니다. 임의의 디지털 핀을 사용할 수 있지만 소프트웨어적으로 SPI 를 구현하기 때문에 다소 느릴 수 있습니다.

반면 아두이노가 제공하는 SPI 라이브러리를 사용할 경우 마이크로 컨트롤러가 가진 SPI 하드웨어를 사용할 수 있어 훨씬 빠르고 안정적입니다. 대신 정해진 SPI 핀만 사용 가능합니다.

SPI 연결은 위에 예시한 표준 방법 외에도 변형된 연결 방법이 다수 있습니다. 센서나 모듈에 따라 그에 맞게 핀 연결을 해줘야 합니다.

참고자료

.