[MSP430] USCI-SPI

pikamon·2020년 12월 23일
0

MSP430

목록 보기
9/13

본 글은 MSP430G2553 MCU를 기준으로 작성되었습니다.
세부적인 내용은 제품군마다 조금씩 다를 수 있습니다.


1. USCI-SPI란?

SPI(Serial Peripheral Interface)란 UART와 마찬가지로 칩 간에 데이터를 주고 받기 위한 시리얼 통신 프로토콜 중 하나이다. 3개 또는 4개의 라인을 이용하며, 시프트 레지스터를 이용한다는 점이 특징이다. UART와 I2C에 비해 비교적 통신 속도가 빠른 것이 장점이다.

MSP430x2xx 모델에서는 USCI 모듈의 SPI 모드를 이용하여 SPI 통신을 할 수 있다.

SPI는 USCI_A와 USCI_B 모두에서 지원하므로, 둘 중 하나를 SPI 모드로 선택하여 사용하면 된다.

2. USCI-SPI 특징

USCI-SPI의 특징은 아래와 같다.

  • 7- or 8-bit data length
  • LSB-first or MSB-first data transmit and receive
  • 3-pin and 4-pin SPI operation
  • Master or slave modes
  • Independent transmit and receive shift registers
  • Separate transmit and receive buffer registers
  • Continuous transmit and receive operation
  • Selectable clock polarity and phase control
  • Programmable clock frequency in master mode
  • Independent interrupt capability for receive and transmit
  • Slave operation in LPM4

몇 가지만 살펴보자.

  • 3-pin and 4-pin SPI operation

SPI 통신 라인을 3핀 또는 4핀으로 설정할 수 있다. 3핀은 흔히 아는 CLK, SIMO, SOMI를 말하며, 4핀은 3핀에 STE 라인이 추가된 것을 말한다. STE란 슬레이브 전송 활성화(Slave Trasmit Enable)의 약자로, 하나의 버스 상에 여러 개의 마스터가 존재할 수 있도록 해주는 핀이라고 한다.

  • Independent interrupt capability for receive and transmit

SPI TX와 RX에 대해 각각 독립적으로 ISR을 작성할 수 있다고 한다.

  • Slave operation in LPM4

LPM4 모드에서 슬레이브 모드로 동작이 가능하다고 한다.

3. USCI-SPI 다이어그램

USCI-SPI의 다이어그램은 아래와 같다.

대체로 USCI-UART에서 설명한 내용과 비슷하다. (실제로 그림도 비슷하게 생겼다). 선택된 클럭 소스로부터 승산 또는 제산, 극성 및 위상 제어를 거쳐 SPI 클럭이 생성되어 CLK 핀으로 출력 및 TX, RX 모듈로 들어간다. TX 모듈은 클럭에 맞춰 데이터를 전송, RX 모듈은 클럭에 맞춰 데이터를 수신한다.

4. 관련 레지스터

USCI-SPI와 관련된 레지스터는 아래와 같다. UCA와 UCB 양쪽에 공통된 부분은 합쳐서 UCX로 표현하였다.

  • UCXxCTLy - USCI_Xx control register
  • UCXxBRy - USCI_Xx baud rate control register
  • UCXxSTAT - USCI_Xx status register
  • UCXxRXBUF - USCI_Xx receive buffer register
  • UCXxTXBUF - USCI_Xx transmit buffer register
  • IE2 - SFR interrupt enable register 2
  • IFG2 - SFR interrupt flag register 2
  • UC1IE - USCI_X1 interrupt enable register
  • UC1IFG - USCI_X1 interrupt flag register

1. UCXxCTLy

SPI 통신을 초기화하기 위한 레지스터이다.

2. UCXxBRy

SPI 클럭 프리스케일 설정을 위한 레지스터이다.

3. UCXxSTAT

각종 상태와 관련된 플래그들을 관리하는 레지스터이다.

4. UCXxRXBUF

SPI RX 버퍼 레지스터이다.

5. UCXxTXBUF

SPI TX 버퍼 레지스터이다.

6. IE2

UCA0, UCB0의 TX, RX 인터럽트 활성화를 위한 레지스터이다.

7. IFG2

UCA0, UCB0의 TX, RX 인터럽트 플래그 레지스터이다.

8. UC1IE

UCA1, UCB1의 TX, RX 인터럽트 활성화를 위한 레지스터이다.

9. UC1IFG

UCA1, UCB1의 TX, RX 인터럽트 플래그 레지스터이다.

5. 준비물

SPI를 이용하는 가장 일반적인 시나리오는 SPI를 지원하는 아날로그 또는 디지털 센서를 MCU로 제어하는 것이다. 하지만 이는 별도의 센서가 필요하므로, 본 글에서는 MSP430G2553 안에 있는 두 개의 USCI-SPI를 각각 마스터와 슬레이브로 이용하는 예제를 다룬다.

두 USCI-SPI에서 사용하는 GPIO 쌍이 서로 다르므로, 이를 서로 이어줄 점퍼선이 필요하다. 점퍼선을 3개 준비하자. (SIMO, SOMI, CLK)

글을 쓰고 든 생각인데, 점퍼선도 없으면 어떡하지?

6. 예제

예제 두 개를 다루어보자. 예제 중에서 센서를 제어하는 예제들은 제외하였다.

  1. USCI_A0를 이용한 3-wire 통신 (Master)
  2. USCI_B0를 이용한 3-wire 통신 (Slave)

1. USCI_A0를 이용한 3-wire 통신 (Master)

