📄 i2c.c
字号:
/******************** (C) COPYRIGHT 2010 Embest Info&Tech Co.,LTD. ************
* 文件名: i2c.c
* 作者 : Wuhan R&D Center, Embest
* 日期 : 01/18/2010
* 描述 : NXP LPC11xx 系列处理器 I2C API 文件.
*******************************************************************************
*******************************************************************************
* 历史:
* 01/18/2010 : V1.0 初始版本
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "LPC11xx.h" /* LPC11xx 外设寄存器 */
#include "type.h"
#include "i2c.h"
volatile uint32_t I2CMasterState = I2C_IDLE;
volatile uint32_t I2CSlaveState = I2C_IDLE;
volatile uint32_t I2CMode;
volatile uint8_t I2CMasterBuffer[I2C_BUFSIZE];
volatile uint8_t I2CSlaveBuffer[I2C_BUFSIZE];
volatile uint32_t I2CCount = 0;
volatile uint32_t I2CReadLength;
volatile uint32_t I2CWriteLength;
volatile uint32_t RdIndex = 0;
volatile uint32_t WrIndex = 0;
/*
根据器件的不同,I2C 通信协议也会不同,在一下例子中, 协议还采用重复开始读取数据
或写入到设备:
从主机读:顺序为: STA,Addr(W),offset,RE-STA,Addr(r),data...STO
从主机写:顺序为: STA,Addr(W),offset,RE-STA,Addr(w),data...STO
也既是,在状态 8,地址始终允许写。在状态 10,地址是否允许读写依赖于 I2C 命令。
*/
/**
* 函数名: I2C_IRQHandler
* 描述: I2C 中断处理程序,只在主模式。
* 参数: 无
* 返回值: 无
*/
void I2C_IRQHandler(void)
{
uint8_t StatValue;
/* 该处理程序只在主机读和写时 */
StatValue = LPC_I2C->STAT;
switch ( StatValue )
{
/* 起始条件发出。 */
case 0x08:
WrIndex = 0;
LPC_I2C->DAT = I2CMasterBuffer[WrIndex++];
LPC_I2C->CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);
I2CMasterState = I2C_STARTED;
break;
/* 一个重复开始发出。 */
case 0x10:
RdIndex = 0;
/* 发送 SLA 在 R 位设置 */
LPC_I2C->DAT = I2CMasterBuffer[WrIndex++];
LPC_I2C->CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);
I2CMasterState = I2C_RESTARTED;
break;
/* 忽略, 是 ACK */
case 0x18:
if ( I2CMasterState == I2C_STARTED )
{
LPC_I2C->DAT = I2CMasterBuffer[WrIndex++];
I2CMasterState = DATA_ACK;
}
LPC_I2C->CONCLR = I2CONCLR_SIC;
break;
/* 数据类型传输,不管是 ACK 或者 NACK */
case 0x28:
case 0x30:
if ( WrIndex < I2CWriteLength )
{
/* 这将是最后一个 */
LPC_I2C->DAT = I2CMasterBuffer[WrIndex++];
I2CMasterState = DATA_ACK;
}
else
{
if ( I2CReadLength != 0 )
{
/* 设置重复开始标志 */
LPC_I2C->CONSET = I2CONSET_STA;
I2CMasterState = I2C_REPEATED_START;
}
else
{
I2CMasterState = DATA_NACK;
/* 设置结束标志 */
LPC_I2C->CONSET = I2CONSET_STO;
}
}
LPC_I2C->CONCLR = I2CONCLR_SIC;
break;
/* 主机接收, SLA_R 已经发送 */
case 0x40:
/* 假定数据后的 ACK 已经接收到 */
LPC_I2C->CONSET = I2CONSET_AA;
LPC_I2C->CONCLR = I2CONCLR_SIC;
break;
/* 数据类型已经接收到,无论之后是否有 ACK 或 NACK */
case 0x50:
I2CSlaveBuffer[RdIndex++] = LPC_I2C->DAT;
if ( RdIndex < I2CReadLength )
{
I2CMasterState = DATA_ACK;
}
else
{
I2CMasterState = DATA_NACK;
}
/* 假定数据后的 ACK 已经接收到 */
LPC_I2C->CONSET = I2CONSET_AA;
LPC_I2C->CONCLR = I2CONCLR_SIC;
break;
case 0x58:
I2CSlaveBuffer[RdIndex++] = LPC_I2C->DAT;
I2CMasterState = DATA_NACK;
/* 设置结束标志 */
LPC_I2C->CONSET = I2CONSET_STO;
/* 清除 SI 标志 */
LPC_I2C->CONCLR = I2CONCLR_SIC;
break;
/* 忽略,是一个 NACK */
case 0x20:
case 0x48:
LPC_I2C->CONCLR = I2CONCLR_SIC;
I2CMasterState = DATA_NACK;
break;
case 0x38: /* 仲裁丢失,在该例子中我们不考虑
多主情况 */
default:
LPC_I2C->CONCLR = I2CONCLR_SIC;
break;
}
return;
}
/**
* 函数名: I2CStart
* 描述: 创建 I2C 开始条件,如果 I2C 一直没有开始
* 将会设置一个超时值,并超时。这是一个致命错误
* 参数: 无
* 返回值: 真或假,如果超时返回假
*/
uint32_t I2CStart( void )
{
uint32_t timeout = 0;
uint32_t retVal = FALSE;
/*--- 发出一个开始条件 ---*/
/* 设置开始标志 */
LPC_I2C->CONSET = I2CONSET_STA;
/*--- 等待直到 START 发送完成 ---*/
while( 1 )
{
if ( I2CMasterState == I2C_STARTED )
{
retVal = TRUE;
break;
}
if ( timeout >= MAX_TIMEOUT )
{
retVal = FALSE;
break;
}
timeout++;
}
return( retVal );
}
/**
* 函数名: I2CStop
* 描述: 设置 I2C 结束条件, 如果没有正常退出
* 这是一个致命总线错误。
* 参数: 无
* 返回值:真或永远不返回
*/
uint32_t I2CStop( void )
{
/* 设置停止标志 */
LPC_I2C->CONSET = I2CONSET_STO;
/* 清除 SI 标志 */
LPC_I2C->CONCLR = I2CONCLR_SIC;
/*--- Wait for STOP detected ---*/
while( LPC_I2C->CONSET & I2CONSET_STO );
return TRUE;
}
/**
* 函数名: I2CInit
* 描述: 初始化 I2C 控制器
* 参数: I2c 模式是主模式或从模式之一
* 返回值: 真或假,如果 I2C
* 中断处理程序没有正确安装返回假
*/
uint32_t I2CInit( uint32_t I2cMode )
{
/* bit0 为 I2C 控制位, 不同于
UM.随着 SSP 复位重新测试。 SSP 和 I2C
复位重叠, 目前已知的 bug,SSP 和
I2C 都使用第 0 位使能复位。一旦修复问题,
更改 "#if 1". */
#if 1
LPC_SYSCON->PRESETCTRL |= (0x1<<1);
#else
LPC_SYSCON->PRESETCTRL |= (0x1<<0);
#endif
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<5);
LPC_IOCON->PIO0_4 &= ~0x3F; /* I2C I/O 配置 */
LPC_IOCON->PIO0_4 |= 0x01; /* I2C SCL */
LPC_IOCON->PIO0_5 &= ~0x3F;
LPC_IOCON->PIO0_5 |= 0x01; /* I2C SDA */
/*--- 清除所有标志 ---*/
LPC_I2C->CONCLR = I2CONCLR_AAC | I2CONCLR_SIC | I2CONCLR_STAC | I2CONCLR_I2ENC;
/*--- 重置寄存器 ---*/
#if FAST_MODE_PLUS
LPC_IOCON->PIO0_4 |= (0x1<<9);
LPC_IOCON->PIO0_5 |= (0x1<<9);
LPC_I2C->SCLL = I2SCLL_HS_SCLL;
LPC_I2C->SCLH = I2SCLH_HS_SCLH;
#else
LPC_I2C->SCLL = I2SCLL_SCLL;
LPC_I2C->SCLH = I2SCLH_SCLH;
#endif
if ( I2cMode == I2CSLAVE )
{
LPC_I2C->ADR0 = PCF8594_ADDR;
}
/* Enable the I2C Interrupt */
NVIC_EnableIRQ(I2C_IRQn);
LPC_I2C->CONSET = I2CONSET_I2EN;
return( TRUE );
}
/**
* 函数名: I2CEngine
* 描述: 常规完成 I2C 通信是从开始到结束。所有的
* 阶段步骤都在中断处理程序中处理。
* 在常规调用之前,必须先填充读长度、写长度、
* I2C 主缓冲区和 I2C 命令区域。
* 查阅 i2cmst.c 更多信息。
* 参数: 无
* 返回值: 真或假,只当开始条件没有被产生返回假
*/
uint32_t I2CEngine( void )
{
I2CMasterState = I2C_IDLE;
RdIndex = 0;
WrIndex = 0;
if ( I2CStart() != TRUE )
{
I2CStop();
return ( FALSE );
}
while ( 1 )
{
if ( I2CMasterState == DATA_NACK )
{
I2CStop();
break;
}
}
return ( TRUE );
}
/**
* @}
*/
/**
* @}
*/
/************* (C) COPYRIGHT 2010 Wuhan R&D Center, Embest *****文件结束*******/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -