반응형

STM32F10x series MCU를 사용하면서 제공되는 stm32f10x_i2c.h / stm32f10x_i2c.c 관련 STM32 library를 사용한 hardware I2C example code를 공유한다.

 

# i2c_hw.h

#ifndef __I2C_HW_H
#define __I2C_HW_H

/* includes */
#include "stm32f10x.h"
#include "hw_config.h"
/* defines */
/* functions */
void HW_I2C_master_initial(void);

uint8_t HW_I2C_Read(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint16_t NumByteToRead, uint8_t* pBuffer);
uint8_t HW_I2C_Write(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint16_t NumByteToWrite, uint8_t* pBuffer);
uint8_t I2C_Check_SlaveAddr(I2C_TypeDef* I2Cx, uint8_t DeviceAddr);

uint8_t HW_I2C_UTIL_Write(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint8_t pBuffer);
uint8_t HW_I2C_UTIL_Read(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr);
void HW_I2C_UTIL_Write_Multi(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint16_t NumByteToWrite, uint8_t* pBuffer);
uint8_t HW_I2C_UTIL_Read_Multi(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint8_t ReadCount, uint8_t (*pReadData));
uint8_t HW_I2C_UTIL_Check_SlaveAddr(I2C_TypeDef* I2Cx);

#endif  /* __I2C_HW_H */

 

# i2c_hw.c

#include "i2c_hw.h"

#define MAX_COMMUNICATION_FREQ   ((uint32_t) 400000)	// 100khz
#define FLAG_TIMEOUT             ((uint32_t)0x1000)
#define LONG_TIMEOUT             ((uint32_t)(10 * FLAG_TIMEOUT))

#define GPIO_I2C_HW        GPIOB

#define GPIO_I2C1_SCL	GPIO_Pin_6
#define GPIO_I2C1_SDA	GPIO_Pin_7
#define GPIO_I2C2_SCL	GPIO_Pin_10
#define GPIO_I2C2_SDA	GPIO_Pin_11

__IO uint32_t  UTIL_Timeout = LONG_TIMEOUT;
__IO uint16_t  UTIL_Address = 0;

void HW_I2C_master_initial(void)
{
	I2C_InitTypeDef 	I2C_InitStructure;
	GPIO_InitTypeDef	GPIO_InitStructure;

	// I2C_SCL_GPIO_CLK and I2C_SDA_GPIO_CLK Periph clock enable
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	// I2C Periph clock enable
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);

	// Configure I2C pins: SCL , SDA
	GPIO_InitStructure.GPIO_Pin = GPIO_I2C1_SCL | GPIO_I2C1_SDA | GPIO_I2C2_SCL | GPIO_I2C2_SDA;;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_Init(GPIO_I2C_HW, &GPIO_InitStructure);

	// Free all used resources
	I2C_DeInit(I2C1);
	I2C_DeInit(I2C2);

	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_InitStructure.I2C_OwnAddress1 = 0x00;
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_ClockSpeed = MAX_COMMUNICATION_FREQ;
	I2C_Init(I2C1, &I2C_InitStructure);
	I2C_Init(I2C2, &I2C_InitStructure);

	I2C_Cmd(I2C1, ENABLE);
	I2C_Cmd(I2C2, ENABLE);
}

