|
IIC.c文件:
/*****************************************************************************
* i2c.c: I2C C file for NXP LPC11xx Family Microprocessors
*
* Copyright(C) 2008, NXP Semiconductor
* All rights reserved.
*
* History
* 2008.07.19 ver 1.00 Preliminary version, first Release
*
*****************************************************************************/
#include "LPC11xx.h" /* LPC11xx Peripheral Registers */
#include "type.h"
#include "i2c.h"
#include "Delay.h"
volatile uint32_t I2CMasterState = I2C_IDLE;
volatile uint32_t I2CSlaveState = I2C_IDLE;
volatile uint32_t I2CMode;
volatile uint8_t I2CMasterBuffer[I2C_BUFSIZE]={0};
volatile uint8_t I2CSlaveBuffer[I2C_BUFSIZE] ={0};
volatile uint32_t I2CReadLength;
volatile uint32_t I2CWriteLength;
volatile uint32_t RdIndex = 0;
volatile uint32_t WrIndex = 0;
/*
From device to device, the I2C communication protocol may vary,
in the example below, the protocol uses repeated start to read data from or
write to the device:
For master read: the sequence is: STA,Addr(W),offset,RE-STA,Addr(r),data...STO
for master write: the sequence is: STA,Addr(W),offset,RE-STA,Addr(w),data...STO
Thus, in state 8, the address is always WRITE. in state 10, the address could
be READ or WRITE depending on the I2C command.
*/
/*****************************************************************************
** Function name: I2C_IRQHandler
**
** Descriptions: I2C interrupt handler, deal with master mode only.
**
** parameters: None
** Returned value: None
**
*****************************************************************************/
void I2C_IRQHandler(void)
{
uint8_t StatValue;
/* this handler deals with master read and master write only */
StatValue = LPC_I2C->STAT;
switch ( StatValue )
{
/**************** Master write **********************************/
case 0x08: /* A Start condition is issued. */
WrIndex = 0;
LPC_I2C->DAT = I2CMasterBuffer[WrIndex++];
LPC_I2C->CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);
I2CMasterState = I2C_STARTED;
break;
case 0x10: /* A repeated started is issued */
WrIndex = 0;
/* Send SLA with R bit set, */
LPC_I2C->DAT = I2CMasterBuffer[WrIndex++];
LPC_I2C->CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);
I2CMasterState = I2C_RESTARTED;
break;
case 0x18: /* Regardless, it's a ACK */
if ( I2CMasterState == I2C_STARTED )
{
LPC_I2C->DAT = I2CMasterBuffer[WrIndex++];
I2CMasterState = DATA_ACK;
}
LPC_I2C->CONCLR = I2CONCLR_SIC;
break;
case 0x28: /* Data byte has been transmitted, regardless ACK or NACK */
case 0x30:
if ( WrIndex < I2CWriteLength )
{
LPC_I2C->DAT = I2CMasterBuffer[WrIndex++]; /* this should be the last one */
I2CMasterState = DATA_ACK;
}
else
{
if ( I2CReadLength != 0 )
{
LPC_I2C->CONSET = I2CONSET_STA; /* Set Repeated-start flag */
I2CMasterState = I2C_REPEATED_START;
}
else
{
I2CMasterState = DATA_NACK;
LPC_I2C->CONSET = I2CONSET_STO; /* Set Stop flag */
}
}
LPC_I2C->CONCLR = I2CONCLR_SIC;
break;
/**************** Master read *********************************/
case 0x40: /* Master Receive, SLA_R has been sent */
LPC_I2C->CONSET = I2CONSET_AA; /* assert ACK after data is received */
LPC_I2C->CONCLR = I2CONCLR_SIC;
break;
case 0x50: /* Data byte has been received, regardless following ACK or NACK */
I2CSlaveBuffer[RdIndex++] = LPC_I2C->DAT;
if ( RdIndex < I2CReadLength )
{
I2CMasterState = DATA_ACK;
}
else
{
I2CMasterState = DATA_NACK;
}
LPC_I2C->CONSET = I2CONSET_AA; /* assert ACK after data is received */
LPC_I2C->CONCLR = I2CONCLR_SIC;
break;
case 0x58:
I2CSlaveBuffer[RdIndex++] = LPC_I2C->DAT;
I2CMasterState = DATA_NACK;
LPC_I2C->CONSET = I2CONSET_STO; /* Set Stop flag */
LPC_I2C->CONCLR = I2CONCLR_SIC; /* Clear SI flag */
break;
case 0x20: /* regardless, it's a NACK */
case 0x48:
LPC_I2C->CONCLR = I2CONCLR_SIC;
I2CMasterState = DATA_NACK;
break;
case 0x38: /* Arbitration lost, in this example, we don't
deal with multiple master situation */
default:
LPC_I2C->CONCLR = I2CONCLR_SIC;
break;
}
return;
}
/*****************************************************************************
** Function name: I2CStart
**
** Descriptions: Create I2C start condition, a timeout
** value is set if the I2C never gets started,
** and timed out. It's a fatal error.
**
** parameters: None
** Returned value: true or false, return false if timed out
**
*****************************************************************************/
uint32_t I2CStart( void )
{
uint32_t timeout = 0;
uint32_t retVal = FALSE;
/*--- Issue a start condition ---*/
LPC_I2C->CONSET = I2CONSET_STA; /* Set Start flag */
/*--- Wait until START transmitted ---*/
while( 1 )
{
if ( I2CMasterState == I2C_STARTED )
{
retVal = TRUE;
break;
}
if ( timeout >= MAX_TIMEOUT )
{
retVal = FALSE;
break;
}
timeout++;
}
return( retVal );
}
/*****************************************************************************
** Function name: I2CStop
**
** Descriptions: Set the I2C stop condition, if the routine
** never exit, it's a fatal bus error.
**
** parameters: None
** Returned value: true or never return
**
*****************************************************************************/
uint32_t I2CStop( void )
{
LPC_I2C->CONSET = I2CONSET_STO; /* Set Stop flag */
LPC_I2C->CONCLR = I2CONCLR_SIC; /* Clear SI flag */
/*--- Wait for STOP detected ---*/
while( LPC_I2C->CONSET & I2CONSET_STO );
return TRUE;
}
/*****************************************************************************
** Function name: I2CInit
**
** Descriptions: Initialize I2C controller
**
** parameters: I2c mode is either MASTER or SLAVE
** Returned value: true or false, return false if the I2C
** interrupt handler was not installed correctly
**
*****************************************************************************/
uint32_t I2CInit( uint32_t I2cMode )
{
/* It seems to be bit0 is for I2C, different from
UM. To be retested along with SSP reset. SSP and I2C
reset are overlapped, a known bug, for now, both SSP
and I2C use bit 0 for reset enable. Once the problem
is fixed, change to "#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 config */
LPC_IOCON->PIO0_4 |= 0x01; /* I2C SCL */
LPC_IOCON->PIO0_5 &= ~0x3F; /* I2C I/O config */
LPC_IOCON->PIO0_5 |= 0x01; /* I2C SDA */
/*--- Clear flags ---*/
LPC_I2C->CONCLR = I2CONCLR_AAC | I2CONCLR_SIC | I2CONCLR_STAC | I2CONCLR_I2ENC;
/*--- Reset registers ---*/
#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 = AT24C_ADDR;
}
NVIC_EnableIRQ(I2C_IRQn); /* Enable the I2C Interrupt */
LPC_I2C->CONSET = I2CONSET_I2EN; /* Enable I2C */
return( TRUE );
}
/*****************************************************************************
**I2C_SendOneByte()啟動I2C發送一個數據,Addr為從機地址,Data為將要發送的數據****
*****************************************************************************/
uint32_t I2C_SendOneByte(uint8_t Addr, uint8_t Data)
{
/* Write SLA(W), address and one data byte */
I2CWriteLength = 2;
I2CReadLength = 0;
I2CMasterBuffer[0] = Addr; /* Address Data and Write Bit */
I2CMasterBuffer[1] = Data; /* Data 0 */
do /*發送起始條件,直到起始條件成功發送,順利接管總線*/
{
;
}
while(I2CStart() == FALSE);
while (1)
{
if ( I2CMasterState == DATA_NACK )
{
I2CStop();
break;
}
}
return ( TRUE );
}
/******************************************************************************************************
**I2C_SendOneByte()啟動I2C發送多個數據,Addr為從機地址,Num為要發送的數據個數,pdata為數據首字節地址指針**
******************************************************************************************************/
uint32_t I2C_SendNumByte(uint8_t Addr, uint8_t Num, uint8_t *pdata)
{
uint8_t x=0;
/* Write SLA(W), address and one data byte */
I2CWriteLength = Num+1;
I2CReadLength = 0;
I2CMasterBuffer[0] = Addr; /* Address Data and Write Bit*/
for(x=0;x<Num;x++)
{
I2CMasterBuffer[x+1] = pdata[x]; /* Data */
}
do /*發送起始條件,直到起始條件成功發送,順利接管總線*/
{
;
}
while(I2CStart() == FALSE);
while (1)
{
if ( I2CMasterState == DATA_NACK )
{
I2CStop();
break;
}
}
return ( TRUE );
}
/*****************************************************************************
****I2C_ReadByte()啟動I2C讀取多個數據,Addr為從機地址,Num為要發送的數據個數
*****************************************************************************/
uint32_t I2C_ReadByte(uint32_t Num)
{
I2CWriteLength = 1;
I2CReadLength = Num;
I2CMasterBuffer[0] = AT24C_ADDR|READ_BIT; /*Address Data and Write Bit*/
do /*發送起始條件,直到起始條件成功發送,接管總線*/
{
;
}
while(I2CStart() == FALSE);
while ( 1 )
{
if ( I2CMasterState == DATA_NACK )
{
I2CStop();
break;
}
}
return ( TRUE );
}
/*****************************************************************************
** 以下為AT24C04驅動程序**
*****************************************************************************/
uint32_t AT24C04_ByteWrite(uint8_t Page,uint8_t WordAddr,uint8_t Data)
{
/* Write SLA(W), DeviceAddress+Page and one data byte */
I2CWriteLength = 3;
I2CReadLength = 0;
I2CMasterBuffer[0] = AT24C_ADDR|Page|WRITE_BIT; /* DeviceAddress Data+Page and Write Bit*/
I2CMasterBuffer[1] = WordAddr; /* Word Address*/
I2CMasterBuffer[2] = Data; /* Data */
do /*發送起始條件,直到起始條件成功發送,順利接管總線*/
{
;
}
while(I2CStart() == FALSE);
while (1)
{
if ( I2CMasterState == DATA_NACK )
{
I2CStop();
break;
}
}
return ( TRUE );
}
/************************************************************************************************/
/* the microcontroller can transmit up to seven(1K/2K) or fifteen (4K, 8K, 16K) more data words.*/
/************************************************************************************************/
uint32_t AT24C04_PageWrite(uint8_t Page,uint8_t WordAddr,uint32_t Num,uint8_t *pdata)
{
uint8_t x=0;
if(Num>16)
{
Num=16;
}
/* Write SLA(W), DeviceAddress+Page and one data byte */
I2CWriteLength = Num+2;
I2CReadLength = 0;
I2CMasterBuffer[0] = AT24C_ADDR|Page|WRITE_BIT; /* DeviceAddress Data+Page and Write Bit*/
I2CMasterBuffer[1] = WordAddr; /* Word Address*/
for(x=0;x<=Num;x++)
{
I2CMasterBuffer[x+2] = pdata[x]; /* Data */
}
do /*發送起始條件,直到起始條件成功發送,順利接管總線*/
{
;
}
while(I2CStart() == FALSE);
while (1)
{
if ( I2CMasterState == DATA_NACK )
{
I2CStop();
break;
}
}
return ( TRUE );
}
/*****************************************************************************
**AT24C04_CurrAdrRead(),參數Page為0或者1,以選擇所讀取的頁面*******************
**Word Address保持上次讀寫操作所用的Word Address地址,并自增1*****************
*****************************************************************************/
uint32_t AT24C04_CurrAdrRead(uint8_t Page)
{
I2CWriteLength = 1;
I2CReadLength = 1;
I2CMasterBuffer[0] = AT24C_ADDR|Page|READ_BIT; /*DeviceAddress Data and Write Bit*/
do /*發送起始條件,直到起始條件成功發送,接管總線*/
{
;
}
while(I2CStart() == FALSE);
while ( 1 )
{
if ( I2CMasterState == DATA_NACK )
{
I2CStop();
break;
}
}
return ( TRUE );
}
/*******************************************************************************************
**AT24C04_RandomRead(),參數Page為0或者1,以選擇所讀取的頁面,WordAddr為所選取頁面的字節地址**
*******************************************************************************************/
uint32_t AT24C04_RandomRead(uint8_t Page,uint8_t WordAddr)
{
/* Write SLA(W), address+Page and one data byte */
I2CWriteLength = 2;
I2CReadLength = 1;
I2CMasterBuffer[0] = AT24C_ADDR|Page|WRITE_BIT; /* DeviceAddress Data+Page and Write Bit*/
I2CMasterBuffer[1] = WordAddr; /* Word Address*/
do /*發送起始條件,直到起始條件成功發送,順利接管總線*/
{
;
}
while(I2CStart() == FALSE); /* 接管總線后,發送DeviceAddress和WoraAddress */
while (1)
{
if ( I2CMasterState == I2C_REPEATED_START )
{
I2CWriteLength = 1;
I2CMasterBuffer[0] = AT24C_ADDR|Page|READ_BIT; /* DeviceAddress Data+Page and Write Bit*/
while ( 1 )
{
if ( I2CMasterState == DATA_NACK )
{
I2CStop();
break;
}
}
return ( TRUE );
}
}
}
/*******************************************************************************************
**AT24C04_SequRead(),參數Page為0或者1,以選擇所讀取的頁面,Num為讀出的字節個數***************
*******************************************************************************************/
uint32_t AT24C04_SequRead(uint8_t Page,uint32_t Num)
{
I2CWriteLength = 1;
I2CReadLength = Num;
I2CMasterBuffer[0] = AT24C_ADDR|Page|READ_BIT; /*DeviceAddress Data and Write Bit*/
do /*發送起始條件,直到起始條件成功發送,接管總線*/
{
;
}
while(I2CStart() == FALSE);
while ( 1 )
{
if ( I2CMasterState == DATA_NACK )
{
I2CStop();
break;
}
}
return ( TRUE );
}
/******************************************************************************
** End Of File
******************************************************************************/
IIC.h文件:
/*****************************************************************************
* i2c.h: Header file for NXP LPC Family Microprocessors
*
* Copyright(C) 2006, NXP Semiconductor
* All rights reserved.
*
* History
* 2006.07.19 ver 1.00 Preliminary version, first Release
*
******************************************************************************/
#ifndef __I2C_H
#define __I2C_H
/* If I2C SEEPROM is tested, make sure FAST_MODE_PLUS is 0.
For board to board test, this flag can be turned on. */
#define FAST_MODE_PLUS 1
#define I2C_BUFSIZE 6
#define MAX_TIMEOUT 0x00FFFFFF
#define I2CMASTER 0x01
#define I2CSLAVE 0x02
#define I2C_ADDR 0x80
#define AT24C_ADDR 0xA0
#define AT24C_Page0 0x00
#define AT24C_Page1 0x02
#define WRITE_BIT 0x00
#define READ_BIT 0x01
#define I2C_IDLE 0
#define I2C_STARTED 1
#define I2C_RESTARTED 2
#define I2C_REPEATED_START 3
#define DATA_ACK 4
#define DATA_NACK 5
#define I2CONSET_I2EN 0x00000040 /* I2C Control Set Register */
#define I2CONSET_AA 0x00000004
#define I2CONSET_SI 0x00000008
#define I2CONSET_STO 0x00000010
#define I2CONSET_STA 0x00000020
#define I2CONCLR_AAC 0x00000004 /* I2C Control clear Register */
#define I2CONCLR_SIC 0x00000008
#define I2CONCLR_STAC 0x00000020
#define I2CONCLR_I2ENC 0x00000040
#define I2DAT_I2C 0x00000000 /* I2C Data Reg */
#define I2ADR_I2C 0x00000000 /* I2C Slave Address Reg */
#define I2SCLH_SCLH 0x00000060 /* I2C SCL Duty Cycle High Reg */
#define I2SCLL_SCLL 0x00000060 /* I2C SCL Duty Cycle Low Reg */
#define I2SCLH_HS_SCLH 0x00000015 /* Fast Plus I2C SCL Duty Cycle High Reg */
#define I2SCLL_HS_SCLL 0x00000015 /* Fast Plus I2C SCL Duty Cycle Low Reg */
void I2C_IRQHandler(void);
uint32_t I2CStart( void );
uint32_t I2CStop( void );
uint32_t I2CInit( uint32_t I2cMode );
uint32_t I2CEngine( void );
uint32_t I2C_SendNumByte(uint8_t Addr, uint8_t Num, uint8_t *pdata);
uint32_t I2C_ReadByte(uint32_t Num);
uint32_t AT24C04_ByteWrite(uint8_t Page,uint8_t WordAddr,uint8_t Data);
uint32_t AT24C04_PageWrite(uint8_t Page,uint8_t WordAddr,uint32_t Num,uint8_t *pdata);
uint32_t AT24C04_CurrAdrRead(uint8_t Page);
uint32_t AT24C04_RandomRead(uint8_t Page,uint8_t WordAddr);
uint32_t AT24C04_SequRead(uint8_t Page,uint32_t Num);
#endif /* end __I2C_H */
/****************************************************************************
** End Of File
*****************************************************************************/
|
|