반응형
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;
}
반응형
'Engineer > 소프트웨어 정보' 카테고리의 다른 글
임의 길이의 숫자 데이터를 signed extend number로 표현 (0) | 2020.05.19 |
---|---|
[STM32F103 Series] HSI clock 사용 (내부 8Mhz to 64Mhz) (0) | 2020.02.18 |
[STM32F10x] software I2C example code (2) | 2020.02.04 |
STM32 ARM series 이클립스(Eclipse) 내 GCC 컴파일 개발 환경 구축 (0) | 2020.01.29 |
[STM32F10x] printf() 사용에 따른 default define 및 이슈 (0) | 2020.01.02 |