⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c.c

📁 I2C library for LPC21xx processor
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
  i2c support for LPC21XX

  (c) 2004  Yuri Tiomkin (yuri@tnkernel.com)


  Includes drivers:

   - EEPROM 24XX series (from 24XX04 to 24XX512)
   - Real Time Clock DS1307
   - I/O Extender PCA9555
   - Temperature sensor LM75

  Supports uCOS-II and TNKernel

THIS SOFTWARE IS PROVIDED BY THE YURI TIOMKIN AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL YURI TIOMKIN OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

*/

#define __UCOS_          1  //-- if uCOS-II is used
//#define __TNKERNEL_    1    //-- if TNKernel is used

#include "LPC21XX.h"
#include "i2c.h"

#if defined(__UCOS_)
#include ".\\os\\includes.h"
#elif defined(__TNKERNEL_)
#include "..\\os\\tn.h"
#include "..\\os\\tn_port.h"
#endif

#ifndef NULL
#define NULL 0
#endif

#if defined(__UCOS_)
extern OS_EVENT  * gpSemI2Cop;
#elif defined(__TNKERNEL_)
extern TN_SEM  gSemI2Cop;
#endif


//===========================================================================
//================ Common routines ==========================================
//===========================================================================
void i2c_lpc_init(int Mode)
{
   if(Mode == I2C_SPEED_400)
   {
  //--- I2C Timing for 58 MHz (t = 16.954 ns) ---
      rI2C_I2SCLH = 47;  //-- more then 0.6 us  - 0.8
      rI2C_I2SCLL = 93;  //-- more then 1.3 us  - 1.4
   }
   else //Slow
   {
      rI2C_I2SCLH = 47*4;
      rI2C_I2SCLL = 93*4;
   }

   rI2C_I2CONCLR = 0xFF;           //-- Clear all flags
   rI2C_I2CONSET = 0x40;           //-- Set Master Mode
   rI2C_I2CONSET |= I2C_FLAG_I2EN; //--- Enable I2C
}

//---------------------------------------------------------------------------
static void i2c_lpc_wr_byte(int byte)
{
   rI2C_I2DAT = byte;
   rI2C_I2CONCLR = I2C_FLAG_SI;                //-- Clear SI
   while(!(rI2C_I2CONSET & I2C_FLAG_SI));      //-- End wr POINT
}

//---------------------------------------------------------------------------
static void i2c_lpc_stop()
{
    //-- Set STOP condition
   rI2C_I2CONCLR = I2C_FLAG_SI;                  //-- Clear SI
   rI2C_I2CONSET |=  I2C_FLAG_AA | I2C_FLAG_STO; //-- Clear NO ASK
}

//---------------------------------------------------------------------------
static int i2c_lpc_ctrl(int ctrl)
{
   int chk;
   //-- Set START
   rI2C_I2CONCLR = 0xFF; // Clear all bits
   rI2C_I2CONSET |= I2C_FLAG_I2EN | I2C_FLAG_STA;
   while(!(rI2C_I2CONSET & I2C_FLAG_SI));      //--- End START
   //-- Set ADDRESS
   rI2C_I2DAT = ctrl;
   rI2C_I2CONCLR = I2C_FLAG_STA | I2C_FLAG_SI; //-- Clear START & SI
   if(ctrl & 1) //-- RD
      chk = 0x40; //-- 40H - SLA+R has been transmitted; ACK has been received
   else
      chk = 0x18; //-- 18H - SLA+W has been transmitted; ACK has been received
   while(!(rI2C_I2CONSET & I2C_FLAG_SI));      //-- End CTRL
   if(rI2C_I2STAT != chk)
   {
      i2c_lpc_stop();
      return I2C_ERR_NO_RESPONSE;
   }
   return I2C_NO_ERR;
}

