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

📄 i2c.c

📁 MPC8241:本程序是freescale的824*系列的BSP源程序
💻 C
📖 第 1 页 / 共 3 页
字号:

/***************************************************************************
 *     Copyright Motorola, Inc. 1989-2001 ALL RIGHTS RESERVED
 *
 *  $ID:$
 *
 * You are hereby granted a copyright license to use, modify, and
 * distribute the SOFTWARE, also know as DINK32 (Dynamic Interactive Nano 
 * Kernel for 32-bit processors) solely in conjunction with the development 
 * and marketing of your products which use and incorporate microprocessors 
 * which implement the PowerPC(TM) architecture manufactured by 
 * Motorola and provided you comply with all of the following restrictions 
 * i) this entire notice is retained without alteration in any
 * modified and/or redistributed versions, and 
 * ii) that such modified versions are clearly identified as such. 
 * No licenses are granted by implication, estoppel or
 * otherwise under any patents or trademarks of Motorola, Inc.
 * 
 * The SOFTWARE is provided on an "AS IS" basis and without warranty. To
 * the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS ALL
 * WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED WARRANTIES OF
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE AND ANY WARRANTY 
 * AGAINST INFRINGEMENT WITH REGARD TO THE SOFTWARE 
 * (INCLUDING ANY MODIFIED VERSIONS THEREOF) AND ANY ACCOMPANYING 
 * WRITTEN MATERIALS.
 * 
 * To the maximum extent permitted by applicable law, IN NO EVENT SHALL
 * MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING WITHOUT 
 * LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS 
 * INTERRUPTION, LOSS OF BUSINESS INFORMATION,
 * OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE
 * SOFTWARE.
 * Motorola assumes no responsibility for the maintenance and support of
 * the SOFTWARE.
 ************************************************************************/
#include "i2c_export.h"
#include "i2c.h"
/*#define I2CDBG0 */


/* Define a macro to use an optional application-layer print function, if
 * one was passed to the I2C library during initialization.  If there was
 * no function pointer passed, this protects against calling it.  Also define
 * the global variable that holds the passed pointer.
 */
/*#define PRINT if ( app_print ) app_print
static int (*app_print)(char *,...);*/
	 
/******************* Internal to I2C Driver *****************/
static unsigned int ByteToXmit = 0;
static unsigned int XmitByte = 0;
static unsigned char *XmitBuf = 0;
static unsigned int XmitBufEmptyStop =0;
static unsigned int ByteToRcv = 0;
static unsigned int RcvByte = 0;
static unsigned char *RcvBuf = 0;
static unsigned int RcvBufFulStop = 0;
static unsigned int MasterRcvAddress = 0;
static unsigned int GlobalTimer = 0;

/* Set by call to get_eumbbar during I2C_Initialize.
 * This could be globally available to the I2C library, but there is
 * an advantage to passing it as a parameter: it is already in a register
 * and doesn't have to be loaded from memory.  Also, that is the way the
 * I2C library was already implemented and I don't want to change it without
 * a more detailed analysis.
 * It is being set as a global variable in I2C_Initialize to hide it from 
 * the DINK application layer, because it is Kahlua-specific.  I think that 
 * get_eumbbar, load_runtime_reg, and store_runtime_reg should be defined in
 * a Kahlua-specific library dealing with the embedded utilities memory block.
 * Right now, get_eumbbar is defined in dink32/kahlua.s.  The other two are
 * defined in dink32/drivers/i2c/i2c2.s.
 */
static unsigned int Global_eumbbar = 0;
extern unsigned int get_eumbbar();
void         delay();
void I2cRead (unsigned char);
unsigned int I2cInit (void);
unsigned char READ_BUFFER[256]={0};
unsigned char WRITE_BUFFER[256]={0};

/*extern unsigned int load_runtime_reg( unsigned int eumbbar, unsigned int reg );
#pragma Alias( load_runtime_reg, "load_runtime_reg" )*/

