[MSP430] USCI-I2C

pikamon·2020년 12월 24일
0

MSP430

목록 보기
10/13

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


1. USCI-I2C란?

I2C는 Inter Integrated Circuit(IIC)의 약자이며, UART, SPI와 마찬가지로 칩 간에 데이터를 주고 받기 위한 시리얼 통신 프로토콜이다. 필립스 사에서 개발하였으며, 2개의 라인만으로도 통신이 가능하다는 것이 특징이다. 마스터-슬레이브 모델을 따르며, 일대다 통신이 가능하다.

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

I2C는 USCI_B에서만 지원하기 때문에, USCI_B 모듈의 레지스터를 이용하여 사용하면 된다.

2. USCI-I2C 특징

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

  • Compliance to the Philips Semiconductor I2C specification v2.1
    • 7-bit and 10-bit device addressing modes
    • General call
    • START / RESTART / STOP
    • Multi-master transmitter/receiver mode
    • Slave receiver/transmitter mode
    • Standard mode up to 100 kbps and fast mode up to 400 kbps support
  • Programmable UCxCLK frequency in master mode
  • Designed for low power
  • Slave receiver START detection for auto-wake up from LPMx modes
  • Slave operation in LPM4

하나씩 살펴보자.

  • Compliance to the Philips Semiconductor I2C specification v2.1

필립스 I2C v2.1 버전 스펙을 지원한다고 한다.

  • Designed for low power
  • Slave receiver START detection for auto-wake up from LPMx modes
  • Slave operation in LPM4

저전력 모드와 관련된 내용이다. 저전력 구동이 가능하며, SPI와 마찬가지로 LPM4 모드에서 슬레이브 모드로 동작이 가능하고, 저전력 모드에서 슬레이브 수신 START 검출 기능이 제공된다.

위 세 기능을 동시에 이용하면, MSP430을 I2C 슬레이브 모드로 사용할 경우, 명령어 수신 시에만 잠시 CPU를 wake-up 시켰다가, 나머지 시간에는 다시 CPU를 꺼놓는 것이 가능해진다.

3. USCI-I2C 다이어그램

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

전체적인 구성은 이전 USCI-UART와 USCI-SPI에서 본 것과 비슷하다. 차이점 위주로 살펴보자면, 송수신 라인이 별도로 존재했던 UART, SPI와는 달리 I2C는 하나의 데이터 라인에 TX와 RX가 모두 붙어있다. 상태 머신도 I2C에는 없는 것을 볼 수 있다.

4. 관련 레지스터

USCI-I2C와 관련된 레지스터는 아래와 같다.

  • UCBxCTLy - USCI_Bx control register
  • UCBxBRy - USCI_Bx bit rate control register
  • UCBxI2CIE - USCI_Bx I2C interrupt enable register
  • UCBxSTAT - USCI_Bx status register
  • UCBxRXBUF - USCI_Bx receive buffer register
  • UCBxTXBUF - USCI_Bx transmit buffer register
  • UCBxI2COA - USCI_Bx I2C own address register
  • UCBxI2CSA - USCI_Bx I2C slave address register
  • IE2 - SFR interrupt enable register 2
  • IFG2 - SFR interrupt flag register 2
  • UC1IE - USCI_A1/B1 interrupt enable register
  • UC1IFG - USCI_A1/B1 interrupt flag register

필자도 각 레지스터들의 명세를 모두 알진 못하므로, 필요할 때마다 참고하는 것을 권한다.

1. UCBxCTLy

I2C 초기화를 위한 레지스터이다.

2. UCBxBRy

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

3. UCBxI2CIE

I2C 통신 시작, 종료에 따른 인터럽트 활성화를 관리하는 레지스터이다.

4. UCBxSTAT

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

5. UCBxRXBUF

I2C RX 버퍼 레지스터이다.

6. UCBxTXBUF

I2C TX 버퍼 레지스터이다.

7. UCBxI2COA

디바이스의 I2C 어드레스를 저장하는 레지스터인 것 같다.

8. UCBxI2CSA

마스터 모드에서 사용할 슬레이브 디바이스의 어드레스를 저장하는 레지스터인 것 같다.

9. IE2

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

10. IFG2

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

11. UC1IE

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

12. UC1IFG

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

5. 준비물

두 칩 간의 I2C 통신을 하기 위해선 두 개의 MCU가 필요하다. 여분의 MSP430 보드를 가지고 있다면 사용하는 것을 권장한다. 필자는 집에 여분이 없어서 라즈베리파이를 사용하였다. 혹시나 필자처럼 라즈베리파이를 쓰는 사람이 있을까봐 예제에 라즈베리파이용 소스 코드를 함께 첨부하였다.

6. 예제

예제를 다루어보자. I2C를 통해 센서를 제어하는 예제들은 별도의 센서가 필요하므로 본 글에서 제외하였다.

  • I2C Master 모드
  • I2C Slave 모드

1. I2C Master 모드