USCI_A0를 이용하여 SPI를 Master 모드로 사용하는 예제이다. 총 5개의 라인을 사용한다.

  • P1.2 -> Data Out (UCA0SIMO)
  • P1.1 <- Data In (UCA0SOMI)
  • P1.4 -> Serial Clock Out (UCA0CLK)
  • P1.0 -> LED
  • P1.5 -> Slave reset

아래는 숫자를 1부터 1씩 증가시키며 슬레이브에 SPI 통신으로 보내는 예제이다. 아래 코드는 마스터용으로, 슬레이브용 코드는 예제 2에 있는 코드를 이용하면 된다.

#include <msp430.h>

unsigned char MST_Data, SLV_Data;

int main(void)
{
    volatile unsigned int i;

    WDTCTL = WDTPW + WDTHOLD;                    // Stop watchdog timer

    P1OUT = 0x00;                                // P1 setup for LED & reset output
    P1DIR |= BIT0 + BIT5;
    P1SEL = BIT1 + BIT2 + BIT4;
    P1SEL2 = BIT1 + BIT2 + BIT4;

    UCA0CTL0 |= UCCKPL + UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI master
    UCA0CTL1 |= UCSSEL_2;                        // SMCLK
    UCA0BR0 |= 0x02;                             // /2
    UCA0BR1 = 0;                                 //
    UCA0MCTL = 0;                                // No modulation
    UCA0CTL1 &= ~UCSWRST;                        // **Initialize USCI state machine**

    IE2 |= UCA0RXIE;                             // Enable USCI0 RX interrupt

    P1OUT &= ~BIT5;                              // Now with SPI signals initialized,
    P1OUT |= BIT5;                               // reset slave

    __delay_cycles(75);                          // Wait for slave to initialize

    MST_Data = 0x01;                             // Initialize data values
    SLV_Data = 0x00;

    UCA0TXBUF = MST_Data;                        // Transmit first character

    __bis_SR_register(LPM0_bits + GIE);          // CPU off, enable interrupts
}

#pragma vector=USCIAB0RX_VECTOR                  // Test for valid RX and TX character
__interrupt void USCIA0RX_ISR(void)
{
    volatile unsigned int i;

    while (!(IFG2 & UCA0TXIFG));                 // USCI_A0 TX buffer ready?

    if (UCA0RXBUF == SLV_Data)                   // Test for correct character RX'd
    P1OUT |= BIT0;                               // If correct, light LED
    else
    P1OUT &= ~BIT0;                              // If incorrect, clear LED

    MST_Data++;                                  // Increment master value
    SLV_Data++;                                  // Increment expected slave value
    UCA0TXBUF = MST_Data;                        // Send next value

    __delay_cycles(50);                          // Add time between transmissions to
}                                                // make sure slave can keep up

MSP-EXT430G2ET 보드의 GPIO 헤더를 점퍼선을 이용해 아래와 같이 연결한 후 코드를 실행한다.

  • P1.2와 P1.7을 연결 (MOSI)
  • P1.1과 P1.6을 연결 (MISO)
  • P1.4와 P1.5를 연결 (CLK) - 맞나?

코드를 실행하면 마스터에서는 데이터를 1부터 1씩 증가시키며 SPI 프로토콜에 맞춰 슬레이브로 보내며, 슬레이브는 받은 데이터를 그대로 다시 마스터로 보내는 것을 볼 수 있다. 직접 동작을 확인하려면 오실로스코프나 로직 아날라이저를 이용하여야 하며, 다른 방법으로 확인하려면 별도의 추가 코드가 필요하다.

2. USCI_B0를 이용한 3-wire 통신 (Slave)

USCI_B0를 이용하여 SPI를 Slave 모드로 사용하는 예제이다. 총 3개의 라인을 사용한다.

  • P1.7 <- Data In (UCB0SIMO)
  • P1.6 -> Data Out (UCB0SOMI)
  • P1.5 -> Serial Clock In (UCABCLK)
#include <msp430.h>

int main(void)
{
    WDTCTL = WDTPW + WDTHOLD;            // Stop watchdog timer
    while (!(P1IN & BIT4));              // If clock sig from mstr stays low,
                                         // it is not yet in SPI mode

    P1SEL = BIT7 + BIT6 + BIT5;
    P1SEL2 = BIT7 + BIT6 + BIT5;
    UCB0CTL1 = UCSWRST;                  // **Put state machine in reset**
    UCB0CTL0 |= UCCKPL + UCMSB + UCSYNC; // 3-pin, 8-bit SPI master
    UCABCTL1 &= ~UCSWRST;                // **Initialize USCI state machine**
    IE2 |= UCA0RXIE;                     // Enable USCI0 RX interrupt

    __bis_SR_register(LPM4_bits + GIE);  // Enter LPM4, enable interrupts
}

#pragma vector=USCIAB0RX_VECTOR          // Echo character
__interrupt void USCI0RX_ISR (void)
{
    while (!(IFG2 & UCB0TXIFG));         // USCI_B0 TX buffer ready?
    UCA0TXBUF = UCB0RXBUF;
}

코드를 실행하면 마스터로부터 받은 데이터를 그대로 다시 전달하는 것을 볼 수 있다. 마찬가지로 직접 동작을 확인하려면 오실로스코프나 로직 아날라이저를 이용하여야 하며, 다른 방법으로 확인하려면 별도의 추가 코드가 필요하다.

profile
개발자입니당 *^^* 깃허브 https://github.com/pikamonvvs

0개의 댓글