/*extern unsigned int store_runtime_reg( unsigned int eumbbar, unsigned int reg, unsigned int val );
#pragma Alias( store_runtime_reg, "store_runtime_reg" )*/

/************************** API *****************/

/* Application Program Interface (API) are the calls provided by the I2C 
 * library to upper layer applications (i.e., DINK) to access the Kahlua
 * I2C bus interface.  The functions and values that are part of this API
 * are declared in i2c_export.h.
 */

/*  Initialize I2C unit with the following:
 *  driver's slave address
 *  interrupt enabled
 *  optional pointer to application layer print function
 *
 *  These parameters may be added:
 *  desired clock rate
 *  digital filter frequency sampling rate
 *
 *  This function must be called before I2C unit can be used.
 */
I2C_Status I2C_Initialize(
        unsigned char addr,
        I2C_INTERRUPT_MODE en_int,
        int (*p)(char *,...))
{
  I2CStatus status;
  /* establish the pointer, if there is one, to the application's "printf" */
  /*app_print = p;*/

  /* If this is the first call, get the embedded utilities memory block
   * base address.  I'm not sure what to do about error handling here:
   * if a non-zero value is returned, accept it.
   */
  if ( Global_eumbbar == 0)
     Global_eumbbar = get_eumbbar();
  if ( Global_eumbbar == 0)
  {
    printf( "I2C_Initialize: can't find EUMBBAR\n" );
    return I2C_ERROR;
  }

  /* validate the I2C address */
  if (addr & 0x80)
  {
    printf( "I2C_Initialize, I2C address invalid:  %d 0x%x\n", 
      (unsigned int)addr, (unsigned int)addr ); 
    return I2C_ERROR;
  }

  /* Call the internal I2C library function to perform work.
   * Accept the default frequency sampling rate (no way to set it currently,
   * via I2C_Init) and set the clock frequency to something reasonable.
   */
  status = I2C_Init( Global_eumbbar, (unsigned char)0x31, addr, en_int);
  if (status != I2CSUCCESS)
  {
    printf( "I2C_Initialize: error in initiation\n" );
    return I2C_ERROR;
  }

  /* all is well */
  return I2C_SUCCESS;
}


/* Perform the given I2C transaction, only MASTER_XMIT and MASTER_RCV
 * are implemented.  Both are only in polling mode.
 *
 * en_int controls interrupt/polling mode
 * act is the type of transaction
 * i2c_addr is the I2C address of the slave device
 * data_addr is the address of the data on the slave device
 * len is the length of data to send or receive
 * buffer is the address of the data buffer
 * stop = I2C_NO_STOP, don't signal STOP at end of transaction
 *        I2C_STOP, signal STOP at end of transaction
 * retry is the timeout retry value, currently ignored
 * rsta = I2C_NO_RESTART, this is not continuation of existing transaction
 *        I2C_RESTART, this is a continuation of existing transaction
 */
