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

📄 i2c1.c

📁 嵌入式linux的bsp
💻 C
📖 第 1 页 / 共 3 页
字号:
/************************************************************* * * Copyright @ Motorola, 1999 * ************************************************************/#include "i2c_export.h"#include "i2c.h"/* 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_printstatic 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;/* 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();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)  {    PRINT( "I2C_Initialize: can't find EUMBBAR\n" );    return I2C_ERROR;  }  /* validate the I2C address */  if (addr & 0x80)  {    PRINT( "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)  {    PRINT( "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)  {    PRINT( "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))  {    PRINT( "I2C_do_transaction, invalid transaction request:  %d\n", act);    return I2C_ERROR;  }  /* range check the I2C address */  if (i2c_addr & 0x80)  {    PRINT( "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)  {    PRINT( "I2C_do_transaction: can't send data address for read\n");    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)  {    PRINT( "I2C_do_transaction: can't perform data transfer\n");    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 );    PRINT( "Error(I2C_do_buffer): control phase, code(0x%08x), status(0x%08x)\n", rval, dev_stat);    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.   */  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 );      PRINT( "Error(I2C_do_buffer):  code(0x%08x), status(0x%08x)\n", rval, dev_stat );      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	PRINT( "%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. * * note: this is master receive API **********************************************************/static I2CStatus I2C_get( unsigned int eumbbar,		   unsigned char rcv_from,    /* sender's address */		   unsigned char *buffer_ptr, /* pointer of receiving buffer */		   unsigned int  length,      /* length of the receiving buffer */		   unsigned int  stop_flag,   /* 1 - signal STOP when buffer is full			                       * 0 - no STOP signal when buffer is full				               */		   unsigned int is_cnt )      /* 1 - this is a restart, don't check MBB					       * 0 - this is a new start, check MBB                                               */{

⌨️ 快捷键说明

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