MCU를 I2C 마스터로 동작시키는 예제이다. 슬레이브에 지속적으로 I2C 전송을 요청하며, 슬레이브로부터 받은 값을 RXCompare 값과 비교한다. UCB0를 사용하며, UCB0를 I2C로 사용할 경우 핀 맵은 아래와 같다.

  • P1.7 <-> UCB0SDA
  • P1.6 -> UCB0SCL
#include <msp430.h>

unsigned char RXData, RXCompare;

int main(void)
{
    WDTCTL = WDTPW + WDTHOLD;             // Stop WDT

    P1OUT &= ~BIT0;                       // P1.0 = 0
    P1DIR |= BIT0;                        // P1.0 output
    P1SEL |= BIT6 + BIT7;                 // Assign I2C pins to USCI_B0
    P1SEL2 |= BIT6 + BIT7;                // Assign I2C pins to USCI_B0

    UCB0CTL1 |= UCSWRST;                  // Enable SW reset
    UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
    UCB0CTL1 = UCSSEL_2 + UCSWRST;        // Use SMCLK, keep SW reset
    UCB0BR0 = 12;                         // fSCL = SMCLK/12 = ~100kHz
    UCB0BR1 = 0;
    UCB0I2CSA = 0x048;                    // Slave Address is 048h
    UCB0CTL1 &= ~UCSWRST;                 // Clear SW reset, resume operation
    IE2 |= UCB0RXIE;                      // Enable RX interrupt

    RXCompare = 0;                        // Used to check incoming data

    while (1)
    {
        while (UCB0CTL1 & UCTXSTP);       // Ensure stop condition got sent
        UCB0CTL1 |= UCTXSTT;              // I2C start condition
        while (UCB0CTL1 & UCTXSTT);       // Start condition sent?
        UCB0CTL1 |= UCTXSTP;              // I2C stop condition
        __bis_SR_register(CPUOFF + GIE);  // Enter LPM0 w/ interrupts

        if (RXData != RXCompare)          // Trap CPU if wrong
        {
            P1OUT |= BIT0;                // P1.0 = 1
            while (1);                    // Trap CPU
        }

        RXCompare++;                      // Increment correct RX value
    }
}

#pragma vector = USCIAB0TX_VECTOR         // USCI_B0 Data ISR
__interrupt void USCIAB0TX_ISR(void)
{
    RXData = UCB0RXBUF;                   // Get RX data
    __bic_SR_register_on_exit(CPUOFF);    // Exit LPM0
}

본 예제의 동작을 확인하려면 I2C 슬레이브 모드로 예제 2의 코드를 실행하는 또 하나의 MCU가 필요하다. 집에 MSP430 보드가 두 개 있다면, 다른 하나를 슬레이브용으로 사용하면 된다.

2. I2C Slave 모드

MCU를 I2C 슬레이브로 동작시키는 예제이다. I2C RX를 받을 때마다 인터럽트가 동작하며, TXData의 값을 1씩 증가시켜 반환한다. UCB0를 사용하며, UCB0를 I2C로 사용할 경우 핀 맵은 아래와 같다.

  • P1.7 <-> UCB0SDA
  • P1.6 <- UCB0SCL
#include <msp430.h>

unsigned char TXData;

int main(void)
{
    WDTCTL = WDTPW + WDTHOLD;            // Stop WDT
    P1DIR |= BIT0;                       // P1.0 output
    P1SEL |= BIT6 + BIT7;                // Assign I2C pins to USCI_B0
    P1SEL2|= BIT6 + BIT7;                // Assign I2C pins to USCI_B0

    UCB0CTL1 |= UCSWRST;                 // Enable SW reset
    UCB0CTL0 = UCMODE_3 + UCSYNC;        // I2C Slave, synchronous mode
    UCB0I2COA = 0x48;                    // Own Address is 048h
    UCB0CTL1 &= ~UCSWRST;                // Clear SW reset, resume operation
    UCB0I2CIE |= UCSTTIE;                // Enable STT interrupt
    IE2 |= UCB0TXIE;                     // Enable TX interrupt
    TXData = 0xff;                       // Used to hold TX data

    while (1)
    {
        __bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
    }
}

#pragma vector = USCIAB0TX_VECTOR        // USCI_B0 Data ISR
__interrupt void USCIAB0TX_ISR(void)
{
    UCB0TXBUF = TXData;                  // TX data
    __bic_SR_register_on_exit(CPUOFF);   // Exit LPM0
}

#pragma vector = USCIAB0RX_VECTOR        // USCI_B0 State ISR
__interrupt void USCIAB0RX_ISR(void)
{
    UCB0STAT &= ~UCSTTIFG;               // Clear start condition int flag
    TXData++;                            // Increment data
}

마찬가지로 동작을 확인하려면 I2C 마스터가 필요하며, 별도의 MSP430이나 적절한 대용을 구하여 이용한다. 실제 I2C 파형을 확인하려면 오실로스코프나 로직 아날라이저를 이용하여야 하며, 다른 방법으로 확인하려면 별도의 추가 코드가 필요하다.

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

0개의 댓글