📄 i2c_if.c
字号:
/********************************************************************* FUNCTION MODULE: i2c_if.c** I2C Serial Data Interface Module for Silabs C8051F133************************************************************************ DESCRIPTION:** Serial I2C/SMBus bus access.** This module is believed to be able to talk to any I2C compliant device.* It has been tested with:* - X64645 EEPROM (obsolete in 2003)* - M24C64 EEPROM* - MAX518 DAC* - MAX5821 DAC* - DS1629 Real Time Clock* - MAX1609 parallel I/O extender** Note: this module includes two versions:* 1) a version using hardware transceiver and* 2) a version using bit-banging.** Define appropriate compilation option I2C_HARDWARE or I2C_BIT_BANGED***********************************************************************/#define I2C_HARDWARE//#define I2C_BIT_BANGED/*** REVISION LOG (don't use TABs for rev log):** Date Name Version Reason* ------- ---------------- ------- -------------------------------* 08-31-05 E.Burzic/D.Juges 0.0.1 Initial design from Silabs and Internet* 09-30-05 E.Burzic/D.Juges 0.2.1 bit-banged or hardware options*********************************************************************//*--------------------------------------------------------------------** INCLUDE FILES*--------------------------------------------------------------------*/#include "f120.h"#include "comdefs.h"#include "i2c_if.h"/*---------------------------------------------------------------------** COMMON CONSTANTS*----------------------------------------------------------------------*/#define ESMB0 2 // SMB interrupt enable bit in sfr EIE1/*---------------------------------------------------------------------** common public variables (used by either version)*---------------------------------------------------------------------*/unsigned char xdata _i2c_error;unsigned char xdata smb_status;/*---------------------------------------------------------------------** COMMON FUNCTION: I2CCheckError() (used by either version)** Returns 0 if no error during previous I2C function, a non-zero* error code otherwise.*---------------------------------------------------------------------*/unsigned char I2CCheckError( void ){ return( _i2c_error );} /* end I2CCheckError() *//*---------------------------------------------------------------------** FUNCTION: I2CClearError()*----------------------------------------------------------------------*//*void I2CClearError( void ){ _i2c_error = 0;} /* end I2CClearError() */#ifdef I2C_HARDWARE/*---------------------------------------------------------------------** CONSTANTS*---------------------------------------------------------------------*/#define I2C_INIT 0x40 // enable SMB transceiver#define AA_BIT 0x04#define STO_BIT 0x10#define STA_BIT 0x20/*--------------------------------------------------------------------** SMBus states for Master Tx or Rx:** MT = Master Transmitter (Tx)* MR = Master Receiver (Rx)* ADD = Address transmitted* DB = Data Byte transmitted/received*----------------------------------------------------------------------*/#define SMB_BUS_ERROR 0x00 // (all modes) BUS ERROR#define SMB_START 0x08 // (MT & MR) START transmitted#define SMB_RP_START 0x10 // (MT & MR) repeated START#define SMB_MTADDACK 0x18 // (MT) Slave address + W transmitted; // ACK received#define SMB_MTADDNACK 0x20 // (MT) Slave address + W transmitted; // NACK received#define SMB_MTDBACK 0x28 // (MT) data byte transmitted; ACK rec'vd#define SMB_MTDBNACK 0x30 // (MT) data byte transmitted; NACK rec'vd#define SMB_MTARBLOST 0x38 // (MT) arbitration lost#define SMB_MRADDACK 0x40 // (MR) Slave address + R transmitted; // ACK received#define SMB_MRADDNACK 0x48 // (MR) Slave address + R transmitted; // NACK received#define SMB_MRDBACK 0x50 // (MR) data byte rec'vd; ACK transmitted#define SMB_MRDBNACK 0x58 // (MR) data byte rec'vd; NACK transmitted#define BUF_LEN 14unsigned char xdata buffer[BUF_LEN]; // ***TESTunsigned char data smb_buf_ndx; // ***TEST/* ----- local function prototypes ----- */void clearbuffer( void );/*=====================================================================** GENERIC I2C FUNCTIONS*=====================================================================*//*---------------------------------------------------------------------** I2CSendAddr()** addr is an address between 0 and 255* rd is either WRITE or READ** - initiates START condition* - send device select address, with appropriate R/W bit as provided in rd* - wait for acknowledge from device* - if timeout before acknlowledge is received, set error flag*---------------------------------------------------------------------*/void I2CSendAddr( unsigned char addr, unsigned char rd ){ int xdata i=0; EA = FALSE; // Disable global interrupt. if( ! rd ){ clearbuffer(); SMB0CN = I2C_INIT; /* SIO1 enable, with bit frequency set. */ } _i2c_error = 0; /* Clear error flag. */ smb_status = 0; SMB0CN = I2C_INIT | STA_BIT; /* SIO1 send START. */ do{ i++; }while( (! SI) && i>0 ); /* Hold here until Serial Interrupt FLag or */// while( SI == 0 ); /* counter rollover. */ if( SMB0STA != SMB_START && SMB0STA != SMB_MTDBACK && SMB0STA != SMB_RP_START ){ smb_status= SMB0STA; _i2c_error = 0x01; // START not transmitted? I2CSendStop(); EA = TRUE; return; } if( rd ) /* I2C address fixup. */ addr++; SMB0DAT = addr; /* Load address into Data Register (which */ SMB0CN = I2C_INIT; /* intitiates transfer), SMB enabled */ i = 0; do{ i++; }while( (! SI) && (i) ); // Hold here until Serial Interrupt FLag or // counter rollover. if( SMB0STA == SMB_MTADDNACK ) // SLA + (W || R) has been transmitted, // NOT ACK has been received _i2c_error |= 0x02; // set error #2 if( SMB0STA == SMB_MRADDNACK ) _i2c_error |= 0x04; EA = TRUE; // Enable global interrupt.} /* end I2CSendAddress() *//*---------------------------------------------------------------------** I2CSendByte()** Send Byte and wait for acknowledge* Set error flag if timeout before acknowledge received.*---------------------------------------------------------------------*/void I2CSendByte( unsigned char byte_data ){ int xdata i=0; EA = FALSE; SMB0DAT = byte_data; SMB0CN = I2C_INIT; // Start Tx do{ i++; }while( (! SI) && i>0 ); // wait for Tx done or timeout if( SMB0STA != SMB_MTDBACK ) // No ACK received after sending data? _i2c_error |= 0x08; EA = TRUE;} /* end I2CSendByte() *//*---------------------------------------------------------------------** I2CGetByte()** Receive Byte and acknowledge*---------------------------------------------------------------------*/unsigned char I2CGetByte( void ){ int xdata i = 0; EA = FALSE; // Disable global interrupt SMB0CN = I2C_INIT | AA_BIT; /* SIO1 Enable, with ACK. */ do{ i++; }while( (! SI) && i>0 ); if( !i ) /* SI never turned on? */ _i2c_error |= 0x10; /* Yes, set error #4. */ EA = TRUE; /* Enable global interrupt. */ return( SMB0DAT );} /* end I2CGetByte() *//*---------------------------------------------------------------------** FUNCTION: I2CGetLastByte()** Receive byte and NAK*----------------------------------------------------------------------*/unsigned char I2CGetLastByte( void ){ int xdata i = 0; EA = FALSE; SMB0CN = I2C_INIT; /* SIO1 Enable, no ACK. */ do{ i++; }while( (! SI) && i>0 ); if( !i ) /* SI never turned on? */ _i2c_error &= 0x20; /* Yes, set error #4. */ EA = TRUE; /* Enable global interrupt. */ return( SMB0DAT );} // end I2CGetLastByte()/*---------------------------------------------------------------------** I2CSendStop()*---------------------------------------------------------------------*/void I2CSendStop( void ){ char xdata i = 0; SMB0CN = I2C_INIT | STO_BIT; /* SIO1 Enable, generate STOP. */ do{ i++; }while( i>0 ); // wait a little SMB0CN = 0; // reset transceiver} /* end I2CSendStop() *//*---------------------------------------------------------------------** I2C_Init()*----------------------------------------------------------------------*/void I2C_Init( void ){ SMB0CN = I2C_INIT; // enable SMBus transceiver SMB0CR = -60; // 100 kHz EIE1 &= ~ESMB0; // disable SMB interrupts XBR0 |= 0x01; // enable SMBus crossbar// SMB0CN = I2C_INIT; /* SIO1 enable, with bit frequency set. */} /* end I2C_Init() *//*-----------------------------------------------------------------------------------** FUNCTION: clearbuffer)*------------------------------------------------------------------------------------*/void clearbuffer( void ){ char i; for(i=0;i<BUF_LEN;i++) buffer[i] = 0; smb_buf_ndx = 0;} /* end clearbuffer() */#endif // I2C_HARDWARE#ifdef I2C_BIT_BANGED/*---------------------------------------------------------------------** Ports** Note: make sure these bits are set as Open Collector (default) outputs*---------------------------------------------------------------------*/sbit SCL = P0_3; // I2C Clocksbit SDA = P0_2; // I2C Data/*---------------------------------------------------------------------** Error Codes (_i2c_error)* 0 No error* 1 no acknowledge from Slave* 2 no address ack* 4 no data ack*----------------------------------------------------------------------*//*---------------------------------------------------------------------** Private Functions Prototypes*----------------------------------------------------------------------*/void i2c_delay( void ); // Wait for 5祍 (for 100kHz operation)void i2c_start( void ); // Geneate I2C START conditionvoid i2c_stop( void ); // Geneate I2C STOP conditionvoid i2c_ack( void ); // Geneate I2C MASTER ACKvoid i2c_nack( void ); // Geneate I2C MASTER NACKunsigned char i2c_write( unsigned char value ); // Write a character via I2Cunsigned char i2c_check( void ); // Check an ACK from SLAVEunsigned char i2c_read( void ); // Read a character via I2C// END Private Function Prototypes ======================================/* ===== code ===== *//*---------------------------------------------------------------------** I2CSendAddr()** addr is an even number between 0 and 254* rd is either WRITE (0) or READ (1)** - initiates START condition* - send device select address, with appropriate R/W bit as provided in rd* - wait for acknowledge from device* - if timeout before acknlowledge is received, set error flag*---------------------------------------------------------------------*/void I2CSendAddr( unsigned char addr, unsigned char rd ){ _i2c_error = 0; i2c_start(); if( i2c_write( addr | rd ) != 0 ) _i2c_error = 0x02;} /* end I2CSendAddr() *//*---------------------------------------------------------------------** I2CSendByte()** Send Byte and wait for acknowledge* Set error flag if timeout before acknowledge received.*---------------------------------------------------------------------*/void I2CSendByte( unsigned char byte_data ){ if( i2c_write( byte_data ))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -