본문 바로가기

[MSP430]/MSP430F2013

MSP430 I2C 테스트 - USCI(H/W SM) vs USI (MSP430F2013 S/W SM I2C)

Universal Serial Interface
MSP430F2013은 USI모듈로 SPI, I2C인터페이스를 제공한다. I2C는 USCI를 지원하는 상위 MSP430과 같은 풀 하드웨어로 동작하는것은 아니고 소프트웨어 State Machine를 구현해야 한다. 이때문에 약간 귀찮은 작업을 해 주어야 한다. 물론 속도도 느려지지만 그나마 소형 모듈에서 쉽게 구현할 수 있다는 장점이 있다.



소프트웨어 SM 구조


Slave 구현
1)Master에서 Start + (7bit+1bit)Address를 전송하고  NACK를 기다린다.
2)Slave에서 Address가 맞으면 NACK를 전송한다.
3)Slave에서 Data 전송한다.
4)Master에서 Data수신후 NACK를 송신
5)Slave에서 NACK수신
6)Slave에서 STOP수신(옵션)



MSP430F2013 I2C Slave SM소스코드
//******************************************************
// USI interrupt service routine
//******************************************************
#pragma vector = USI_VECTOR
__interrupt void USI_TXRX (void)
{
  if (USICTL1 & USISTTIFG)             // Start entry?
  {
    I2C_State = 2;                     // Enter 1st state on start
  }

  switch(I2C_State)
    {
      case 0: //Idle, should not get here
              break;

      case 2: //RX Address
              USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, RX Address
              USICTL1 &= ~USISTTIFG;   // Clear start flag
              I2C_State = 4;           // Go to next state: check address
              break;

      case 4: // Process Address and send (N)Ack
              if (USISRL & 0x01)       // If read...
                SLV_Addr++;            // Save R/W bit
              USICTL0 |= USIOE;        // SDA = output
              if (USISRL == SLV_Addr)  // Address match?
              {
                USISRL = 0x00;         // Send Ack
                I2C_State = 8;         // Go to next state: TX data
              }
              else
              {
                USISRL = 0xFF;         // Send NAck
                P1OUT |= 0x01;         // LED on: error
                I2C_State = 6;         // Go to next state: prep for next Start
              }
              USICNT |= 0x01;          // Bit counter = 1, send (N)Ack bit
              break;

      case 6: // Prep for Start condition
              USICTL0 &= ~USIOE;       // SDA = input
              SLV_Addr = 0x90;         // Reset slave address
              I2C_State = 0;           // Reset state machine
              break;

      case 8: // Send Data byte
              USICTL0 |= USIOE;        // SDA = output
              USISRL = SLV_Data;       // Send data byte
              USICNT |=  0x08;         // Bit counter = 8, TX data
              I2C_State = 10;          // Go to next state: receive (N)Ack
              break;

      case 10:// Receive Data (N)Ack
              USICTL0 &= ~USIOE;       // SDA = input
              USICNT |= 0x01;          // Bit counter = 1, receive (N)Ack
              I2C_State = 12;          // Go to next state: check (N)Ack
              break;

      case 12:// Process Data Ack/NAck
              if (USISRL & 0x01)       // If Nack received...
              {
              }
              else                     // Ack received
              {
                SLV_Data++;            // Increment Slave data
              }
              // Prep for Start condition
              USICTL0 &= ~USIOE;       // SDA = input
              SLV_Addr = 0x90;         // Reset slave address
              I2C_State = 0;           // Reset state machine
              break;
    }

  USICTL1 &= ~USIIFG;                  // Clear pending flags
}



참고로 USCI를 제공하는 MSP430F16x의 I2C구조이다. 외쪽 중앙에 하드웨어 I2C SM모듈이 들어가 있다.



실제 코드를 보면 I2C를 상당히 간단하게 제어할 수 있다.
// Common ISR for I2C Module
#pragma vector=USART0TX_VECTOR
__interrupt void I2C_ISR(void)
{
 switch(I2CIV)
 {
   case  0: break;                          // No interrupt
   case  2: break;                          // Arbitration lost
   case  4: break;                          // No Acknowledge
   case  6: break;                          // Own Address
   case  8: break;                          // Register Access Ready
   case 10:                                 // Receive Ready
     RXData = I2CDRB;                       // RX data
     _BIC_SR_IRQ(CPUOFF);                   // Clear LPM0
     break;
   case 12: break;                          // Transmit Ready
   case 14: break;                          // General Call
   case 16: break;                          // Start Condition
 }
}
반응형