I2C_Status I2C_do_transaction( I2C_INTERRUPT_MODE en_int,
                               I2C_TRANSACTION_MODE act,
                               unsigned char i2c_addr,
                               unsigned char data_addr,
                               int len,
                               char *buffer,
                               I2C_STOP_MODE stop,
                               int retry,
                               I2C_RESTART_MODE rsta)
{
  I2C_Status status;
  unsigned char data_addr_buffer[1];

#if 1
/* This is a temporary work-around.  The I2C library breaks the protocol
 * if it attempts to handle a data transmission in more than one
 * transaction, so the data address and the actual data bytes are put
 * into a single buffer before sending it to the library internal functions.
 * The problem is related to being able to restart a transaction without
 * sending the I2C device address or repeating the data address.  It may take
 * a day or two to sort it all out, so I'll have to get back to it later.
 * Look at I2C_Start to see about using some status flags (I'm not sure that
 * "stop" and "rsta" are enough to reflect the states, maybe so; but the logic
 * in the library is insufficient) to control correct handling of the protocol.
 */
unsigned char dummy_buffer[257];
if (act == I2C_MASTER_XMIT)
{
int i;
for (i=1;i<=len;i++)dummy_buffer[i]=buffer[i-1];
dummy_buffer[0]=data_addr;
  status = I2C_do_buffer(en_int, act, i2c_addr, 1 + len, 
    dummy_buffer, stop, retry, rsta); 
  if (status != I2C_SUCCESS)
  {
    printf( "I2C_do_transaction: can't perform data transfer\n");
    return I2C_ERROR;
  }
return I2C_SUCCESS;
}
#endif /* end of temp work-around */

  /* validate requested transaction type */
  if ((act != I2C_MASTER_XMIT) && (act != I2C_MASTER_RCV))
  {
    printf( "I2C_do_transaction, invalid transaction request:  %d\n", act);
    return I2C_ERROR;
  }

  /* range check the I2C address */
  if (i2c_addr & 0x80)
  {
    printf( "I2C_do_transaction, I2C address out of range:  %d 0x%x\n", 
      (unsigned int)i2c_addr, (unsigned int)i2c_addr ); 
    return I2C_ERROR;
  } else {
    data_addr_buffer[0] = data_addr;
  }

  /* We first have to contact the slave device and transmit the data address.
   * Be careful about the STOP and restart stuff.  We don't want to signal STOP 
   * after sending the data address, but this could be a continuation if the
   * application didn't release the bus after the previous transaction, by
   * not sending a STOP after it.
   */
  status = I2C_do_buffer(en_int, I2C_MASTER_XMIT, i2c_addr, 1, 
   data_addr_buffer, I2C_NO_STOP, retry, rsta); 
  if (status != I2C_SUCCESS)
  {
#ifdef I2CDBG0
    printf( "I2C_do_transaction: can't send data address for read\n");
#endif
    return I2C_ERROR;
  }

  /* The data transfer will be a continuation. */
  rsta = I2C_RESTART;

  /* now handle the user data */
  status = I2C_do_buffer(en_int, act, i2c_addr, len, 
    buffer, stop, retry, rsta); 
  if (status != I2C_SUCCESS)
  {
#ifdef I2CDBG0
    printf( "I2C_do_transaction: can't perform data transfer\n");
#endif
    return I2C_ERROR;
  }

  /* all is well */
  return I2C_SUCCESS;
}

/* This function performs the work for I2C_do_transaction.  The work is
 * split into this function to enable I2C_do_transaction to first transmit
 * the data address to the I2C slave device without putting the data address
 * into the first byte of the buffer.
 *
 * en_int controls interrupt/polling mode
 * act is the type of transaction
 * i2c_addr is the I2C address of the slave device
 * len is the length of data to send or receive
 * buffer is the address of the data buffer
 * stop = I2C_NO_STOP, don't signal STOP at end of transaction
 *        I2C_STOP, signal STOP at end of transaction
 * retry is the timeout retry value, currently ignored
 * rsta = I2C_NO_RESTART, this is not continuation of existing transaction
 *        I2C_RESTART, this is a continuation of existing transaction
 */