//---------------------------------------------------------------------------
static int i2c_lpc_rx_to_buf(char * buf,int num)
{
   int rc;

   if(buf == NULL)
      return I2C_ERR_WRONG_PARAM;

   rc = num;
   if(rc > 1)
   {
      rI2C_I2CONCLR = I2C_FLAG_SI;
      rI2C_I2CONSET |= I2C_FLAG_AA;
      for(;;)
      {
         while(!(rI2C_I2CONSET & I2C_FLAG_SI));  //-- End Data from slave;
         *buf++ = (unsigned char)rI2C_I2DAT;
         rc--;
         if(rc <= 0)
            break;
         else if(rc == 1)
            rI2C_I2CONCLR = I2C_FLAG_AA | I2C_FLAG_SI;  //-- After next will NO ASK
         else
         {
            rI2C_I2CONCLR = I2C_FLAG_SI;
            rI2C_I2CONSET |= I2C_FLAG_AA;
         }
      }
   }
   else if(rc == 1)
   {
      rI2C_I2CONCLR = I2C_FLAG_AA | I2C_FLAG_SI;  //-- After next will NO ASK
      while(!(rI2C_I2CONSET & I2C_FLAG_SI));  //-- End Data from slave;
      *buf = (unsigned char)rI2C_I2DAT;
   }
   else //err
      return I2C_ERR_WRONG_PARAM;

   return I2C_NO_ERR;
}
//----------------------------------------------------------------------
static int i2c_lpc_ask_polling_op(int ctrl)  //-- wait until write finished
{
   int rc;
   int i;

#if defined(__UCOS_)
   for(i=0;i < 15; i++)
#elif defined(__TNKERNEL_)
   for(i=0;i < 15; i++)
#else
   for(i=0;i < I2C_WR_24XX_TIMEOUT; i++) //-- actually wr = ~110 but timeout =10000
#endif
   {
      rI2C_I2CONSET = I2C_FLAG_STA;
      rI2C_I2CONCLR = I2C_FLAG_SI;  //-- Here - clear only SI (not all rI2C_I2CONCLR)
      while(!(rI2C_I2CONSET & I2C_FLAG_SI));        //wait the ACK

      rI2C_I2DAT = ctrl & 0xFE;; // R/WI = 0
      rI2C_I2CONCLR = I2C_FLAG_SI | I2C_FLAG_STA; //-- Clear START & SI
      while(!(rI2C_I2CONSET & I2C_FLAG_SI));//wait the ACK
      rc = rI2C_I2STAT;
      if(rc == 0x18) //-- got ACK after CLA + W
         break;
      else
      {
#if defined(__UCOS_)
         OSTimeDly(2);      //-- 2 mS
#elif defined(__TNKERNEL_)
         tn_task_sleep(2);  //-- 2 mS
#endif
      }
   }
   if(i == I2C_WR_24XX_TIMEOUT)
      return I2C_ERR_24XX_WR_TIMEOUT;
   return I2C_NO_ERR;
}
//===========================================================================
//================ EEPROM 24XX series ========================================
//===========================================================================

