www.pudn.com > Bit1611_demo_code.rar > I2C.C


/* ********************************************************************** 
 
         Copyright (c) 2002-2006 Beyond Innovation Technology Co., Ltd 
 
        All rights are reserved. Reproduction in whole or in parts is 
    prohibited without the prior written consent of the copyright owner. 
   ---------------------------------------------------------------------- 
 
    Module: I2C.C 
 
    Purpose: Implementation of I2C module. 
 
    Version: 0.02                                   11:15AM  2005/12/09 
 
    Compiler: Keil 8051 C Compiler v8.01 
 
    Reference: 
    [1] I2C Peripherals data handbook IC12, 1996 Philips Semiconductors 
    [2] Display Driver and I2C-bus Peripherals data handbook IC12, 2000 
        Philips Semiconductors 
 
   ---------------------------------------------------------------------- 
    Modification: 
 
    R0.01 05:19PM  2004/10/25 Jeffrey Chang 
    Reason: 
        1. Original. 
    Solution: 
 
   ---------------------------------------------------------------------- 
    R0.02 11:14AM  2005/12/09 Jeffrey Chang 
    Reason: 
        1. Revised timing. 
    Solution: 
 
   ********************************************************************** */ 
 
#define _I2C_C_ 
 
 
/* ------------------------------------ 
    Header Files 
   ------------------------------------ */ 
#include  
 
#include "common.h" 
#include "i2c.h" 
 
/* ------------------------------------ 
    Macro Definitions 
   ------------------------------------ */ 
 
#define NOP_24  { _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();} 
#define NOP_20  { _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); } 
#define NOP_18  { _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); } 
#define NOP_15  { _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();  } 
#define NOP_12  { _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();   } 
#define NOP_10  { _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();                     } 
#define NOP_3   { _nop_(); _nop_(); _nop_(); } 
#define NOP_2   { _nop_(); _nop_(); } 
#define NOP_1   { _nop_(); } 
#define NOP_0   {  } 
 
// 6 / 14.318MHz = 419 ns ! 
 
#if (I2C_MODE_CFG  == I2C_MODE_SLOW) 
    // 100 kHz 
 
    // [10]165 Standard Mode Start Set-up Time:             Tsu,sta = 4.7 us 
    // [11]72  Standard Mode Start Set-up Time:             Tsu,sta = 4.7 us 
    #define I2C_SU_STA      NOP_24 
 
    // [10]165 Standard Mode Start Hold Time:               Thd,dat = 4.0 us 
    // [11]72  Standard Mode Start Hold Time:               Thd,dat = 4.0 us 
    #define I2C_HD_STA      NOP_20 
 
    // [10]165 Standard Mode Data Set-Up Time:              Tsu,dat = 250 ns 
    // [11]72  Standard Mode Data Set-Up Time:              Tsu,dat = 250 ns 
    #define I2C_SU_DAT      NOP_2 
 
    // [10]165 Standard Mode Data Hold Time:                Thd,dat = 0 us 
    // [11]72  Standard Mode Data Hold Time:                Thd,dat = 0 us 
    #define I2C_HD_DAT      NOP_0 
 
    // [10]165 Standard Mode HIGH period of the SCL clock:  Thigh = 4.0 us 
    // [11]72  Standard Mode HIGH period of the SCL clock:  Thigh = 4.0 us 
    #define I2C_HIGH        NOP_20 
 
    // [10]165 Standard Mode LOW period of the SCL clock:   Tlow = 4.7 us 
    // [11]72  Standard Mode LOW period of the SCL clock:   Tlow = 4.7 us 
    #define I2C_LOW         NOP_24 
 
    // [10]165 Standard Mode Stop Set-up Time:              Tsu,sto = 4.0 us 
    // [11]72  Standard Mode Stop Set-up Time:              Tsu,sto = 4.0 us 
    #define I2C_SU_STO      NOP_20 
 