static I2C_Status I2C_do_buffer( I2C_INTERRUPT_MODE en_int,
                                 I2C_TRANSACTION_MODE act,
                                 unsigned char i2c_addr,
                                 int len,
                                 unsigned char *buffer,
                                 I2C_STOP_MODE stop,
                                 int retry,
                                 I2C_RESTART_MODE rsta)
{
  I2CStatus rval;
  unsigned int dev_stat;
  if (act == I2C_MASTER_RCV)
  {
    /* set up for master-receive transaction */
    rval = I2C_get(Global_eumbbar,i2c_addr,buffer,len,stop,rsta);
  } else {
    /* set up for master-transmit transaction */
    rval = I2C_put(Global_eumbbar,i2c_addr,buffer,len,stop,rsta);
  }

  /* validate the setup */
  if ( rval != I2CSUCCESS )
  {
    dev_stat = load_runtime_reg( Global_eumbbar, I2CSR );

#ifdef I2CDBG0
    printf( "Error(I2C_do_buffer): control phase, code(0x%08x), status(0x%08x)\n", rval, dev_stat);
#endif
    I2C_Stop( Global_eumbbar );
    return I2C_ERROR;
  }

  if (en_int == 1)
  {
    /* this should not happen, no interrupt handling yet */
    return I2C_SUCCESS;
  }

  /* this performs the polling action, when the transfer is completed,
   * the status returned from I2C_Timer_Event will be I2CBUFFFULL or
   * I2CBUFFEMPTY (rcv or xmit), I2CSUCCESS or I2CADDRESS indicates the
   * transaction is not yet complete, anything else is an error.
   */

	GlobalTimer = (retry / 10);

  while ( rval == I2CSUCCESS || rval == I2CADDRESS )
  {
    /* poll the device until something happens */
    do
    {
      rval = I2C_Timer_Event( Global_eumbbar, 0 );
    }
    while ( rval == I2CNOEVENT );

    /* check for error condition */
    if ( rval == I2CSUCCESS || rval == I2CBUFFFULL ||
         rval == I2CBUFFEMPTY || rval == I2CADDRESS )
    { ; /* do nothing */
    } else {
      /* report the error condition */
      dev_stat = load_runtime_reg( Global_eumbbar, I2CSR );

#ifdef I2CDBG0
      printf( "Error(I2C_do_buffer):  code(0x%08x), status(0x%08x)\n", rval, dev_stat );
#endif
      return I2C_ERROR;
    }
  }

  /* all is well */
  return I2C_SUCCESS;
}

/**
 * Note:
 *
 * In all following functions,
 * the caller shall pass the configured embedded utility memory
 * block base, EUMBBAR.
 **/

/***********************************************************
 * function: I2C_put
 *
 * description:
   Send a buffer of data to the intended rcv_addr. 
 * If stop_flag is set, after the whole buffer 
 * is sent, generate a STOP signal provided that the
 * receiver doesn't signal the STOP in the middle.
 * I2C is the master performing transmitting. If
 * no STOP signal is generated at the end of current
 * transaction, the master can generate a START signal
 * to another slave addr.
 *
 * note: this is master xmit API
 *********************************************************/
static I2CStatus I2C_put( unsigned int   eumbbar,
                   unsigned char  rcv_addr,   /* receiver's address */
                   unsigned char *buffer_ptr, /* pointer of data to be sent */
                   unsigned int  length,      /* number of byte of in the buffer */
                   unsigned int  stop_flag,   /* 1 - signal STOP when buffer is empty
                                               * 0 - no STOP signal when buffer is empty
                                               */
                   unsigned int is_cnt )      /* 1 - this is a restart, don't check MBB
                                               * 0 - this is a new start, check MBB
                                               */
		  
{
    if ( buffer_ptr == 0 || length == 0 )
    {
      return I2CERROR;
    }

#ifdef I2CDBG0
	printf( "%s(%d): I2C_put\n", __FILE__, __LINE__ );
#endif
	
    XmitByte = 0;
    ByteToXmit = length;
    XmitBuf = buffer_ptr;
    XmitBufEmptyStop = stop_flag;

    RcvByte = 0;
    ByteToRcv = 0;
    RcvBuf = 0;

    /* we are the master, start transaction */
    return I2C_Start( eumbbar, rcv_addr, XMIT, is_cnt );
}

/***********************************************************
 * function: I2C_get
 *
 * description:
 * Receive a buffer of data from the desired sender_addr
 * If stop_flag is set, when the buffer is full and the 
 * sender does not signal STOP, generate a STOP signal.
 * I2C is the master performing receiving. If no STOP signal
 * is generated, the master can generate a START signal
 * to another slave addr.
 *

⌨️ 快捷键说明

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