[MSP430]/MSP430F20132009. 3. 18. 21:34

MSP430 I2C 전송 속도 테스트

MSP430 I2C 전송 속도 테스트




MSP430F2013 보드는 UART가 없어 I2C로 데이터를 수집테스트 정리

구성도
MSP430F2013 (I2C Slave) ->AVR (I2C Master) -> USB2Serial -> PC Host



AVR - > 8Mhz 구동
MSP430F2013 -> 16Mhz구동

2Byte 데이터 수집 속도 측정


H/W 구동시

100Khz
구동시 450us 소요된다.

150Khz 까지 구동 가능하고 이때는 300us 소요된다. (200Khz 이상부터 깨지기 시작한다.)

->메인클럭을 16Mhz까지 올리니 400khz도 문제 없이 잘 동작한다.
 

S/W I2C 구현시
AVR 8Mhz클럭에서  600us 소요된다.

 


H/W I2C
구현 예제

unsigned char ReadByte8( unsigned char add)

{

           unsigned char data_in = 0;

          

           i2c_start_wait(add);

           data_in = i2c_readAck(); 

           i2c_stop();

 

           return (data_in);

}

 

S/W I2C 구현 예제

unsigned char ReadByte8( unsigned char add)

{

           unsigned char data_in = 0;

          

           I2C_Start();

           #if _USE_I2C_DELAY

           Delay_us(I2C_DELAY);

           #endif

 

           I2C_PutByte(add);

           #if _USE_I2C_DELAY

           Delay_us(I2C_DELAY+10);

           #endif  

           I2C_Nack();

 

           #if _USE_I2C_DELAY       

           Delay_us(I2C_DELAY);

           #endif

 

           data_in = I2C_GetByte();

           #if _USE_I2C_DELAY

           Delay_us(I2C_DELAY);

           #endif

           I2C_Nack();

 

           //Delay_us(100);

           I2C_Stop();

 

           return (data_in);

}

Posted by nexp

댓글을 달아 주세요

[MSP430]/MSP430F20132009. 3. 6. 18:27

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
 }
}
Posted by nexp

댓글을 달아 주세요

[DATA]/ElectPart2008. 4. 7. 10:02

[ PCA9539 ] I2C to Parallel Port Expander

[ PCA9539 ] I2C to Parallel Port Expander
 
Posted by nexp
TAG I2C

댓글을 달아 주세요

[ST_MICRO]/STM322008. 2. 25. 07:57

[STM32] I2C테스트

STM32 I2C테스트
 
일단 STM32 I2C 테스트 하면서 필요한 사항을 정리해 본다.
 
STM32와 MSP430(2013)을 이용하한 기본 I2C 테스트 보드
 
 
테스트 예제소스
 
STM32 유저 가이드
 

I2C블럭도
STM32는 2개의 I2C모듈이 있고 그림과 같은 블록도로
 
I2C1
PB6 - SCL
PB7 - SDA
 
I2C2
PB10 - SCL
PB11 - SDA
 
 
초기화
void i2c_init(void)
{
    I2C_InitTypeDef  I2C_InitStructure; 
 
 //1)클럭 초기화 I2C1 and Periph clock enable
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);   
 //GPIOB Periph clock enable
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
 
 //2)Configure I2C2 pins: SCL and SDA
 GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_10 | GPIO_Pin_11;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
 GPIO_Init(GPIOB, &GPIO_InitStructure);
 
 //3)I2C1 configuration
 I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
 I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
 I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
 //  I2C_InitStructure.I2C_OwnAddress1 = I2C1_SLAVE_ADDRESS7; 
 I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
 I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;
 I2C_Init(I2C2, &I2C_InitStructure);
 
 I2C_Cmd(I2C_ID, ENABLE);
}
 
 
I2C 프로토콜
 

 
I2C Read 동작
아래 블럭도와 같이 코딩을하면된다.
 