#elif (I2C_MODE_CFG  == I2C_MODE_STANDARD) 
    // 100 kHz 
 
    // [10]165 Standard Mode Start Set-up Time:             Tsu,sta = 4.7 us 
    // [11]72  Standard Mode Start Set-up Time:             Tsu,sta = 4.7 us 
    #define I2C_SU_STA      NOP_12 
 
    // [10]165 Standard Mode Start Hold Time:               Thd,dat = 4.0 us 
    // [11]72  Standard Mode Start Hold Time:               Thd,dat = 4.0 us 
    #define I2C_HD_STA      NOP_10 
 
    // [10]165 Standard Mode Data Set-Up Time:              Tsu,dat = 250 ns 
    // [11]72  Standard Mode Data Set-Up Time:              Tsu,dat = 250 ns 
    #define I2C_SU_DAT      NOP_1 
 
    // [10]165 Standard Mode Data Hold Time:                Thd,dat = 0 us 
    // [11]72  Standard Mode Data Hold Time:                Thd,dat = 0 us 
    #define I2C_HD_DAT      NOP_0 
 
    // [10]165 Standard Mode HIGH period of the SCL clock:  Thigh = 4.0 us 
    // [11]72  Standard Mode HIGH period of the SCL clock:  Thigh = 4.0 us 
    #define I2C_HIGH        NOP_10 
 
    // [10]165 Standard Mode LOW period of the SCL clock:   Tlow = 4.7 us 
    // [11]72  Standard Mode LOW period of the SCL clock:   Tlow = 4.7 us 
    #define I2C_LOW         NOP_12 
 
    // [10]165 Standard Mode Stop Set-up Time:              Tsu,sto = 4.0 us 
    // [11]72  Standard Mode Stop Set-up Time:              Tsu,sto = 4.0 us 
    #define I2C_SU_STO      NOP_10 
 
 
#elif (I2C_MODE_CFG  == I2C_MODE_FAST) 
    // 400 kHz 
 
    // [10]165 Fast Mode Start Set-up Time:                 Tsu,sta = 0.6 us 
    #define I2C_SU_STA      NOP_2 
 
    // [10]165 Fast Mode Start Hold Time:                   Thd,dat = 0.6 us 
    #define I2C_HD_STA      NOP_2 
 
    // [10]165 Fast Mode Data Set-Up Time:                  Tsu,dat = 100 ns 
    #define I2C_SU_DAT      NOP_1 
 
    // [10]165 Fast Mode Data Hold Time:                    Thd,dat = 0 us 
    #define I2C_HD_DAT      NOP_0 
 
    // [10]165 Fast Mode HIGH period of the SCL clock:      Thigh = 0.6 us 
    #define I2C_HIGH        NOP_2 
 
    // [10]165 Fast Mode LOW period of the SCL clock:       Tlow = 1.3 us 
    #define I2C_LOW         NOP_3 
 
    // [10]165 Fast Mode Stop Set-up Time:                  Tsu,sto = 0.6 us 
    #define I2C_SU_STO      NOP_2 
 
#elif (I2C_MODE_CFG  == I2C_MODE_HIGHSPEED) 
    // 3.4 MHz 
 
    // [10]165 Highspeed Mode Start Set-up Time:            Tsu,sta = 4.7 us 
    #define I2C_SU_STA      NOP_0 
 
    // [10]165 Highspeed Mode Start Hold Time:              Thd,dat = 4.0 us 
    #define I2C_HD_STA      NOP_0 
 
    // [10]165 Highspeed Mode Data Set-Up Time:             Tsu,dat = 250 ns 
    #define I2C_SU_DAT      NOP_0 
 
    // [10]165 Highspeed Mode Data Hold Time:               Thd,dat = 0 us 
    #define I2C_HD_DAT      NOP_0 
 
    // [10]165 Highspeed Mode HIGH period of the SCL clock: Thigh = 4.0 us 
    #define I2C_HIGH        NOP_0 
 
    // [10]165 Highspeed Mode LOW period of the SCL clock:  Tlow = 4.7 us 
    #define I2C_LOW         NOP_0 
 
    // [10]165 Highspeed Mode Stop Set-up Time:             Tsu,sto = 4.0 us 
    #define I2C_SU_STO      NOP_0 
 
#else 
    #error I2C.C - Invalid I2C_MODE_CFG ! 
#endif // I2C_MODE_CFG 
 
 
#define     I2C_GET_DAT_HIGH        (   I2C_ioSDA == HIGH   ) 
 
#define     I2C_SET_CLK(HiLo)       {   I2C_ioSCL = (HiLo) ? HIGH : LOW;    } 
#define     I2C_SET_DAT(HiLo)       {   I2C_ioSDA = (HiLo) ? HIGH : LOW;    } 
 
 
/* ------------------------------------ 
    Type Definitions 
   ------------------------------------ */ 
 
 
/* ------------------------------------ 
    Variables Definitions 
   ------------------------------------ */ 
sbit I2C_ioSCL  = P1 ^ 6; 
sbit I2C_ioSDA  = P1 ^ 7; 
 
 
/* ------------------------------------ 
    Function Prototypes 
   ------------------------------------ */ 
 
 
 
