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
}
}