uint8_t HW_I2C_Read(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint16_t NumByteToRead, uint8_t* pBuffer)
{
  __IO uint32_t UTIL_Timeout = LONG_TIMEOUT;
  __IO uint32_t temp;

  (void)(temp);

restart:

  UTIL_Timeout = LONG_TIMEOUT;
/* Send START condition */
  I2C_GenerateSTART(I2Cx, ENABLE);
  /* Test on EV5 and clear it */
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
  {
    if (UTIL_Timeout-- == 0)
      return ERROR;
  }

  UTIL_Timeout = LONG_TIMEOUT;
  /* Send slave address for read */
  I2C_Send7bitAddress(I2Cx, DeviceAddr, I2C_Direction_Transmitter);

  while (!I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
  {
    if (UTIL_Timeout-- == 0)
    {
      I2C_ClearFlag(I2Cx,I2C_FLAG_BUSY|I2C_FLAG_AF);
      goto restart;
    }
  }
  /* Clear EV6 by setting again the PE bit */
  I2C_Cmd(I2Cx, ENABLE);

  I2C_SendData(I2Cx, RegisterAddr);

  /* Test on EV8 and clear it */
  UTIL_Timeout = LONG_TIMEOUT;
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  {
    if (UTIL_Timeout-- == 0)
     return ERROR;
  }

  if (NumByteToRead == 0x01)
  {
    restart3:
    /* Send START condition */
    I2C_GenerateSTART(I2Cx, ENABLE);
    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
    /* Send Slave address for read */
    I2C_Send7bitAddress(I2Cx, DeviceAddr, I2C_Direction_Receiver);
    /* Wait until ADDR is set */
    UTIL_Timeout = LONG_TIMEOUT;
    while (!I2C_GetFlagStatus(I2Cx, I2C_FLAG_ADDR))
    {
      if (UTIL_Timeout-- == 0)
      {
        I2C_ClearFlag(I2Cx,I2C_FLAG_BUSY|I2C_FLAG_AF);
        goto restart3;
      }
    }
    /* Clear ACK */
    I2C_AcknowledgeConfig(I2Cx, DISABLE);
    __disable_irq();
    /* Clear ADDR flag */
    temp = I2Cx->SR2;
    /* Program the STOP */
    I2C_GenerateSTOP(I2Cx, ENABLE);
    __enable_irq();
    while ((I2C_GetLastEvent(I2Cx) & 0x0040) != 0x000040); /* Poll on RxNE */
    /* Read the data */
    *pBuffer = I2C_ReceiveData(I2Cx);
    /* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
    while ((I2Cx->CR1&0x200) == 0x200);
    /* Enable Acknowledgement to be ready for another reception */
    I2C_AcknowledgeConfig(I2Cx, ENABLE);

    return SUCCESS;
  }
  else
    if(NumByteToRead == 0x02)
    {
      restart4:
      /* Send START condition */
      I2C_GenerateSTART(I2Cx, ENABLE);
      while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
      /* Send EEPROM address for read */
      I2C_Send7bitAddress(I2Cx, DeviceAddr, I2C_Direction_Receiver);
      I2Cx->CR1 = 0xC01; /* ACK=1; POS =1 */
      UTIL_Timeout = LONG_TIMEOUT;
      while (!I2C_GetFlagStatus(I2Cx, I2C_FLAG_ADDR))
      {
        if (UTIL_Timeout-- == 0)
        {
          I2C_ClearFlag(I2Cx,I2C_FLAG_BUSY|I2C_FLAG_AF);
          goto restart4;
        }
      }
      __disable_irq();
      /* Clear ADDR */
      temp = I2Cx->SR2;
      /* Disable ACK */
      I2C_AcknowledgeConfig(I2Cx, DISABLE);
      __enable_irq();
      while ((I2C_GetLastEvent(I2Cx) & 0x0004) != 0x00004); /* Poll on BTF */

       __disable_irq();
      /* Program the STOP */
      I2C_GenerateSTOP(I2Cx, ENABLE);
      /* Read first data */
      *pBuffer = I2Cx->DR;
      pBuffer++;
      /* Read second data */
      *pBuffer = I2Cx->DR;
      __enable_irq();
      I2Cx->CR1 = 0x0401; /* POS = 0, ACK = 1, PE = 1 */

      return SUCCESS;
    }
  else
  {
restart2:
    UTIL_Timeout = LONG_TIMEOUT;
    /* Send START condition */
    I2C_GenerateSTART(I2Cx, ENABLE);
    /* Test on EV5 and clear it */
    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
    {
      if (UTIL_Timeout-- == 0) return ERROR;
    }
    UTIL_Timeout = LONG_TIMEOUT;
    /* Send slave address for read */
    I2C_Send7bitAddress(I2Cx,  DeviceAddr, I2C_Direction_Receiver);
    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
    {

      if (UTIL_Timeout-- == 0)
      {
        I2C_ClearFlag(I2Cx,I2C_FLAG_BUSY|I2C_FLAG_AF);
        goto restart2;
      }
    }

    /* While there is data to be read; here the safe procedure is implemented */
    while (NumByteToRead)
    {

      if (NumByteToRead != 3) /* Receive bytes from first byte until byte N-3 */
      {
        while ((I2C_GetLastEvent(I2Cx) & 0x00004) != 0x000004); /* Poll on BTF */
        /* Read data */
        *pBuffer = I2C_ReceiveData(I2Cx);
        pBuffer++;
        /* Decrement the read bytes counter */
        NumByteToRead--;
      }

      if (NumByteToRead == 3)  /* it remains to read three data: data N-2, data N-1, Data N */
      {

        /* Data N-2 in DR and data N -1 in shift register */
        while ((I2C_GetLastEvent(I2Cx) & 0x000004) != 0x0000004); /* Poll on BTF */
        /* Clear ACK */
        I2C_AcknowledgeConfig(I2Cx, DISABLE);
        __disable_irq();
        /* Read Data N-2 */
        *pBuffer = I2C_ReceiveData(I2Cx);
        pBuffer++;
        /* Program the STOP */
        I2C_GenerateSTOP(I2Cx, ENABLE);
        /* Read DataN-1 */
        *pBuffer = I2C_ReceiveData(I2Cx);
        __enable_irq();
        pBuffer++;
        while ((I2C_GetLastEvent(I2Cx) & 0x00000040) != 0x0000040); /* Poll on RxNE */
        /* Read DataN */
        *pBuffer = I2Cx->DR;
        /* Reset the number of bytes to be read by master */
        NumByteToRead = 0;
      }
    }
    /* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
    while ((I2Cx->CR1&0x200) == 0x200);
    /* Enable Acknowledgement to be ready for another reception */
    I2C_AcknowledgeConfig(I2Cx, ENABLE);

    return SUCCESS;
  }
}

uint8_t HW_I2C_Write(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr,
                               uint16_t NumByteToWrite,
                               uint8_t* pBuffer)
{

 restart1:
  UTIL_Timeout = LONG_TIMEOUT;
  /* Send START condition */
  I2C_GenerateSTART(I2Cx, ENABLE);
  /* Test on EV5 and clear it */
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
  {
    if (UTIL_Timeout-- == 0) return ERROR;
  }
  /* Send slave address for write */
  I2C_Send7bitAddress(I2Cx, DeviceAddr, I2C_Direction_Transmitter);

  UTIL_Timeout = LONG_TIMEOUT;
  /* Test on EV6 and clear it */
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
  {

    if (UTIL_Timeout-- == 0)
    {
      I2C_ClearFlag(I2Cx,I2C_FLAG_BUSY|I2C_FLAG_AF);
      goto restart1;
    }
  }

  UTIL_Timeout = LONG_TIMEOUT;

  /* Transmit the first address for r/w operations */
  I2C_SendData(I2Cx, RegisterAddr);

  /* Test on EV8 and clear it */
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  {
    if (UTIL_Timeout-- == 0)
      return ERROR;
  }
  if (NumByteToWrite == 0x01)
  {
    UTIL_Timeout = LONG_TIMEOUT;
    /* Prepare the register value to be sent */
    I2C_SendData(I2Cx, *pBuffer);

    /* Test on EV8 and clear it */
    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
    {
      if (UTIL_Timeout-- == 0)
        return ERROR;
    }

    /* End the configuration sequence */
    I2C_GenerateSTOP(I2Cx, ENABLE);
    return SUCCESS;
  }
  I2C_SendData(I2Cx, *pBuffer);
  pBuffer++;
  NumByteToWrite--;
  /* While there is data to be written */
  while (NumByteToWrite--)
  {
    while ((I2C_GetLastEvent(I2Cx) & 0x04) != 0x04);  /* Poll on BTF */
    /* Send the current byte */
    I2C_SendData(I2Cx, *pBuffer);
    /* Point to the next byte to be written */
    pBuffer++;

  }
  UTIL_Timeout = LONG_TIMEOUT;
  /* Test on EV8_2 and clear it, BTF = TxE = 1, DR and shift registers are
   empty */
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  {
    if (UTIL_Timeout-- == 0) return ERROR;
  }
  /* Send STOP condition */
  I2C_GenerateSTOP(I2Cx, ENABLE);
  return SUCCESS;
}

uint8_t I2C_Check_SlaveAddr(I2C_TypeDef* I2Cx, uint8_t DeviceAddr)
{
	uint8_t   returnack = SUCCESS;

	UTIL_Timeout = FLAG_TIMEOUT;
	/* Send START condition */
	I2C_GenerateSTART(I2Cx, ENABLE);
	/* Test on EV5 and clear it */
	while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
	{
		if (UTIL_Timeout-- == 0) return ERROR;
	}
	/* Send slave address for write */
	I2C_Send7bitAddress(I2Cx, DeviceAddr, I2C_Direction_Transmitter);

	UTIL_Timeout = FLAG_TIMEOUT;
	/* Test on EV6 and clear it */
	while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
	{

		if (UTIL_Timeout-- == 0)
		{
		  I2C_ClearFlag(I2Cx,I2C_FLAG_BUSY|I2C_FLAG_AF);
		  returnack = ERROR;
		  break;
		}
	}
	I2C_GenerateSTOP(I2Cx, ENABLE);

	return returnack;
}

uint8_t HW_I2C_UTIL_Write(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint8_t pBuffer)
{
	return HW_I2C_Write(I2Cx, DeviceAddr<<1,RegisterAddr,1,&pBuffer);
}

uint8_t HW_I2C_UTIL_Read(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr)
{
	uint8_t	pBuffer;

	HW_I2C_Read(I2Cx, DeviceAddr<<1,RegisterAddr,1,&pBuffer);

	return pBuffer;
}

void HW_I2C_UTIL_Write_Multi(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint16_t NumByteToWrite, uint8_t* pBuffer)
{
	HW_I2C_Write(I2Cx, DeviceAddr<<1,RegisterAddr,NumByteToWrite,pBuffer);
}

uint8_t HW_I2C_UTIL_Read_Multi(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint8_t ReadCount, uint8_t (*pReadData))
{
	HW_I2C_Read(I2Cx, DeviceAddr<<1,RegisterAddr,ReadCount,pReadData);

	return 1;
}

uint8_t HW_I2C_UTIL_Check_SlaveAddr(I2C_TypeDef* I2Cx)
{
	uint8_t i = 0x00;

	for(i = 0; i < 255; i++)
	{
		if(I2C_Check_SlaveAddr(I2Cx, i) == SUCCESS)
		{
			return i;
		}
	}
	return i;
}
반응형

+ Recent posts