/* ------------------------------------------------------------------- 
    Name: I2C_GetACK - 
    Purpose: . 
    Passed: None. 
    Returns: LOW if OK 
    Notes: 
  ------------------------------------------------------------------- */ 
BOOL I2C_GetACK (void) 
{ 
    BOOL    fResult; 
 
 
    //I2C_SET_DAT(HIGH);        // Removed by JC 01:48PM  2005/11/23 
    I2C_SU_DAT;                 // Added by JC 01:51PM  2005/11/23 
 
    I2C_SET_CLK(HIGH); 
    I2C_HIGH; 
 
    fResult = I2C_GET_DAT_HIGH; 
 
    I2C_SET_CLK(LOW); 
    I2C_LOW; 
 
    return( fResult ); 
} /* I2C_GetACK */ 
 
 
/* ------------------------------------------------------------------- 
    Name: I2C_Init - 
    Purpose: . 
    Passed: None. 
    Returns: None. 
    Notes: 
  ------------------------------------------------------------------- */ 
void I2C_Init (void) 
{ 
    I2C_SET_DAT(HIGH); 
    I2C_SET_CLK(HIGH); 
} /* I2C_Init */ 
 
 
#if (I2C_RX_BURST) 
/* ------------------------------------------------------------------- 
    Name: I2C_RxBurst - 
    Purpose: To receive bulk data from I2C slave device. 
    Passed: 
        bIdx: 1..255. (Excludes slave address and sub-address) 
    Returns: None. 
    Notes: 
        The bSLA should be the slave device's 'WRITE' module addres, 
        not 'READ' one. 
   ------------------------------------------------------------------- */ 
void I2C_RxBurst ( 
UB8  bSLA,          /* I2C slave address */ 
UB8  bREG,          /* I2C sub-address */ 
UB8  bCNT,          /* The number of data which will be transmitted */ 
UB8  *pbDATA        /* Point to the first DATA item */ 
) 
{ 
    UB8     bIdx; 
 
 
    I2C_Start(); 
 
    /* -------------------------------- 
        Write 
       -------------------------------- */ 
    I2C_TxData(bSLA);                  
    I2C_GetACK();                      
 
    I2C_TxData(bREG);                  
    I2C_GetACK(); 
 
 
    /* -------------------------------- 
        Read 
       -------------------------------- */ 
    I2C_Start();                        
    I2C_TxData(bSLA | 0x01); 
    I2C_GetACK(); 
 
 
    for (bIdx = 0; bIdx < (bCNT - 1); bIdx++) 
    { 
        *pbDATA++ = I2C_RxData(); 
 
        I2C_SetACK(); 
    } /* for */ 
 
 
    /* -------------------------------- 
        Last Read 
       -------------------------------- */ 
    *pbDATA = I2C_RxData(); 
    I2C_SetNAK(); 
 
    I2C_Stop(); 
} /* I2C_RxBurst */ 
#endif 
 
 
#if (I2C_RX_BYTE) 
/* ------------------------------------------------------------------- 
    Name: I2C_RxByte - 
    Purpose: To receive one byte data from I2C slave device. 
    Passed: 
        UB8 bSLA,          I2C slave address 
        UB8 bREG           I2C sub-address 
 
    Returns: 
        One byte received data. 
    Notes: 
        The bSLA should be the slave device's 'WRITE' mode address, 
        not 'READ' one. 
   ------------------------------------------------------------------- */ 
UB8 I2C_RxByte ( 
UB8 bSLA,          /* I2C slave address */ 
UB8 bREG           /* I2C sub-address */ 
) 
{ 
    UB8    bDATA; 
 
 
    I2C_Start(); 
 
    /* -------------------------------- 
        Write 
       -------------------------------- */ 
    I2C_TxData(bSLA);                    
    I2C_GetACK();                        
 
    I2C_TxData(bREG); 
    I2C_GetACK(); 
 
 
    /* -------------------------------- 
        Read 
       -------------------------------- */ 
    I2C_Start(); 
    I2C_TxData(bSLA | 0x01);             
    I2C_GetACK(); 
 
 
    /* -------------------------------- 
        Last Read 
       -------------------------------- */ 
    bDATA = I2C_RxData(); 
    I2C_SetNAK();                      
 
    I2C_Stop(); 
 
    return( bDATA ); 
} /* I2C_RxByte */ 
#endif 
 
 
/* ------------------------------------------------------------------- 
    Name: I2C_RxData - 
    Purpose: 
        To do I2C parallel serial conversion for reception. 
    Passed: None. 
    Returns: 
    Notes: 
  ------------------------------------------------------------------- */ 