//----------------------------------------------------------------------------
static int m24xx_page_size(int eeprom_type, int eeprom_addr,int * pg_sz)
{
   int page_size,rc;

   page_size = 0;
   rc = I2C_NO_ERR;
   switch(eeprom_type)
   {
      case EEPROM_24XX04:
         if(eeprom_addr > EEPROM_MAX_ADDR_24XX04)
            rc = I2C_ERR_24XX_BAD_ADDR;
         else
            page_size = 16; // 24LC04B have page size = 16,24C04A = 8
         break;
      case EEPROM_24XX08:
         if(eeprom_addr > EEPROM_MAX_ADDR_24XX08)
            rc = I2C_ERR_24XX_BAD_ADDR;
         else
            page_size = 16;
         break;
      case EEPROM_24XX16:
         if(eeprom_addr > EEPROM_MAX_ADDR_24XX16)
            rc = I2C_ERR_24XX_BAD_ADDR;
         else
            page_size = 16;
         break;
      case EEPROM_24XX32:
         if(eeprom_addr > EEPROM_MAX_ADDR_24XX32)
            rc = I2C_ERR_24XX_BAD_ADDR;
         else
            page_size = 32;
         break;
      case EEPROM_24XX64:
         if(eeprom_addr > EEPROM_MAX_ADDR_24XX64)
            rc = I2C_ERR_24XX_BAD_ADDR;
         else
            page_size = 32;
         break;
      case EEPROM_24XX128:
         if(eeprom_addr > EEPROM_MAX_ADDR_24XX128)
            rc = I2C_ERR_24XX_BAD_ADDR;
         else
            page_size = 64;
         break;
      case EEPROM_24XX256:
         if(eeprom_addr > EEPROM_MAX_ADDR_24XX256)
            rc = I2C_ERR_24XX_BAD_ADDR;
         else
            page_size = 64;
         break;
      case EEPROM_24XX512:
         if(eeprom_addr > EEPROM_MAX_ADDR_24XX512)
            rc = I2C_ERR_24XX_BAD_ADDR;
         else
            page_size = 128;
         break;
   }
   if(rc != I2C_NO_ERR)
      return rc;
   if(page_size == 0)  //-- Bad eeprom_type
      return I2C_ERR_24XX_BAD_TYPE;

   if(pg_sz)
      *pg_sz = page_size;
   return I2C_NO_ERR;
}
//----------------------------------------------------------------------------
static int m24xx_set_addr(
    int eeprom_type,     //-- EEPROM type
    int eeprom_addr,     //-- start eeprom addr ( not included Hardware A2,A1,A0)
    int eeprom_cs_val,   //-- Hardware A2,A1,A0 (valid from 24XX32)
    int * ctrl_val,      //-- Value of ctrl(return)
    int * addr_hi_val,   //-- Value of addr_hi(return)
    int * addr_lo_val)   //-- Value of addr_lo(return)
{
   int ctrl;
   int addr_hi;
   int addr_lo;
   int rc;

   rc = I2C_NO_ERR;
   ctrl = 0;
   addr_hi = 0;
   addr_lo = 0;

   switch(eeprom_type)
   {
      case EEPROM_24XX04:   // 24LC04B ignore AO,A1,A2 pins


         ctrl = (eeprom_addr>>7) & 0x02; //-- 00000010
         ctrl |= 0xA0; //-- 1010xxxx
         addr_hi = eeprom_addr & 0xFF;
         addr_lo = -1;
         break;

      case EEPROM_24XX08: // 24LC08B ignore AO,A1,A2 pins

         ctrl = (eeprom_addr>>7) & 0x06; //-- 00000110
         ctrl |= 0xA0; //-- 1010xxxx
         addr_hi = eeprom_addr & 0xFF;
         addr_lo = -1;
         break;

      case EEPROM_24XX16: // 24LC16B ignore AO,A1,A2 pins

         ctrl = (eeprom_addr>>7) & 0x07; //-- 00001110
         ctrl |= 0xA0; //-- 1010xxxx
         addr_hi = eeprom_addr & 0xFF;
         addr_lo = -1;
         break;

      case EEPROM_24XX32:

         ctrl = (eeprom_cs_val<<1) & 0x07; //-- 00001110
         ctrl |= 0xA0; //-- 1010xxxx
         addr_hi = (eeprom_addr>>8) & 0x0F;
         addr_lo = eeprom_addr & 0xFF;
         break;

      case EEPROM_24XX64:

         ctrl = (eeprom_cs_val<<1) & 0x07; //-- 00001110
         ctrl |= 0xA0; //-- 1010xxxx
         addr_hi = (eeprom_addr>>8) & 0x1F;
         addr_lo = eeprom_addr & 0xFF;
         break;

      case EEPROM_24XX128:

         ctrl = (eeprom_cs_val<<1) & 0x07; //-- 00001110
         ctrl |= 0xA0; //-- 1010xxxx
         addr_hi = (eeprom_addr>>8) & 0x3F;
         addr_lo = eeprom_addr & 0xFF;
         break;

      case EEPROM_24XX256:

         ctrl = (eeprom_cs_val<<1) & 0x07; //-- 00001110
         ctrl |= 0xA0; //-- 1010xxxx
         addr_hi = (eeprom_addr>>8) & 0x7F;
         addr_lo = eeprom_addr & 0xFF;
         break;

      case EEPROM_24XX512:

         ctrl = (eeprom_cs_val<<1) & 0x07; //-- 00001110
         ctrl |= 0xA0; //-- 1010xxxx
         addr_hi = (eeprom_addr>>8) & 0xFF;
         addr_lo = eeprom_addr & 0xFF;
         break;
   }
   if(rc != I2C_NO_ERR)
      return rc;
   if(ctrl == 0)
      return I2C_ERR_24XX_BAD_TYPE;

   if(ctrl_val)
      *ctrl_val = ctrl;
   if(addr_hi_val)
      *addr_hi_val = addr_hi;
   if(addr_lo_val)
      *addr_lo_val = addr_lo;

   return I2C_NO_ERR;
}

//----------------------------------------------------------------------------
static int i2c_lpc_m24xx_wr(
     int eeprom_type,    //-- EEPROM type
     int eeprom_addr,    //-- start eeprom addr ( not included Hardware A2,A1,A0)
     int eeprom_cs_val,  //-- Hardware A2,A1,A0 (valid from 24XX32)
     char * buf,         //-- Data srs buf
     int num )            //-- Bytes to write qty
{
   int rc;
   int ctrl;
   int addr_hi;
   int addr_lo;

   rc = m24xx_set_addr(eeprom_type,eeprom_addr,eeprom_cs_val,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -