myGyro300SPI에 어떤 커맨드를 내리는 작업은 SPI 인터페이스를 통해 이루어진다. MCU에서 SPI의 MOSI 핀을 통해 명령을 내리는 것이다. 이번에는 이 커맨드에 관해 살펴보자.
myGyro300SPI의 명령은 ADIS16100 데이터쉬트의 12페이지 Control Register에 자세히 설명되어 있다. 커맨드는 12bit 길이를 가지고 있어서 16bit의 SPI frame 중 앞쪽 12비트만 사용한다.
ADIS16100 데이터 프레임의 구성
커맨드 구조는 13페이지 Table 5에 잘 설명되어 있다. 중요한 것은 15,11,10, 4번 비트 뿐이다. 혹시 모르는 사람을 위해...D/C는 Don't Care의 약자다. 즉 0이든 1이든 상관없다는 뜻.
- 15번 비트에 0을 주면 뒤에 따라오는 모든 DIN 비트는 무시한다. 무언가 write하려면 이 비트는 꼭 1이어야 한다는 뜻. 반면 설정을 바꾸지 않고 데이타만 계속 얻고자 할 때에는 이 비트를 0으로 주면 된다.
- 11,10 비트는 ADC 대상을 지정하는 것. ADIS16100에는 ADC 앞에 4채널 analog mux가 내장되어 있다. 이 mux의 채널을 설정함으로써 ADC 하는 대상을 선택할 수 있다. 자이로, 온도센서, 외부입력1/2 이렇게 4개의 채널을 선택 가능하다.
- 4번 비트는 출력 데이타의 format을 설정하는 것이다. 12bit 데이타를 표현할 때 0~4095 범위를 가지는 정수로 표현하거나, -2048~2047 범위를 가지는 정수로 표현할 수 있다. 전자의 경우 straight binary 포맷으로, 후자는 2의 보수로 출력을 받아보게 된다.
- gyro sensor 값을 2의 보수 형태로 읽고자 할 때 -> 0x8300
- 온도 센서 값을 binary로 읽고자 할 때 -> 0x8710
- 이전 셋팅(ADC 채널, 데이타 포맷)을 그대로 유지하면서 다시 ADC하고자 할 때 -> 0x0000
한가지 언급하고 넘어가야 할 부분이 있다. 별로 어려운 개념도 아닌데, 잘 이해못하는 사람이 많은듯해서...
쉽게 설명하기 위해 예를 들어 살펴보자. 길동이가 myGyro300SPI에 있는 외부 입력 1을 이용해 무언가 다른 센서의 아날로그 출력값을 ADC하고자 하는 경우를 생각해 보자. 길동이가 원하는 것은 gyro 값을 한번 읽고, AIN1 값을 한번 읽은 다음 이렇게 얻은 2개의 데이터로 무언가 열심히 처리하고 다시 두개의 값을 읽는 것으로 되돌아오는 루프이다. 바로 아래처럼.
코드를 보면 대략 이런 형태일 것이다.
위 코드는 잘못된 것이다.
ADIS16100에 넣는 command는 정확하다. 문제는 command를 넣는다고 그 결과가 바로 나오지 않는다는 것. 10라인에서 gyro 값을 읽기 위한 command word인 0x8300을 put 하고, 11라인에서 결과값을 get 했다. 이전 글에서도 언급했지만 SPI는 full-duplex(전이중) 통신을 하고, read(get)와 write(put)는 꼭 한쌍으로 붙어 존재한다. 동시에! 이번 포스팅의 첫번째 그림을 보자. 한번의 프레임을 보여주고 있는데, DIN과 DOUT은 동시에 움직인다. 그러니 10라인에서 "gyro 값을 읽어라" 하고 명령을 내린 것과 11라인에서 "값을 읽어 gyro 변수에 넣어라" 라는 동작이 동시에 일어난다는 뜻이다. 자이로 센서가 미래를 예측할 수 있는 기능이 있지 않은 이상 명령을 받는것과 동시에 그 결과값을 알려주는 것은 말이 안된다. 센서 입장에서는 어느 채널을 ADC해야하는 지 command word를 수신한 후에나 알 수 있다. 마치 "오늘 숙제는 4장 연습문제 풀어오는겁니다"라고 말하는 것과 동시에 숙제를 거둬 들이는 성질 급한 조교와 같은 상황... 센서가 ADC 할 시간은 줘야 할것 아닌가?
위 timing chart를 보자. 2개의 프레임이 표현되고 있는데, 좌측의 첫번째 프레임에서 DIN 핀을 통해 write 한 command word의 결과값은 우측의 다음 프레임에서 DOUT 핀을 통해 read 할 수 있다.
달리 표현하면... read 하는 데이타는 이전 프레임의 ADC 결과이다.
길동이가 원하는 결과를 얻으려면 Put하는 command word와 Get하는 data를 서로 타이밍을 맞춰서 진행해야 한다. 소스코드를 수정하면 아래와 같이 될 것이다.
10라인에서 "AIN1을 읽어" 라는 command word를 put했고 그 결과는 다음번 frame, 즉 14라인의 get에서 읽혀진다. 마찬가지로 13라인에서 "gyro를 읽어"라는 명령은 다음번 루프에 가서 11라인을 통해 읽혀진다. 이제 자기 자리 맞게 찾아 들어간 샘.
사실 마지막 코드 역시 잘못된 코드다. 읽어들인 data의 포맷에 따라 처리를 해야 하는데, 그 부분이 빠져있다. 이 내용은 다음 글에서 다룰 예정이므로 일단 넘어가는 것.