UB8 I2C_RxData (void) 
{ 
    UB8     bResult; 
    UB8     bMask; 
 
 
    bResult = 0x00;                 /* Clear value */ 
 
    I2C_SET_DAT(HIGH); 
 
    /* MSB is read first */ 
    for (bMask = 0x80; bMask; bMask >>= 1) 
    { 
        I2C_SET_CLK(HIGH); 
        I2C_HIGH;                    
 
        if ( I2C_GET_DAT_HIGH ) 
            bResult |= bMask; 
 
        I2C_SET_CLK(LOW); 
    } /* for */ 
 
    return( bResult ); 
} /* I2C_RxData */ 
 
 
#if (I2C_RX_WORD) 
/* ------------------------------------------------------------------- 
    Name: I2C_RxWord - 
    Purpose: To receive one WORD data from I2C slave device. 
    Passed: 
    Returns: one WORD data. 
    Notes: 
        1) Only for little-endian storage format devices !!! 
        2) Keil C51 uses *big-endian* storage format. [1]144 
 
   ------------------------------------------------------------------- */ 
UW16 I2C_RxWord ( 
UB8 bSLA,                       /* I2C slave address */ 
UB8 bREG                        /* I2C sub-address */ 
) 
{ 
    UW16    wDATA; 
 
 
    I2C_Start(); 
 
    /* -------------------------------- 
        Write 
       -------------------------------- */ 
    I2C_TxData(bSLA);                   
    I2C_GetACK();                       
 
    I2C_TxData(bREG);                   
    I2C_GetACK();                       
 
 
    /* -------------------------------- 
        Read 
       -------------------------------- */ 
    I2C_Start(); 
    I2C_TxData(bSLA | 0x01); 
    I2C_GetACK(); 
 
 
    /* -------------------------------- 
        Last Read 
       -------------------------------- */ 
    wDATA = I2C_RxData();                
    I2C_SetACK(); 
 
    wDATA = (I2C_RxData() << 8) + wDATA; 
    I2C_SetNAK();                        
 
    I2C_Stop();                          
 
    return( wDATA ); 
} /* I2C_RxWord */ 
#endif 
 
 
/* ------------------------------------------------------------------- 
    Name: I2C_SetACK - 
    Purpose: . 
    Passed: None. 
    Returns: None. 
    Notes: 
   ------------------------------------------------------------------- */ 
void I2C_SetACK (void) 
{ 
    I2C_SET_DAT(LOW); 
    I2C_SU_DAT;             // Added by JC 01:53PM  2005/11/23 
 
    I2C_SET_CLK(HIGH); 
    I2C_HIGH; 
 
    I2C_SET_CLK(LOW); 
    I2C_LOW; 
} /* I2C_SetACK */ 
 
 
/* ------------------------------------------------------------------- 
    Name: I2C_SetNAK - 
    Purpose: . 
    Passed: None. 
    Returns: None. 
    Notes: 
   ------------------------------------------------------------------- */ 
void I2C_SetNAK (void) 
{ 
    I2C_SET_DAT(HIGH); 
    I2C_SU_DAT;             // Added by JC 01:53PM  2005/11/23 
 
    I2C_SET_CLK(HIGH); 
    I2C_HIGH; 
 
    I2C_SET_CLK(LOW); 
    I2C_LOW; 
} /* I2C_SetNAK */ 
 
 
/* ------------------------------------------------------------------- 
    Name: I2C_Start - START condition (SDA falling edge). 
    Purpose: . 
    Passed: None. 
    Returns: None. 
    Notes: 
    Reference: 
        [1] p64 
   ------------------------------------------------------------------- */ 
void I2C_Start (void) 
{ 
    I2C_SET_DAT(HIGH); 
 
    I2C_SET_CLK(HIGH); 
    I2C_SU_STA; 
 
 
    I2C_SET_DAT(LOW); 
    I2C_HD_STA;           
 
    I2C_SET_CLK(LOW); 
    I2C_LOW;              
} /* I2C_Start */ 
 
 
/* ------------------------------------------------------------------- 
    Name: I2C_Stop - STOP condition (SDA rising edge). 
    Purpose: . 
    Passed: None. 
    Returns: None. 
    Notes: 
    Reference: 
        [1] p64 
 
  ------------------------------------------------------------------- */ 
