본문 바로가기

[ST_MICRO]/STM32F1

[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;  
}
반응형