myCortex 시리즈에 사용된 Luminary micro LM3S 칩셋에는 모델에 따라 1개 혹은 2개의 SPI peripheral이 내장되어있다. 많이 사용되는 myCortex-LM8962에는 1개의 SPI가 내장되어 있다. myGyro300SPI를 myCortex-LM8962와 연결하여 SPI 통신을 하는 방법에 대해 자세히 살펴보자.
우선 LM3S8962에 내장된 SPI peirpheral에 대해 살펴보자. (편의상 LM3S8962를 기준으로 설명하지만 myCortex-LM308/608/808에서 사용된 LM3S308/608/808 칩에도 동일한 SPI peripheral이 내장되어 있으므로 동일하게 적용된다.)
LM3S8962 데이터쉬트에서 14장 Synchronous Serial Interface(SSI) 장이 SPI peripheral에 대한 내용을 다루고 있다.(방금전에 언급했듯이, LM3S308/608/808 데이터쉬트에도 동일한 내용이 있으며, chapter 번호는 모델에 따라 다를 수 있다) 데이터쉬트의 내용을 살펴보면 peripheral block diagram부터 시작해서 bit rate 생성기 구조, FIFO의 구조와 사용법, 인터럽트 등등에 대한 내용이 연달아 나오지만, 일단은 그냥 넘어가도 무관하다. 이 내용들을 모르더라도 DriverLib 함수들을 사용하면 손쉽게 설정해서 사용할 수 있기 때문. 하지만 14.2.4절의 Frame Format 부분은 읽어봐야 한다.
이전 글에서도 설명했지만 이쯤에서 다시한번. Frame이란 무엇인가? SPI에서 말하는 frame은 한번의 유효한 데이타 전송 단위를 말하며, 비트 숫자로 표시된다. CS핀이 low인 동안 몇 비트의 데이타가 오고가는가 라고 생각할 수도 있다(그런데 이건 frame size와 다른 경우도 있으니 정확한 정의는 아니다) myGyro300SPI를 예로 살펴보면, CS가 한번 low로 내려간 다음 다시 high로 올라가기 전에 16비트의 데이터가 오고간다. 물론 클럭도 16 클럭이 들어간다. 이처럼 한번의 의미있는 통신에 소요되는 클럭 숫자를 frame size라고 표현한다.
SPI 인터페이스는 SCLK의 phase와 polarity에 따라 다양한 모드를 가지고 있다. 이 모드는 각각의 SPI 장치에 따라 다르고, 올바르게 설정하지 않으면 정상적으로 통신이 이루어 지지 않는다. myGyro300SPI의 경우에는 Freescale MODE 2를 사용한다. 잘 모르겠다면 ADIS16100 데이터쉬트 페이지 5의 그림 2에 있는 SPI bus timing chart를 LM3S8962 데이터쉬트 그림 14-2 ~ 14-11까지와 죽 비교해 보고 가장 가까운 것으로 고르면 된다. ADIS16100 데이터쉬트의 그림 2를 자세히 보면 CS의 falling edge에서 SCLK가 high이고, SCLK의 rising edge에서 DIN이 변한다. SPI 신호선의 이름이 조금 다르지만 FSS = CS, DOUT = RX로 생각하고 LM3S8962 데이터쉬트의 그림과 비교해 보면 그림 14-7과 같다.
그러면 SPO, SPH는 무슨 뜻일까? SPO는 polarity를, SPH는 phase를 나타낸다.
소스코드를 보기 전에 어떻게 핀이 연결되는지 간단히 살펴보자. myCortex 보드에 1개의 myGyro300SPI를 연결하고자 할 때에는 아래 그림과 같이 단순히 1:1로 master와 slave의 핀들을 연결해 주면 된다. 전원은 VDD5V와 Vdrive의 차이점글 참조.
myCortex-LM8962의 예제 spi_myGyro300SPI를 살펴보면 SPI 설정을 잡아주는 부분이 위와 같이 있다. 코드를 한줄씩 살펴보자.
75라인은 SPI peripheral을 enable시키는 부분이다. Luminary chip에서는 peripheral을 사용하기 전에 반듯이 enable 시켜줘야 한다.
76라인에서 GPIO 핀을 SPI 버스용으로 설정한다. Port A의 2, 3, 4, 5번 핀을 SPI 목적으로 할당한 것이다.
77-78라인에서 GPIO 패드 설정을 한다. 4mA 전류 구동과 weak pull-up 저항을 사용하게끔 설정하였다.
79라인이 SPI 설정의 핵심부분이다. SSI_FRF_MOTO_MODE_2 라는 부분이 SPI frame format motorola mode 2이다. (Freescale=Motolora 라고 생각하면 된다) SSI_MODE_MASTER는 MCU를 SPI master mode로 사용하겠다는 뜻이고, 1000000은 SPI 클럭 속도를 1MHz로 사용하겠다는 뜻이다. 마지막 인자 16은 SPI frame width를 의미하며, myGyro300SPI의 frame width와 같은 16bit로 설정하게 된다.
위 코드는 하나의 SPI frame 통신을 하는 부분이다.
SSIDataPut() 함수는 SPI 버스를 통해 myGyro300SPI로 데이터를 내보내는 함수이고, SSIDataGet() 함수는 SPI 버스를 통해 myGyro300SPI에서 부터 데이터를 읽어오는 함수이다. Put의 경우 MCU에서 write하는, 즉 MOSI 핀을 통해 데이터를 내보내게 되고, 반대로 Get의 경우 MISO 핀을 통해 데이터를 읽어온다. myGyro300SPI의 frame width가 16bit이므로 Put/Get 하는 데이터의 크기 역시 16bit로 구성된다.
여기서 잠깐 SPI의 핀 구성을 다시 살펴보자. SPI에는 MOSI와 MISO 두개의 데이터 신호선이 독립적으로 있다. 이를 통해 master->slave와 slave->master의 양방향 통신이 동시에 이루어진다. 하나의 프레임에는 master->slave 방향의 데이터 흐름과 slave->master 방향의 데이터 흐름이 항상 같이 존재한다. 이것은 SSIDataPut() 함수만, 혹은 SSIDataGet() 함수만 단독으로 사용될 수는 없다는 뜻이다. 소스 코드상으로는 SSIDataPut()함수가 호출되고 뒤이에 SSIDataGet() 함수가 호출되지만 실제로 데이터 통신이 일어나는 시점은 같은 순간이다. SSIDataPut() 함수가 호출된 상황에서 바로 SPI frame이 시작되지 않고 이어지는 SSIDataGet() 함수가 호출되어 한쌍이 만들어지면 그때에서야 SPI frame이 시작된다. 이처럼 Put과 Get이 한쌍으로 있어야 한번의 frame이 이루어진다는 점을 명심하자.
SPI 초기화 코드 부분에서 SSIConfigSetExpClk() 함수의 마지막 인자로 frame size를 16으로 지정했다. 그리고 GPIOPinTypeSSI() 함수를 이용해 CS(FSS)핀 포함 SPI 핀 4개 모두를 SPI로 할당했다. 이렇게 설정한 경우 SPI 모듈에서 CS(FSS)핀을 자동으로 관리한다. 즉 별도로 CS(FSS)핀을 low로 내리거나 high로 올리거나 하는 코드를 넣지 않아도 칩이 알아서 다 처리해 준다는 뜻이다.
만일 GPIOPinTypeSSI() 함수에서 특정 핀을 빼고 호출하게 되면 빠진 핀은 자동으로 처리해 주지 않는다. 만일 CS(FSS)핀에 해당하는 GPIO_PIN_3를 빼고 지정하면 CS(FSS) 제어를 자동으로 해 주지 않고, MISO(RX)에 해당하는 GPIO_PIN_4를 뺀다면 read를 하지 않는-write만 하는 SPI 통신 형태로 구성된다.
만일 CS 제어를 SPI 페리페럴에게 위임하는 대신 프로그래머가 직접 제어한다면 어떤 상황인 것일까? myCortex 보드에 3개의 myGyro300SPI가 연결된 경우를 생각해 보자. SCLK, MOSI, MISO 핀은 3개의 myGyro300SPI에 병렬로 연결하지만, CS핀은 3개의 모듈에 각각 따로 연결해야 한다. 문제는 myCortex-LM8962에는 1개의 CS 핀만 있다. 이런 경우에는 임의의 GPIO 핀을 CS로 활용할 수 있다.
CS 핀의 역할은 frame의 시작과 끝을 알려주는 것이므로 빠른 동작이 필요없다. 놀고 있는 GPIO 핀을 output 형태로 설정하고, 이를 myGyro300SPI의 CS핀에 연결해 주면 된다. 그리고 frame을 시작하기 전에 해당 모듈의 CS핀을 low로 떨어뜨리고 frame이 모두 끝난 후에 CS를 high로 올려주는 것이다.
이 방법은 myGyro300SPI와 myAccel3LV02를 동시에 연결할 때에도 그대로 적용된다. 이 경우에는 myAccel3LV02의 SPI frame format이 myGyro300SPI와 다르기 때문에 추가적인 코드가 더 필요하긴 한다. 이 내용은 다음번에 정리할 계획.
우선 LM3S8962에 내장된 SPI peirpheral에 대해 살펴보자. (편의상 LM3S8962를 기준으로 설명하지만 myCortex-LM308/608/808에서 사용된 LM3S308/608/808 칩에도 동일한 SPI peripheral이 내장되어 있으므로 동일하게 적용된다.)
LM3S8962 데이터쉬트에서 14장 Synchronous Serial Interface(SSI) 장이 SPI peripheral에 대한 내용을 다루고 있다.(방금전에 언급했듯이, LM3S308/608/808 데이터쉬트에도 동일한 내용이 있으며, chapter 번호는 모델에 따라 다를 수 있다) 데이터쉬트의 내용을 살펴보면 peripheral block diagram부터 시작해서 bit rate 생성기 구조, FIFO의 구조와 사용법, 인터럽트 등등에 대한 내용이 연달아 나오지만, 일단은 그냥 넘어가도 무관하다. 이 내용들을 모르더라도 DriverLib 함수들을 사용하면 손쉽게 설정해서 사용할 수 있기 때문. 하지만 14.2.4절의 Frame Format 부분은 읽어봐야 한다.
이전 글에서도 설명했지만 이쯤에서 다시한번. Frame이란 무엇인가? SPI에서 말하는 frame은 한번의 유효한 데이타 전송 단위를 말하며, 비트 숫자로 표시된다. CS핀이 low인 동안 몇 비트의 데이타가 오고가는가 라고 생각할 수도 있다(그런데 이건 frame size와 다른 경우도 있으니 정확한 정의는 아니다) myGyro300SPI를 예로 살펴보면, CS가 한번 low로 내려간 다음 다시 high로 올라가기 전에 16비트의 데이터가 오고간다. 물론 클럭도 16 클럭이 들어간다. 이처럼 한번의 의미있는 통신에 소요되는 클럭 숫자를 frame size라고 표현한다.
SPI 인터페이스는 SCLK의 phase와 polarity에 따라 다양한 모드를 가지고 있다. 이 모드는 각각의 SPI 장치에 따라 다르고, 올바르게 설정하지 않으면 정상적으로 통신이 이루어 지지 않는다. myGyro300SPI의 경우에는 Freescale MODE 2를 사용한다. 잘 모르겠다면 ADIS16100 데이터쉬트 페이지 5의 그림 2에 있는 SPI bus timing chart를 LM3S8962 데이터쉬트 그림 14-2 ~ 14-11까지와 죽 비교해 보고 가장 가까운 것으로 고르면 된다. ADIS16100 데이터쉬트의 그림 2를 자세히 보면 CS의 falling edge에서 SCLK가 high이고, SCLK의 rising edge에서 DIN이 변한다. SPI 신호선의 이름이 조금 다르지만 FSS = CS, DOUT = RX로 생각하고 LM3S8962 데이터쉬트의 그림과 비교해 보면 그림 14-7과 같다.
ADIS16100 SPI 타이밍
LM3S8962 SPI 타이밍 차트(mode = 2)
그러면 SPO, SPH는 무슨 뜻일까? SPO는 polarity를, SPH는 phase를 나타낸다.
- SPO = 0 : idle상태(CS가 high일때)에서 SCLK가 low이다.
- SPO = 1 : idle상태에서 SCLK가 high이다.
- SPH = 0 : SCLK의 rising edge에서 MOSI가 변한다.
- SPH = 1 : SCLK의 falling edge에서 MOSI가 변한다.
소스코드를 보기 전에 어떻게 핀이 연결되는지 간단히 살펴보자. myCortex 보드에 1개의 myGyro300SPI를 연결하고자 할 때에는 아래 그림과 같이 단순히 1:1로 master와 slave의 핀들을 연결해 주면 된다. 전원은 VDD5V와 Vdrive의 차이점글 참조.
SPI 버스
myCortex-LM8962의 예제 spi_myGyro300SPI를 살펴보면 SPI 설정을 잡아주는 부분이 위와 같이 있다. 코드를 한줄씩 살펴보자.
75라인은 SPI peripheral을 enable시키는 부분이다. Luminary chip에서는 peripheral을 사용하기 전에 반듯이 enable 시켜줘야 한다.
76라인에서 GPIO 핀을 SPI 버스용으로 설정한다. Port A의 2, 3, 4, 5번 핀을 SPI 목적으로 할당한 것이다.
77-78라인에서 GPIO 패드 설정을 한다. 4mA 전류 구동과 weak pull-up 저항을 사용하게끔 설정하였다.
79라인이 SPI 설정의 핵심부분이다. SSI_FRF_MOTO_MODE_2 라는 부분이 SPI frame format motorola mode 2이다. (Freescale=Motolora 라고 생각하면 된다) SSI_MODE_MASTER는 MCU를 SPI master mode로 사용하겠다는 뜻이고, 1000000은 SPI 클럭 속도를 1MHz로 사용하겠다는 뜻이다. 마지막 인자 16은 SPI frame width를 의미하며, myGyro300SPI의 frame width와 같은 16bit로 설정하게 된다.
위 코드는 하나의 SPI frame 통신을 하는 부분이다.
SSIDataPut() 함수는 SPI 버스를 통해 myGyro300SPI로 데이터를 내보내는 함수이고, SSIDataGet() 함수는 SPI 버스를 통해 myGyro300SPI에서 부터 데이터를 읽어오는 함수이다. Put의 경우 MCU에서 write하는, 즉 MOSI 핀을 통해 데이터를 내보내게 되고, 반대로 Get의 경우 MISO 핀을 통해 데이터를 읽어온다. myGyro300SPI의 frame width가 16bit이므로 Put/Get 하는 데이터의 크기 역시 16bit로 구성된다.
여기서 잠깐 SPI의 핀 구성을 다시 살펴보자. SPI에는 MOSI와 MISO 두개의 데이터 신호선이 독립적으로 있다. 이를 통해 master->slave와 slave->master의 양방향 통신이 동시에 이루어진다. 하나의 프레임에는 master->slave 방향의 데이터 흐름과 slave->master 방향의 데이터 흐름이 항상 같이 존재한다. 이것은 SSIDataPut() 함수만, 혹은 SSIDataGet() 함수만 단독으로 사용될 수는 없다는 뜻이다. 소스 코드상으로는 SSIDataPut()함수가 호출되고 뒤이에 SSIDataGet() 함수가 호출되지만 실제로 데이터 통신이 일어나는 시점은 같은 순간이다. SSIDataPut() 함수가 호출된 상황에서 바로 SPI frame이 시작되지 않고 이어지는 SSIDataGet() 함수가 호출되어 한쌍이 만들어지면 그때에서야 SPI frame이 시작된다. 이처럼 Put과 Get이 한쌍으로 있어야 한번의 frame이 이루어진다는 점을 명심하자.
SPI 초기화 코드 부분에서 SSIConfigSetExpClk() 함수의 마지막 인자로 frame size를 16으로 지정했다. 그리고 GPIOPinTypeSSI() 함수를 이용해 CS(FSS)핀 포함 SPI 핀 4개 모두를 SPI로 할당했다. 이렇게 설정한 경우 SPI 모듈에서 CS(FSS)핀을 자동으로 관리한다. 즉 별도로 CS(FSS)핀을 low로 내리거나 high로 올리거나 하는 코드를 넣지 않아도 칩이 알아서 다 처리해 준다는 뜻이다.
만일 GPIOPinTypeSSI() 함수에서 특정 핀을 빼고 호출하게 되면 빠진 핀은 자동으로 처리해 주지 않는다. 만일 CS(FSS)핀에 해당하는 GPIO_PIN_3를 빼고 지정하면 CS(FSS) 제어를 자동으로 해 주지 않고, MISO(RX)에 해당하는 GPIO_PIN_4를 뺀다면 read를 하지 않는-write만 하는 SPI 통신 형태로 구성된다.
만일 CS 제어를 SPI 페리페럴에게 위임하는 대신 프로그래머가 직접 제어한다면 어떤 상황인 것일까? myCortex 보드에 3개의 myGyro300SPI가 연결된 경우를 생각해 보자. SCLK, MOSI, MISO 핀은 3개의 myGyro300SPI에 병렬로 연결하지만, CS핀은 3개의 모듈에 각각 따로 연결해야 한다. 문제는 myCortex-LM8962에는 1개의 CS 핀만 있다. 이런 경우에는 임의의 GPIO 핀을 CS로 활용할 수 있다.
CS 핀의 역할은 frame의 시작과 끝을 알려주는 것이므로 빠른 동작이 필요없다. 놀고 있는 GPIO 핀을 output 형태로 설정하고, 이를 myGyro300SPI의 CS핀에 연결해 주면 된다. 그리고 frame을 시작하기 전에 해당 모듈의 CS핀을 low로 떨어뜨리고 frame이 모두 끝난 후에 CS를 high로 올려주는 것이다.
이 방법은 myGyro300SPI와 myAccel3LV02를 동시에 연결할 때에도 그대로 적용된다. 이 경우에는 myAccel3LV02의 SPI frame format이 myGyro300SPI와 다르기 때문에 추가적인 코드가 더 필요하긴 한다. 이 내용은 다음번에 정리할 계획.