STM32 I2C를 테스트 하면가 가장 고생했던 점은 처음 한번은 잘 동작하고 어떨때 Read가 되지 않은 현상 발생 한다.
코드상 문제는 없는데... 딜레이도 주고 여러가지 다 해봤지만 원인을 찾을 수가 없었다.  
결국 2일을 고생하고 찾아낸 결론은 I2C_Cmd() 함수로 리셋을 해주면 문제없이 잘 동작한다. 그래서 i2c_start()함수 초기에 항상 리셋을 걸고 있다
 
unsigned char i2c_start(unsigned char address)
{
 I2C_Cmd(I2C_ID, DISABLE);
 I2C_Cmd(I2C_ID, ENABLE);
 
 
큰 부하는 아니지만 속도가 문제라면 함수가 아니라 메크로로 정의해 둘수도 있겠다.
 
 #define CR1_PE_Set              ((u16)0x0001)
 #define CR1_PE_Reset            ((u16)0xFFFE)

 I2C_ID->CR1 = CR1_PE_Reset;
 I2C_ID->CR1 = CR1_PE_Set; 
 



STM32 I2C에서 또한번 나를 당혹하게한다.
I2C를 이용하는 센서 테스트중 Read시에 EV7체크하는 부분이 있는데... 아무리해도 이 값이 세트되지 않는 현상이 발생하기에 Address Write이후 EV6 체크하는 부분을 삭제하니 정상동작한다.
이게 무슨일인지...다른 MCU에서 잘동작히니 디바이스 문제는 아닌것 같고... 아무튼 해결은 되었지만 맘에 들지 않는다
 
ST예제 STM32 I2C 코드
  /* Send address for read */
  I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Receiver);
 
  /* Test on EV6 and clear it */
 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
 
 while(NumByteToRead) 
 {
    /* Test on EV7 and clear it */
    if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) 
    {     
      /* Read a byte from the EEPROM */
      *pBuffer = I2C_ReceiveData(I2C1);
 
 
 
내가 수정한 STM32 I2C코드
 //Send address for read
 I2C_Send7bitAddress(I2C_ID, LIS3L02_I2C_ADDR, I2C_Direction_Receiver);
 
 //Test on EV6 and clear it
 while(!I2C_CheckEvent(I2C_ID, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
 
    while(1) 
    {
        //Test on EV7 and clear it
        if(I2C_CheckEvent(I2C_ID, I2C_EVENT_MASTER_BYTE_RECEIVED)) 
        {     
            data = I2C_ReceiveData(I2C_ID);
            break;
        }  
    }




이상하게 STM32 I2C에만 문제가 있네...
연속적인데이터를 수집하려하니 문제가 있다. start()에서 100us정도의 딜레이를 주니 잘동작은 하는데... 아무래도 나중에 속도문제가 될것 같다...
 
unsigned char i2c_start(unsigned char address)
{
    Delay_us(100); 
      :
}

테스트 동영상
기울기에따라 I2C 가속도센서 데이터를 그래프로 표시



테스트 코드 (STM32 M-Tyep EVM)

Delay없이 사용할 수 있도록 수정한 STM32 최종 I2C start() 함수  소스
unsigned char i2c2_start(unsigned char address)
{
    if(address&I2C_READ)
    {
  /* Send STRAT condition a second time */ 
  I2C_GenerateSTART(I2C2, ENABLE);
  
  /* Test on EV5 and clear it */
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
 
  /* Send EEPROM address for read */
  I2C_Send7bitAddress(I2C2, address-1, I2C_Direction_Receiver);
  /* Test on EV6 and clear it */
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    }
    else
    {
  /* While the bus is busy */
  while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY));
 
  /* Send START condition */
  I2C_GenerateSTART(I2C2, ENABLE);
 
  /* Test on EV5 and clear it */
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
 
  /* Send EEPROM address for write */
  I2C_Send7bitAddress(I2C2, address, I2C_Direction_Transmitter);
  /* Test on EV6 and clear it */
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
  
  /* Clear EV6 by setting again the PE bit */
  I2C_Cmd(I2C2, ENABLE);  
    }  
  
   return 0;  
}
Posted by nexp

댓글을 달아 주세요

  1. 샤인

    관리자의 승인을 기다리고 있는 댓글입니다

    2011.09.16 11:35 [ ADDR : EDIT/ DEL : REPLY ]