void I2C_Stop (void) 
{ 
    I2C_SET_DAT(LOW); 
 
    I2C_SET_CLK(HIGH); 
    I2C_SU_STO; 
 
    I2C_SET_DAT(HIGH); 
} /* I2C_Stop */ 
 
 
#if (I2C_TX_BURST) 
/* ------------------------------------------------------------------- 
    Name: I2C_TxBurst - 
    Purpose: To transmit bulk data to I2C slave device. 
    Passed: 
        bCNT: 1..255. (Excludes slave address and sub-address) 
    Returns: None. 
    Notes: 
        The bSLA should be the slave device's 'WRITE' module addres, 
        not 'READ' one. 
   ------------------------------------------------------------------- */ 
void I2C_TxBurst ( 
UB8  bSLA,          /* I2C slave address */ 
UB8  bREG,          /* I2C sub-address */ 
UB8  bCNT,          /* The number of data which will be transmitted */ 
UB8  *pbDATA        /* Point to the first DATA item */ 
) 
{ 
    UB8 bIdx; 
 
 
    I2C_Start(); 
 
    I2C_TxData(bSLA); 
    I2C_GetACK(); 
 
    I2C_TxData(bREG); 
    I2C_GetACK(); 
 
    for (bIdx = 0; bIdx < bCNT; bIdx++) 
    { 
        I2C_TxData(*pbDATA++); 
        I2C_GetACK(); 
    } /* for */ 
 
    I2C_Stop(); 
} /* I2C_TxBurst */ 
#endif 
 
 
#if (I2C_TX_BYTE) 
/* ------------------------------------------------------------------- 
    Name: I2C_TxByte - 
    Purpose: To transmit one byte data to I2C slave device. 
    Passed: 
    Returns: None. 
    Notes: 
        The bSLA should be the slave device's 'WRITE' module addres, 
        not 'READ' one. 
   ------------------------------------------------------------------- */ 
void I2C_TxByte ( 
UB8 bSLA,          /* I2C slave address */ 
UB8 bREG,          /* I2C sub-address */ 
UB8 bDATA          /* DATA item */ 
) 
{ 
    I2C_Start(); 
 
    I2C_TxData(bSLA); 
    I2C_GetACK(); 
 
    I2C_TxData(bREG); 
    I2C_GetACK(); 
 
    I2C_TxData(bDATA); 
    I2C_GetACK(); 
 
    I2C_Stop(); 
} /* I2C_TxByte */ 
#endif 
 
 
/* ------------------------------------------------------------------- 
    Name: I2C_TxData - 
    Purpose: To do I2C parallel serial conversion for transmission. 
    Passed: 
    Returns: None. 
    Notes: 
   ------------------------------------------------------------------- */ 
void I2C_TxData (UB8 bData) 
{ 
    UB8     bMask; 
 
 
    /* MSB is sent first */ 
    for (bMask = 0x80; bMask; bMask >>= 1) 
    { 
        I2C_SET_DAT(bData & bMask); 
        I2C_SU_DAT; 
 
        I2C_SET_CLK(HIGH); 
        I2C_HIGH; 
 
        I2C_SET_CLK(LOW); 
    } 
 
    I2C_SET_DAT(HIGH);      // Added by JC 01:47PM  2005/11/23 
} /* I2C_TxData */ 
 
 
#if (I2C_TX_WORD) 
/* ------------------------------------------------------------------- 
    Name: I2C_TxWord - 
    Purpose: To transmit bulk data to I2C slave device. 
    Passed: 
    Returns: None. 
    Notes: 
   ------------------------------------------------------------------- */ 
void I2C_TxWord ( 
UB8  bSLA,          /* I2C slave address */ 
UB8  bREG,          /* I2C sub-address */ 
UW16 wDATA          /* DATA item */ 
) 
{ 
    I2C_Start();                         
 
    I2C_TxData(bSLA);                    
    I2C_GetACK();                        
 
    I2C_TxData(bREG);                    
    I2C_GetACK();                        
 
    I2C_TxData(wDATA & 0xFF);            
    I2C_GetACK();                        
 
    I2C_TxData(wDATA >> 8);              
    I2C_GetACK();                        
 
    I2C_Stop();                          
} /* I2C_TxWord */ 
#endif 
 
 
 
/* ------------------------------------------------------------------- 
    Name:  - 
    Purpose: . 
    Passed: None. 
    Returns: None. 
    Notes: 
   ------------------------------------------------------------------- */ 
 
 
/* ********************************************************************** 
 
    Description: 
 
 
   ********************************************************************** */ 
 
/* %% End Of File %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */