Página 1 de 2

como configurar o I2C no LPC4350

MensagemEnviado: 07 Fev 2013 10:39
por Larissa
Como faço para configurar o i2c no modo mestre e como faço para endereçar o escravo?

se alguém tem algum código de exemplo agradeço.

MensagemEnviado: 09 Fev 2013 09:52
por tcpipchip
Código: Selecionar todos
/**********************************************************************
* $Id$      lpc43xx_i2c.c      2011-06-02
*//**
* @file      lpc43xx_i2c.c
* @brief   Contains all functions support for I2C firmware library
*          on lpc43xx
* @version   1.0
* @date      02. June. 2011
* @author   NXP MCU SW Application Team
*
* Copyright(C) 2011, NXP Semiconductor
* All rights reserved.
*
***********************************************************************
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors’
* relevant copyright in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers.  This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
**********************************************************************/

/* Peripheral group ----------------------------------------------------------- */
/** @addtogroup I2C
 * @{
 */

/* Includes ------------------------------------------------------------------- */
#include "lpc43xx_i2c.h"
#include "lpc43xx_cgu.h"
#include "lpc43xx_scu.h"

/* If this source file built with example, the lpc43xx FW library configuration
 * file in each example directory ("lpc43xx_libcfg.h") must be included,
 * otherwise the default FW library configuration file must be included instead
 */
#ifdef __BUILD_WITH_EXAMPLE__
#include "lpc43xx_libcfg.h"
#else
#include "lpc43xx_libcfg_default.h"
#endif /* __BUILD_WITH_EXAMPLE__ */


#ifdef _I2C


/* Private Types -------------------------------------------------------------- */
/** @defgroup I2C_Private_Types I2C Private Types
 * @{
 */
#define SFSP2_3_CONFIGURE_I2C1_SDA               (0x00000001 | MD_ZI | MD_EZI)
#define SFSP2_4_CONFIGURE_I2C1_SCL               (0x00000001 | MD_ZI | MD_EZI)
#define SFSI2C0_CONFIGURE_STANDARD_FAST_MODE      (1<<3 | 1<<11)
#define SFSI2C0_CONFIGURE_FASTPLUS_HIGHSPEED_MODE   (2<<1 | 1<<3 | 1<<7 | 1<<10 | 1<<11)

/**
 * @brief I2C device configuration structure type
 */
typedef struct
{
  uint32_t      txrx_setup;                   /* Transmission setup */
  int32_t      dir;                        /* Current direction phase, 0 - write, 1 - read */
} I2C_CFG_T;

/**
 * @}
 */

/* Private Variables ---------------------------------------------------------- */
/**
 * @brief II2C driver data for I2C0, I2C1
 */
static I2C_CFG_T i2cdat[3];

volatile static uint32_t I2C_MasterComplete[3];
volatile static uint32_t I2C_SlaveComplete[3];

static uint32_t I2C_MonitorBufferIndex;

/* Private Functions ---------------------------------------------------------- */

/* Get I2C number */
static int32_t I2C_getNum(LPC_I2Cn_Type *I2Cx);

/* Generate a start condition on I2C bus (in master mode only) */
static uint32_t I2C_Start (LPC_I2Cn_Type *I2Cx);

/* Generate a stop condition on I2C bus (in master mode only) */
static void I2C_Stop (LPC_I2Cn_Type *I2Cx);

/* I2C send byte subroutine */
static uint32_t I2C_SendByte (LPC_I2Cn_Type *I2Cx, uint8_t databyte);

/* I2C get byte subroutine */
static uint32_t I2C_GetByte (LPC_I2Cn_Type *I2Cx, uint8_t *retdat, Bool ack);

/*--------------------------------------------------------------------------------*/
/********************************************************************//**
 * @brief      Convert from I2C peripheral to number
 * @param[in]   I2Cx I2C peripheral selected, should be:
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @return       I2C number or error code, could be:
 *                - 0      :I2C0
 *                - 1      :I2C1
 *                - (-1)   :Error
 *********************************************************************/
static int32_t I2C_getNum(LPC_I2Cn_Type *I2Cx){
   if (I2Cx == LPC_I2C0) {
      return (0);
   } else if (I2Cx == LPC_I2C1) {
      return (1);
   }
   return (-1);
}


/********************************************************************//**
 * @brief      Generate a start condition on I2C bus (in master mode only)
 * @param[in]   I2Cx I2C peripheral selected, should be:
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @return       value of I2C status register after generate a start condition
 *********************************************************************/
static uint32_t I2C_Start (LPC_I2Cn_Type *I2Cx)
{
   I2Cx->CONCLR = I2C_I2CONCLR_SIC; // Clear interrupt
   I2Cx->CONSET = I2C_I2CONSET_STA; // Send "Start"

   // Wait for complete
   while (!(I2Cx->CONSET & I2C_I2CONSET_SI));
   I2Cx->CONCLR = I2C_I2CONCLR_STAC;
   return (I2Cx->STAT & I2C_STAT_CODE_BITMASK);
}


/********************************************************************//**
 * @brief      Generate a stop condition on I2C bus (in master mode only)
 * @param[in]   I2Cx I2C peripheral selected, should be:
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @return       None
 *********************************************************************/
static void I2C_Stop (LPC_I2Cn_Type *I2Cx)
{

   /* Make sure start bit is not active */
   if (I2Cx->CONSET & I2C_I2CONSET_STA)
   {
      I2Cx->CONCLR = I2C_I2CONCLR_STAC;
   }
   I2Cx->CONSET = I2C_I2CONSET_STO;
   I2Cx->CONCLR = I2C_I2CONCLR_SIC;
}


/********************************************************************//**
 * @brief      Send a byte
 * @param[in]   I2Cx I2C peripheral selected, should be:
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @param[in]   databyte   sent data
 * @return       value of I2C status register after sending
 *********************************************************************/
static uint32_t I2C_SendByte (LPC_I2Cn_Type *I2Cx, uint8_t databyte)
{
   /* Make sure start bit is not active */
   if (I2Cx->CONSET & I2C_I2CONSET_STA)
   {
      I2Cx->CONCLR = I2C_I2CONCLR_STAC;
   }
   I2Cx->DAT = databyte & I2C_I2DAT_BITMASK;
   I2Cx->CONCLR = I2C_I2CONCLR_SIC;

   while (!(I2Cx->CONSET & I2C_I2CONSET_SI));
   return (I2Cx->STAT & I2C_STAT_CODE_BITMASK);
}


/********************************************************************//**
 * @brief      Get a byte
 * @param[in]   I2Cx I2C peripheral selected, should be:
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @param[out]   retdat   pointer to return data
 * @param[in]   ack      assert acknowledge or not, should be: TRUE/FALSE
 * @return       value of I2C status register after sending
 *********************************************************************/
static uint32_t I2C_GetByte (LPC_I2Cn_Type *I2Cx, uint8_t *retdat, Bool ack)
{
   if (ack == TRUE)
   {
      I2Cx->CONSET = I2C_I2CONSET_AA;
   }
   else
   {
      I2Cx->CONCLR = I2C_I2CONCLR_AAC;
   }
   I2Cx->CONCLR = I2C_I2CONCLR_SIC;

   while (!(I2Cx->CONSET & I2C_I2CONSET_SI));
   *retdat = (uint8_t) (I2Cx->DAT & I2C_I2DAT_BITMASK);
   return (I2Cx->STAT & I2C_STAT_CODE_BITMASK);
}

/* End of Private Functions --------------------------------------------------- */


/* Public Functions ----------------------------------------------------------- */
/** @addtogroup I2C_Public_Functions
 * @{
 */

/********************************************************************//**
 * @brief      Initializes the I2Cx peripheral with specified parameter.
 * @param[in]   I2Cx   I2C peripheral selected, should be
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @param[in]   clockrate Target clock rate value to initialized I2C
 *             peripheral (Hz)
 * @return       None
 *********************************************************************/
void I2C_Init(LPC_I2Cn_Type *I2Cx, uint32_t clockrate)
{
   uint32_t tem;

   CHECK_PARAM(PARAM_I2Cx(I2Cx));

   if (I2Cx==LPC_I2C0)
   {
      /* Set up clock for I2C0 module */
      //LPC_CGU->BASE_VPB1_CLK = (SRC_PL160M_0<<24) | (1<<11);
      CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_BASE_APB1);
      /* Select weather standard, fast, fast plus mode*/
      if(clockrate>=1000000)// Fast mode plus: 1MHz, high speed 3.4MHz
         LPC_SCU->SFSI2C0 = SFSI2C0_CONFIGURE_FASTPLUS_HIGHSPEED_MODE;
      else              // standard 100KHz, fast 400KHz
         LPC_SCU->SFSI2C0 = SFSI2C0_CONFIGURE_STANDARD_FAST_MODE;
   }
   else if (I2Cx==LPC_I2C1)
   {
      /* Set up clock for I2C1 module */
      //LPC_CGU->BASE_VPB3_CLK = (SRC_PL160M_0<<24) | (1<<11);
      CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_BASE_APB3);
      /* Configure pin function for I2C1*/
      LPC_SCU->SFSP2_3 = SFSP2_3_CONFIGURE_I2C1_SDA;         /* SDA */
      LPC_SCU->SFSP2_4 = SFSP2_4_CONFIGURE_I2C1_SCL;         /* SCL */
      /* Check if I2C1 run fast mode*/
        if(clockrate != 400000)
           return;
   }
   else {
      // Up-Support this device
      return;
   }

    /* Set clock rate */
   if(clockrate<1000)   //make sure SCLH,SCLL not exceed its 16bit value
      return;
   tem = CGU_GetPCLKFrequency(CGU_PERIPHERAL_M4CORE) / clockrate;
   I2Cx->SCLH = (uint32_t)(tem / 2);
   I2Cx->SCLL = (uint32_t)(tem - I2Cx->SCLH);
    /* Set I2C operation to default */
    I2Cx->CONCLR = (I2C_I2CONCLR_AAC |I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC | I2C_I2CONCLR_I2ENC);
}


/*********************************************************************//**
 * @brief      De-initializes the I2C peripheral registers to their
 *                  default reset values.
 * @param[in]   I2Cx   I2C peripheral selected, should be
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @return       None
 **********************************************************************/
void I2C_DeInit(LPC_I2Cn_Type* I2Cx)
{
   CHECK_PARAM(PARAM_I2Cx(I2Cx));

   /* Disable I2C control */
   I2Cx->CONCLR = I2C_I2CONCLR_I2ENC;

}


/*********************************************************************//**
 * @brief      Enable or disable I2C peripheral's operation
 * @param[in]   I2Cx I2C peripheral selected, should be
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @param[in]   NewState New State of I2Cx peripheral's operation, should be:
 *                - ENABLE   :enable I2C operation
 *                - DISABLE   :disable I2C operation
 * @return       none
 **********************************************************************/
void I2C_Cmd(LPC_I2Cn_Type* I2Cx, FunctionalState NewState)
{
   CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState));
   CHECK_PARAM(PARAM_I2Cx(I2Cx));

   if (NewState == ENABLE)
   {
      I2Cx->CONSET = I2C_I2CONSET_I2EN;
   }
   else
   {
      I2Cx->CONCLR = I2C_I2CONCLR_I2ENC;
   }
}


/*********************************************************************//**
 * @brief       Enable/Disable interrupt for I2C peripheral
 * @param[in]   I2Cx   I2C peripheral selected, should be:
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @param[in]   NewState   New State of I2C peripheral interrupt in NVIC core
 *             should be:
 *                - ENABLE: enable interrupt for this I2C peripheral
 *                - DISABLE: disable interrupt for this I2C peripheral
 * @return       None
 **********************************************************************/
void I2C_IntCmd (LPC_I2Cn_Type *I2Cx, Bool NewState)
{
   if (NewState)
   {
      if(I2Cx == LPC_I2C0)
      {
         NVIC_EnableIRQ(I2C0_IRQn);
      }
      else if (I2Cx == LPC_I2C1)
      {
         NVIC_EnableIRQ(I2C1_IRQn);
      }
   }
   else
   {
      if(I2Cx == LPC_I2C0)
      {
         NVIC_DisableIRQ(I2C0_IRQn);
      }
      else if (I2Cx == LPC_I2C1)
      {
         NVIC_DisableIRQ(I2C1_IRQn);
      }
   }
    return;
}


/*********************************************************************//**
 * @brief       General Master Interrupt handler for I2C peripheral
 * @param[in]   I2Cx   I2C peripheral selected, should be:
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @return       None
 **********************************************************************/
void I2C_MasterHandler (LPC_I2Cn_Type  *I2Cx)
{
   int32_t tmp;
   uint8_t returnCode;
   I2C_M_SETUP_Type *txrx_setup;

   tmp = I2C_getNum(I2Cx);
   txrx_setup = (I2C_M_SETUP_Type *) i2cdat[tmp].txrx_setup;

   returnCode = (I2Cx->STAT & I2C_STAT_CODE_BITMASK);
   // Save current status
   txrx_setup->status = returnCode;
   // there's no relevant information
   if (returnCode == I2C_I2STAT_NO_INF){
      I2Cx->CONCLR = I2C_I2CONCLR_SIC;
      return;
   }

   /* ----------------------------- TRANSMIT PHASE --------------------------*/
   if (i2cdat[tmp].dir == 0){
      switch (returnCode)
      {
      /* A start/repeat start condition has been transmitted -------------------*/
      case I2C_I2STAT_M_TX_START:
      case I2C_I2STAT_M_TX_RESTART:
         I2Cx->CONCLR = I2C_I2CONCLR_STAC;
         /*
          * If there's any transmit data, then start to
          * send SLA+W right now, otherwise check whether if there's
          * any receive data for next state.
          */
         if ((txrx_setup->tx_data != NULL) && (txrx_setup->tx_length != 0)){
            I2Cx->DAT = (txrx_setup->sl_addr7bit << 1);
            I2Cx->CONCLR = I2C_I2CONCLR_SIC;
         } else {
            goto next_stage;
         }
         break;

      /* SLA+W has been transmitted, ACK has been received ----------------------*/
      case I2C_I2STAT_M_TX_SLAW_ACK:
      /* Data has been transmitted, ACK has been received */
      case I2C_I2STAT_M_TX_DAT_ACK:
         /* Send more data */
         if ((txrx_setup->tx_count < txrx_setup->tx_length) \
               && (txrx_setup->tx_data != NULL)){
            I2Cx->DAT =  *(uint8_t *)(txrx_setup->tx_data + txrx_setup->tx_count);
            txrx_setup->tx_count++;
            I2Cx->CONCLR = I2C_I2CONCLR_SIC;
         }
         // no more data, switch to next stage
         else {
next_stage:
            // change direction
            i2cdat[tmp].dir = 1;
            // Check if any data to receive
            if ((txrx_setup->rx_length != 0) && (txrx_setup->rx_data != NULL)){
                  // check whether if we need to issue an repeat start
                  if ((txrx_setup->tx_length != 0) && (txrx_setup->tx_data != NULL)){
                     // Send out an repeat start command
                     I2Cx->CONSET = I2C_I2CONSET_STA;
                     I2Cx->CONCLR = I2C_I2CONCLR_AAC | I2C_I2CONCLR_SIC;
                  }
                  // Don't need issue an repeat start, just goto send SLA+R
                  else {
                     goto send_slar;
                  }
            }
            // no more data send, the go to end stage now
            else {
               // success, goto end stage
               txrx_setup->status |= I2C_SETUP_STATUS_DONE;
               goto end_stage;
            }
         }
         break;

      /* SLA+W has been transmitted, NACK has been received ----------------------*/
      case I2C_I2STAT_M_TX_SLAW_NACK:
      /* Data has been transmitted, NACK has been received -----------------------*/
      case I2C_I2STAT_M_TX_DAT_NACK:
         // update status
         txrx_setup->status |= I2C_SETUP_STATUS_NOACKF;
         goto retry;
      /* Arbitration lost in SLA+R/W or Data bytes -------------------------------*/
      case I2C_I2STAT_M_TX_ARB_LOST:
         // update status
         txrx_setup->status |= I2C_SETUP_STATUS_ARBF;
      default:
         goto retry;
      }
   }

   /* ----------------------------- RECEIVE PHASE --------------------------*/
   else if (i2cdat[tmp].dir == 1){
      switch (returnCode){
         /* A start/repeat start condition has been transmitted ---------------------*/
      case I2C_I2STAT_M_RX_START:
      case I2C_I2STAT_M_RX_RESTART:
         I2Cx->CONCLR = I2C_I2CONCLR_STAC;
         /*
          * If there's any receive data, then start to
          * send SLA+R right now, otherwise check whether if there's
          * any receive data for end of state.
          */
         if ((txrx_setup->rx_data != NULL) && (txrx_setup->rx_length != 0)){
send_slar:
            I2Cx->DAT = (txrx_setup->sl_addr7bit << 1) | 0x01;
            I2Cx->CONCLR = I2C_I2CONCLR_SIC;
         } else {
            // Success, goto end stage
            txrx_setup->status |= I2C_SETUP_STATUS_DONE;
            goto end_stage;
         }
         break;

      /* SLA+R has been transmitted, ACK has been received -----------------*/
      case I2C_I2STAT_M_RX_SLAR_ACK:
         if (txrx_setup->rx_count < (txrx_setup->rx_length - 1)) {
            /*Data will be received,  ACK will be return*/
            I2Cx->CONSET = I2C_I2CONSET_AA;
         }
         else {
            /*Last data will be received,  NACK will be return*/
            I2Cx->CONCLR = I2C_I2CONSET_AA;
         }
         I2Cx->CONCLR = I2C_I2CONCLR_SIC;
         break;

      /* Data has been received, ACK has been returned ----------------------*/
      case I2C_I2STAT_M_RX_DAT_ACK:
         // Note save data and increase counter first, then check later
         /* Save data  */
         if ((txrx_setup->rx_data != NULL) && (txrx_setup->rx_count < txrx_setup->rx_length)){
            *(uint8_t *)(txrx_setup->rx_data + txrx_setup->rx_count) = (I2Cx->DAT & I2C_I2DAT_BITMASK);
            txrx_setup->rx_count++;
         }
         if (txrx_setup->rx_count < (txrx_setup->rx_length - 1)) {
            /*Data will be received,  ACK will be return*/
            I2Cx->CONSET = I2C_I2CONSET_AA;
         }
         else {
            /*Last data will be received,  NACK will be return*/
            I2Cx->CONCLR = I2C_I2CONSET_AA;
         }

         I2Cx->CONCLR = I2C_I2CONCLR_SIC;
         break;

      /* Data has been received, NACK has been return -------------------------*/
      case I2C_I2STAT_M_RX_DAT_NACK:
         /* Save the last data */
         if ((txrx_setup->rx_data != NULL) && (txrx_setup->rx_count < txrx_setup->rx_length)){
            *(uint8_t *)(txrx_setup->rx_data + txrx_setup->rx_count) = (I2Cx->DAT & I2C_I2DAT_BITMASK);
            txrx_setup->rx_count++;
         }
         // success, go to end stage
         txrx_setup->status |= I2C_SETUP_STATUS_DONE;
         goto end_stage;

      /* SLA+R has been transmitted, NACK has been received ------------------*/
      case I2C_I2STAT_M_RX_SLAR_NACK:
         // update status
         txrx_setup->status |= I2C_SETUP_STATUS_NOACKF;
         goto retry;

      /* Arbitration lost ----------------------------------------------------*/
      case I2C_I2STAT_M_RX_ARB_LOST:
         // update status
         txrx_setup->status |= I2C_SETUP_STATUS_ARBF;
      default:
retry:
         // check if retransmission is available
         if (txrx_setup->retransmissions_count < txrx_setup->retransmissions_max){
            // Clear tx count
            txrx_setup->tx_count = 0;
            I2Cx->CONSET = I2C_I2CONSET_STA;
            I2Cx->CONCLR = I2C_I2CONCLR_AAC | I2C_I2CONCLR_SIC;
            txrx_setup->retransmissions_count++;
         }
         // End of stage
         else {
end_stage:
            // Disable interrupt
            I2C_IntCmd(I2Cx, FALSE);
            // Send stop
            I2C_Stop(I2Cx);
            
            I2C_MasterComplete[tmp] = TRUE;
         }
         break;
      }
   }
}


/*********************************************************************//**
 * @brief       General Slave Interrupt handler for I2C peripheral
 * @param[in]   I2Cx   I2C peripheral selected, should be:
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @return       None
 **********************************************************************/
void I2C_SlaveHandler (LPC_I2Cn_Type  *I2Cx)
{
   int32_t tmp;
   uint8_t returnCode;
   I2C_S_SETUP_Type *txrx_setup;
   uint32_t timeout;

   tmp = I2C_getNum(I2Cx);
   txrx_setup = (I2C_S_SETUP_Type *) i2cdat[tmp].txrx_setup;

   returnCode = (I2Cx->STAT & I2C_STAT_CODE_BITMASK);
   // Save current status
   txrx_setup->status = returnCode;
   // there's no relevant information
   if (returnCode == I2C_I2STAT_NO_INF){
      I2Cx->CONCLR = I2C_I2CONCLR_SIC;
      return;
   }


   switch (returnCode)
   {

   /* No status information */
   case I2C_I2STAT_NO_INF:
      I2Cx->CONSET = I2C_I2CONSET_AA;
      I2Cx->CONCLR = I2C_I2CONCLR_SIC;
      break;

   /* Reading phase -------------------------------------------------------- */
   /* Own SLA+R has been received, ACK has been returned */
   case I2C_I2STAT_S_RX_SLAW_ACK:
   /* General call address has been received, ACK has been returned */
   case I2C_I2STAT_S_RX_GENCALL_ACK:
      I2Cx->CONSET = I2C_I2CONSET_AA;
      I2Cx->CONCLR = I2C_I2CONCLR_SIC;
      break;

   /* Previously addressed with own SLA;
    * DATA byte has been received;
    * ACK has been returned */
   case I2C_I2STAT_S_RX_PRE_SLA_DAT_ACK:
   /* DATA has been received, ACK hasn been return */
   case I2C_I2STAT_S_RX_PRE_GENCALL_DAT_ACK:
      /*
       * All data bytes that over-flow the specified receive
       * data length, just ignore them.
       */
      if ((txrx_setup->rx_count < txrx_setup->rx_length) \
            && (txrx_setup->rx_data != NULL)){
         *(uint8_t *)(txrx_setup->rx_data + txrx_setup->rx_count) = (uint8_t)I2Cx->DAT;
         txrx_setup->rx_count++;
      }
      I2Cx->CONSET = I2C_I2CONSET_AA;
      I2Cx->CONCLR = I2C_I2CONCLR_SIC;
      break;

   /* Previously addressed with own SLA;
    * DATA byte has been received;
    * NOT ACK has been returned */
   case I2C_I2STAT_S_RX_PRE_SLA_DAT_NACK:
   /* DATA has been received, NOT ACK has been returned */
   case I2C_I2STAT_S_RX_PRE_GENCALL_DAT_NACK:
      I2Cx->CONCLR = I2C_I2CONCLR_SIC;
      break;

   /*
    * Note that: Return code only let us know a stop condition mixed
    * with a repeat start condition in the same code value.
    * So we should provide a time-out. In case this is really a stop
    * condition, this will return back after time out condition. Otherwise,
    * next session that is slave receive data will be completed.
    */

   /* A Stop or a repeat start condition */
   case I2C_I2STAT_S_RX_STA_STO_SLVREC_SLVTRX:
      // Temporally lock the interrupt for timeout condition
      I2C_IntCmd(I2Cx, FALSE);
      I2Cx->CONCLR = I2C_I2CONCLR_SIC;
      // enable time out
      timeout = I2C_SLAVE_TIME_OUT;
      while(1){
         if (I2Cx->CONSET & I2C_I2CONSET_SI){
            // re-Enable interrupt
            I2C_IntCmd(I2Cx, TRUE);
            break;
         } else {
            timeout--;
            if (timeout == 0){
               // timeout occur, it's really a stop condition
               txrx_setup->status |= I2C_SETUP_STATUS_DONE;
               goto s_int_end;
            }
         }
      }
      break;

   /* Writing phase -------------------------------------------------------- */
   /* Own SLA+R has been received, ACK has been returned */
   case I2C_I2STAT_S_TX_SLAR_ACK:
   /* Data has been transmitted, ACK has been received */
   case I2C_I2STAT_S_TX_DAT_ACK:
      /*
       * All data bytes that over-flow the specified receive
       * data length, just ignore them.
       */
      if ((txrx_setup->tx_count < txrx_setup->tx_length) \
            && (txrx_setup->tx_data != NULL)){
         I2Cx->DAT = *(uint8_t *) (txrx_setup->tx_data + txrx_setup->tx_count);
         txrx_setup->tx_count++;
      }
      I2Cx->CONSET = I2C_I2CONSET_AA;
      I2Cx->CONCLR = I2C_I2CONCLR_SIC;
      break;

   /* Data has been transmitted, NACK has been received,
    * that means there's no more data to send, exit now */
   /*
    * Note: Don't wait for stop event since in slave transmit mode,
    * since there no proof lets us know when a stop signal has been received
    * on slave side.
    */
   case I2C_I2STAT_S_TX_DAT_NACK:
      I2Cx->CONSET = I2C_I2CONSET_AA;
      I2Cx->CONCLR = I2C_I2CONCLR_SIC;
      txrx_setup->status |= I2C_SETUP_STATUS_DONE;
      goto s_int_end;

   // Other status must be captured
   default:
s_int_end:
      // Disable interrupt
      I2C_IntCmd(I2Cx, FALSE);
      I2Cx->CONCLR = I2C_I2CONCLR_AAC | I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC;
      I2C_SlaveComplete[tmp] = TRUE;
      break;
   }
}


/*********************************************************************//**
 * @brief       Transmit and Receive data in master mode
 * @param[in]   I2Cx I2C peripheral selected, should be:
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @param[in]   TransferCfg   Pointer to a I2C_M_SETUP_Type structure that
 *             contains specified information about the configuration
 *             for master transfer.
 * @param[in]   Opt   a I2C_TRANSFER_OPT_Type type that selected for interrupt
 *             or polling mode.
 * @return       Transmit/receive status, should be:
 *                - SUCCESS
 *                - ERROR
 *
 * Note:
 * - In case of using I2C to transmit data only, either transmit length set to 0
 * or transmit data pointer set to NULL.
 * - In case of using I2C to receive data only, either receive length set to 0
 * or receive data pointer set to NULL.
 * - In case of using I2C to transmit followed by receive data, transmit length,
 * transmit data pointer, receive length and receive data pointer should be set
 * corresponding.
 **********************************************************************/
Status I2C_MasterTransferData(LPC_I2Cn_Type *I2Cx, I2C_M_SETUP_Type *TransferCfg, \
                        I2C_TRANSFER_OPT_Type Opt)
{
   uint8_t *txdat;
   uint8_t *rxdat;
   uint32_t CodeStatus;
   uint8_t tmp;

   // reset all default state
   txdat = (uint8_t *) TransferCfg->tx_data;
   rxdat = (uint8_t *) TransferCfg->rx_data;
   // Reset I2C setup value to default state
   TransferCfg->tx_count = 0;
   TransferCfg->rx_count = 0;
   TransferCfg->status = 0;

   if (Opt == I2C_TRANSFER_POLLING){

      /* First Start condition -------------------------------------------------------------- */
      TransferCfg->retransmissions_count = 0;
retry:
      // reset all default state
      txdat = (uint8_t *) TransferCfg->tx_data;
      rxdat = (uint8_t *) TransferCfg->rx_data;
      // Reset I2C setup value to default state
      TransferCfg->tx_count = 0;
      TransferCfg->rx_count = 0;
      CodeStatus = 0;

      // Start command
      CodeStatus = I2C_Start(I2Cx);
      if ((CodeStatus != I2C_I2STAT_M_TX_START) \
            && (CodeStatus != I2C_I2STAT_M_TX_RESTART)){
         TransferCfg->retransmissions_count++;
         if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){
            // save status
            TransferCfg->status = CodeStatus;
            goto error;
         } else {
            goto retry;
         }
      }

      /* In case of sending data first --------------------------------------------------- */
      if ((TransferCfg->tx_length != 0) && (TransferCfg->tx_data != NULL)){

         /* Send slave address + WR direction bit = 0 ----------------------------------- */
         CodeStatus = I2C_SendByte(I2Cx, (TransferCfg->sl_addr7bit << 1));
         if (CodeStatus != I2C_I2STAT_M_TX_SLAW_ACK){
            TransferCfg->retransmissions_count++;
            if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){
               // save status
               TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_NOACKF;
               goto error;
            } else {
               goto retry;
            }
         }

         /* Send a number of data bytes ---------------------------------------- */
         while (TransferCfg->tx_count < TransferCfg->tx_length)
         {
            CodeStatus = I2C_SendByte(I2Cx, *txdat);
            if (CodeStatus != I2C_I2STAT_M_TX_DAT_ACK){
               TransferCfg->retransmissions_count++;
               if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){
                  // save status
                  TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_NOACKF;
                  goto error;
               } else {
                  goto retry;
               }
            }

            txdat++;
            TransferCfg->tx_count++;
         }
      }

      /* Second Start condition (Repeat Start) ------------------------------------------- */
      if ((TransferCfg->tx_length != 0) && (TransferCfg->tx_data != NULL) \
            && (TransferCfg->rx_length != 0) && (TransferCfg->rx_data != NULL)){

         CodeStatus = I2C_Start(I2Cx);
         if ((CodeStatus != I2C_I2STAT_M_RX_START) \
               && (CodeStatus != I2C_I2STAT_M_RX_RESTART)){
            TransferCfg->retransmissions_count++;
            if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){
               // Update status
               TransferCfg->status = CodeStatus;
               goto error;
            } else {
               goto retry;
            }
         }
      }

      /* Then, start reading after sending data -------------------------------------- */
      if ((TransferCfg->rx_length != 0) && (TransferCfg->rx_data != NULL)){
         /* Send slave address + RD direction bit = 1 ----------------------------------- */

         CodeStatus = I2C_SendByte(I2Cx, ((TransferCfg->sl_addr7bit << 1) | 0x01));
         if (CodeStatus != I2C_I2STAT_M_RX_SLAR_ACK){
            TransferCfg->retransmissions_count++;
            if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){
               // update status
               TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_NOACKF;
               goto error;
            } else {
               goto retry;
            }
         }

         /* Receive a number of data bytes ------------------------------------------------- */
         while (TransferCfg->rx_count < TransferCfg->rx_length){

            /*
             * Note that: if data length is only one, the master should not
             * issue an ACK signal on bus after reading to avoid of next data frame
             * on slave side
             */
            if (TransferCfg->rx_count < (TransferCfg->rx_length - 1)){
               // Issue an ACK signal for next data frame
               CodeStatus = I2C_GetByte(I2Cx, &tmp, TRUE);
               if (CodeStatus != I2C_I2STAT_M_RX_DAT_ACK){
                  TransferCfg->retransmissions_count++;
                  if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){
                     // update status
                     TransferCfg->status = CodeStatus;
                     goto error;
                  } else {
                     goto retry;
                  }
               }
            } else {
               // Do not issue an ACK signal
               CodeStatus = I2C_GetByte(I2Cx, &tmp, FALSE);
               if (CodeStatus != I2C_I2STAT_M_RX_DAT_NACK){
                  TransferCfg->retransmissions_count++;
                  if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){
                     // update status
                     TransferCfg->status = CodeStatus;
                     goto error;
                  } else {
                     goto retry;
                  }
               }
            }
            *rxdat++ = tmp;
            TransferCfg->rx_count++;
         }
      }

      /* Send STOP condition ------------------------------------------------- */
      I2C_Stop(I2Cx);
      return SUCCESS;

error:
      // Send stop condition
      I2C_Stop(I2Cx);
      return ERROR;
   }

   else if (Opt == I2C_TRANSFER_INTERRUPT){

      // Setup tx_rx data, callback and interrupt handler
      tmp = I2C_getNum(I2Cx);
      i2cdat[tmp].txrx_setup = (uint32_t) TransferCfg;
      // Set direction phase, write first
      i2cdat[tmp].dir = 0;

      /* First Start condition -------------------------------------------------------------- */
      I2Cx->CONCLR = I2C_I2CONCLR_SIC;
      I2Cx->CONSET = I2C_I2CONSET_STA;
      I2C_IntCmd(I2Cx, TRUE);

      while(I2C_MasterComplete[tmp] != TRUE);
      I2C_MasterComplete[tmp] = FALSE;

      return (SUCCESS);
   }

   return ERROR;
}


/*********************************************************************//**
 * @brief       Receive and Transmit data in slave mode
 * @param[in]   I2Cx   I2C peripheral selected, should be
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @param[in]   TransferCfg      Pointer to a I2C_S_SETUP_Type structure that
 *             contains specified information about the configuration for
 *             master transfer.
 * @param[in]   Opt   I2C_TRANSFER_OPT_Type type that selected for interrupt
 *             or polling mode.
 * @return       Transmit/receive status, could be:
 *                - SUCCESS
 *                - ERRRO
 *
 * Note:
 * The mode of slave's operation depends on the command sent from master on
 * the I2C bus. If the master send a SLA+W command, this sub-routine will
 * use receive data length and receive data pointer. If the master send a SLA+R
 * command, this sub-routine will use transmit data length and transmit data
 * pointer.
 * If the master issue an repeat start command or a stop command, the slave will
 * enable an time out condition, during time out condition, if there's no activity
 * on I2C bus, the slave will exit, otherwise (i.e. the master send a SLA+R/W),
 * the slave then switch to relevant operation mode. The time out should be used
 * because the return status code can not show difference from stop and repeat
 * start command in slave operation.
 * In case of the expected data length from master is greater than data length
 * that slave can support:
 * - In case of reading operation (from master): slave will return I2C_I2DAT_IDLE_CHAR
 * value.
 * - In case of writing operation (from master): slave will ignore remain data from master.
 **********************************************************************/
Status I2C_SlaveTransferData(LPC_I2Cn_Type *I2Cx, I2C_S_SETUP_Type *TransferCfg, \
                        I2C_TRANSFER_OPT_Type Opt)
{
   uint8_t *txdat;
   uint8_t *rxdat;
   uint32_t CodeStatus;
   uint32_t timeout;
   int32_t time_en;
   int32_t tmp;

   // reset all default state
   txdat = (uint8_t *) TransferCfg->tx_data;
   rxdat = (uint8_t *) TransferCfg->rx_data;
   // Reset I2C setup value to default state
   TransferCfg->tx_count = 0;
   TransferCfg->rx_count = 0;
   TransferCfg->status = 0;


   // Polling option
   if (Opt == I2C_TRANSFER_POLLING){

      /* Set AA bit to ACK command on I2C bus */
      I2Cx->CONSET = I2C_I2CONSET_AA;
      /* Clear SI bit to be ready ... */
      I2Cx->CONCLR = (I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC);

      time_en = 0;
      timeout = 0;

      while (1)
      {
         /* Check SI flag ready */
         if (I2Cx->CONSET & I2C_I2CONSET_SI)
         {
            time_en = 0;

            switch (CodeStatus = (I2Cx->STAT & I2C_STAT_CODE_BITMASK))
            {

            /* No status information */
            case I2C_I2STAT_NO_INF:
               I2Cx->CONSET = I2C_I2CONSET_AA;
               I2Cx->CONCLR = I2C_I2CONCLR_SIC;
               break;

            /* Reading phase -------------------------------------------------------- */
            /* Own SLA+R has been received, ACK has been returned */
            case I2C_I2STAT_S_RX_SLAW_ACK:
            /* General call address has been received, ACK has been returned */
            case I2C_I2STAT_S_RX_GENCALL_ACK:
               I2Cx->CONSET = I2C_I2CONSET_AA;
               I2Cx->CONCLR = I2C_I2CONCLR_SIC;
               break;

            /* Previously addressed with own SLA;
             * DATA byte has been received;
             * ACK has been returned */
            case I2C_I2STAT_S_RX_PRE_SLA_DAT_ACK:
            /* DATA has been received, ACK hasn been return */
            case I2C_I2STAT_S_RX_PRE_GENCALL_DAT_ACK:
               /*
                * All data bytes that over-flow the specified receive
                * data length, just ignore them.
                */
               if ((TransferCfg->rx_count < TransferCfg->rx_length) \
                     && (TransferCfg->rx_data != NULL)){
                  *rxdat++ = (uint8_t)I2Cx->DAT;
                  TransferCfg->rx_count++;
               }
               I2Cx->CONSET = I2C_I2CONSET_AA;
               I2Cx->CONCLR = I2C_I2CONCLR_SIC;
               break;

            /* Previously addressed with own SLA;
             * DATA byte has been received;
             * NOT ACK has been returned */
            case I2C_I2STAT_S_RX_PRE_SLA_DAT_NACK:
            /* DATA has been received, NOT ACK has been returned */
            case I2C_I2STAT_S_RX_PRE_GENCALL_DAT_NACK:
               I2Cx->CONCLR = I2C_I2CONCLR_SIC;
               break;

            /*
             * Note that: Return code only let us know a stop condition mixed
             * with a repeat start condition in the same code value.
             * So we should provide a time-out. In case this is really a stop
             * condition, this will return back after time out condition. Otherwise,
             * next session that is slave receive data will be completed.
             */

            /* A Stop or a repeat start condition */
            case I2C_I2STAT_S_RX_STA_STO_SLVREC_SLVTRX:
               I2Cx->CONCLR = I2C_I2CONCLR_SIC;
               // enable time out
               time_en = 1;
               timeout = 0;
               break;

            /* Writing phase -------------------------------------------------------- */
            /* Own SLA+R has been received, ACK has been returned */
            case I2C_I2STAT_S_TX_SLAR_ACK:
            /* Data has been transmitted, ACK has been received */
            case I2C_I2STAT_S_TX_DAT_ACK:
               /*
                * All data bytes that over-flow the specified receive
                * data length, just ignore them.
                */
               if ((TransferCfg->tx_count < TransferCfg->tx_length) \
                     && (TransferCfg->tx_data != NULL)){
                  I2Cx->DAT = *txdat++;
                  TransferCfg->tx_count++;
               }
               I2Cx->CONSET = I2C_I2CONSET_AA;
               I2Cx->CONCLR = I2C_I2CONCLR_SIC;
               break;

            /* Data has been transmitted, NACK has been received,
             * that means there's no more data to send, exit now */
            /*
             * Note: Don't wait for stop event since in slave transmit mode,
             * since there no proof lets us know when a stop signal has been received
             * on slave side.
             */
            case I2C_I2STAT_S_TX_DAT_NACK:
               I2Cx->CONSET = I2C_I2CONSET_AA;
               I2Cx->CONCLR = I2C_I2CONCLR_SIC;
               // enable time out
               time_en = 1;
               timeout = 0;
               break;

            // Other status must be captured
            default:
               I2Cx->CONCLR = I2C_I2CONCLR_SIC;
               goto s_error;
            }
         } else if (time_en){
            if (timeout++ > I2C_SLAVE_TIME_OUT){
               // it's really a stop condition, goto end stage
               goto s_end_stage;
            }
         }
      }

s_end_stage:
      /* Clear AA bit to disable ACK on I2C bus */
      I2Cx->CONCLR = I2C_I2CONCLR_AAC;
      // Check if there's no error during operation
      // Update status
      TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_DONE;
      return SUCCESS;

s_error:
      /* Clear AA bit to disable ACK on I2C bus */
      I2Cx->CONCLR = I2C_I2CONCLR_AAC;
      // Update status
      TransferCfg->status = CodeStatus;
      return ERROR;
   }

   else if (Opt == I2C_TRANSFER_INTERRUPT){
      // Setup tx_rx data, callback and interrupt handler
      tmp = I2C_getNum(I2Cx);
      i2cdat[tmp].txrx_setup = (uint32_t) TransferCfg;
      // Set direction phase, read first
      i2cdat[tmp].dir = 1;

      // Enable AA
      I2Cx->CONSET = I2C_I2CONSET_AA;
      I2Cx->CONCLR = I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC;
      I2C_IntCmd(I2Cx, TRUE);

      return (SUCCESS);
   }

   return ERROR;
}

/*********************************************************************//**
 * @brief      Set Own slave address in I2C peripheral corresponding to
 *             parameter specified in OwnSlaveAddrConfigStruct.
 * @param[in]   I2Cx   I2C peripheral selected, should be
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @param[in]   OwnSlaveAddrConfigStruct   Pointer to a I2C_OWNSLAVEADDR_CFG_Type
 *             structure that contains the configuration information for the
 *              specified I2C slave address.
 * @return       None
 **********************************************************************/
void I2C_SetOwnSlaveAddr(LPC_I2Cn_Type *I2Cx, I2C_OWNSLAVEADDR_CFG_Type *OwnSlaveAddrConfigStruct)
{
   uint32_t tmp;
   CHECK_PARAM(PARAM_I2Cx(I2Cx));
   CHECK_PARAM(PARAM_I2C_SLAVEADDR_CH(OwnSlaveAddrConfigStruct->SlaveAddrChannel));
   CHECK_PARAM(PARAM_FUNCTIONALSTATE(OwnSlaveAddrConfigStruct->GeneralCallState));

   tmp = (((uint32_t)(OwnSlaveAddrConfigStruct->SlaveAddr_7bit << 1)) \
         | ((OwnSlaveAddrConfigStruct->GeneralCallState == ENABLE) ? 0x01 : 0x00))& I2C_I2ADR_BITMASK;
   switch (OwnSlaveAddrConfigStruct->SlaveAddrChannel)
   {
   case 0:
      I2Cx->ADR0 = tmp;
      I2Cx->MASK[0] = I2C_I2MASK_MASK((uint32_t) \
            (OwnSlaveAddrConfigStruct->SlaveAddrMaskValue));
      break;
   case 1:
      I2Cx->ADR1 = tmp;
      I2Cx->MASK[1] = I2C_I2MASK_MASK((uint32_t) \
            (OwnSlaveAddrConfigStruct->SlaveAddrMaskValue));
      break;
   case 2:
      I2Cx->ADR2 = tmp;
      I2Cx->MASK[2] = I2C_I2MASK_MASK((uint32_t) \
            (OwnSlaveAddrConfigStruct->SlaveAddrMaskValue));
      break;
   case 3:
      I2Cx->ADR3 = tmp;
      I2Cx->MASK[3] = I2C_I2MASK_MASK((uint32_t) \
            (OwnSlaveAddrConfigStruct->SlaveAddrMaskValue));
      break;
   }
}


/*********************************************************************//**
 * @brief      Configures functionality in I2C monitor mode
 * @param[in]   I2Cx   I2C peripheral selected, should be
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @param[in]   MonitorCfgType Monitor Configuration type, should be:
 *                - I2C_MONITOR_CFG_SCL_OUTPUT   :I2C module can 'stretch'
 *             the clock line (hold it low) until it has had time to respond
 *             to an I2C interrupt.
 *                - I2C_MONITOR_CFG_MATCHALL      :When this bit is set to '1'
 *             and the I2C is in monitor mode, an interrupt will be generated
 *             on ANY address received.
 * @param[in]   NewState New State of this function, should be:
 *                - ENABLE   :Enable this function.
 *                - DISABLE   :Disable this function.
 * @return      None
 **********************************************************************/
void I2C_MonitorModeConfig(LPC_I2Cn_Type *I2Cx, uint32_t MonitorCfgType, FunctionalState NewState)
{
   CHECK_PARAM(PARAM_I2Cx(I2Cx));
   CHECK_PARAM(PARAM_I2C_MONITOR_CFG(MonitorCfgType));
   CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState));

   if (NewState == ENABLE)
   {
      I2Cx->MMCTRL |= MonitorCfgType;
   }
   else
   {
      I2Cx->MMCTRL &= (~MonitorCfgType) & I2C_I2MMCTRL_BITMASK;
   }
}


/*********************************************************************//**
 * @brief      Enable/Disable I2C monitor mode
 * @param[in]   I2Cx   I2C peripheral selected, should be
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @param[in]   NewState New State of this function, should be:
 *                - ENABLE   :Enable monitor mode.
 *                - DISABLE   :Disable monitor mode.
 * @return      None
 **********************************************************************/
void I2C_MonitorModeCmd(LPC_I2Cn_Type *I2Cx, FunctionalState NewState)
{
   CHECK_PARAM(PARAM_I2Cx(I2Cx));
   CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState));

   if (NewState == ENABLE)
   {
      I2Cx->MMCTRL |= I2C_I2MMCTRL_MM_ENA;
      I2Cx->CONSET = I2C_I2CONSET_AA;
      I2Cx->CONCLR = I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC;
   }
   else
   {
      I2Cx->MMCTRL &= (~I2C_I2MMCTRL_MM_ENA) & I2C_I2MMCTRL_BITMASK;
      I2Cx->CONCLR = I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC | I2C_I2CONCLR_AAC;
   }
   I2C_MonitorBufferIndex = 0;
}


/*********************************************************************//**
 * @brief      Get data from I2C data buffer in monitor mode.
 * @param[in]   I2Cx   I2C peripheral selected, should be
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @return      None
 * Note:   In monitor mode, the I2C module may lose the ability to stretch
 * the clock (stall the bus) if the ENA_SCL bit is not set. This means that
 * the processor will have a limited amount of time to read the contents of
 * the data received on the bus. If the processor reads the I2DAT shift
 * register, as it ordinarily would, it could have only one bit-time to
 * respond to the interrupt before the received data is overwritten by
 * new data.
 **********************************************************************/
uint8_t I2C_MonitorGetDatabuffer(LPC_I2Cn_Type *I2Cx)
{
   CHECK_PARAM(PARAM_I2Cx(I2Cx));
   return ((uint8_t)(I2Cx->DATA_BUFFER));
}


/*********************************************************************//**
 * @brief      Get data from I2C data buffer in monitor mode.
 * @param[in]   I2Cx   I2C peripheral selected, should be
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @return      None
 * Note:   In monitor mode, the I2C module may lose the ability to stretch
 * the clock (stall the bus) if the ENA_SCL bit is not set. This means that
 * the processor will have a limited amount of time to read the contents of
 * the data received on the bus. If the processor reads the I2DAT shift
 * register, as it ordinarily would, it could have only one bit-time to
 * respond to the interrupt before the received data is overwritten by
 * new data.
 **********************************************************************/
BOOL_8 I2C_MonitorHandler(LPC_I2Cn_Type *I2Cx, uint8_t *buffer, uint32_t size)
{
   BOOL_8 ret=FALSE;

   I2Cx->CONCLR = I2C_I2CONCLR_SIC;

   buffer[I2C_MonitorBufferIndex] = (uint8_t)(I2Cx->DATA_BUFFER);
   I2C_MonitorBufferIndex++;
   if(I2C_MonitorBufferIndex >= size)
   {
      ret = TRUE;
   }
   return ret;
}


/*********************************************************************//**
 * @brief       Get status of Master Transfer
 * @param[in]   I2Cx   I2C peripheral selected, should be:
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @return       Master transfer status, could be:
 *                - TRUE      :master transfer completed
 *                - FALSE    :master transfer have not completed yet
 **********************************************************************/
uint32_t I2C_MasterTransferComplete(LPC_I2Cn_Type *I2Cx)
{
   uint32_t retval, tmp;
   tmp = I2C_getNum(I2Cx);
   retval = I2C_MasterComplete[tmp];
   I2C_MasterComplete[tmp] = FALSE;
   return retval;
}


/*********************************************************************//**
 * @brief       Get status of Slave Transfer
 * @param[in]   I2Cx   I2C peripheral selected, should be:
 *                - LPC_I2C0   :I2C0 peripheral
 *                - LPC_I2C1   :I2C1 peripheral
 * @return       Complete status, could be: TRUE/FALSE
 **********************************************************************/
uint32_t I2C_SlaveTransferComplete(LPC_I2Cn_Type *I2Cx)
{
   uint32_t retval, tmp;
   tmp = I2C_getNum(I2Cx);
   retval = I2C_SlaveComplete[tmp];
   I2C_SlaveComplete[tmp] = FALSE;
   return retval;
}



/**
 * @}
 */

#endif /* _I2C */

/**
 * @}
 */

/* --------------------------------- End Of File ------------------------------ */

MensagemEnviado: 09 Fev 2013 11:03
por proex
Nossa, como os caras conseguem complicar um coisa tão simples.

Eu faria por soft mesmo, seria bem mais simples, inteligível e enxuto.


.

MensagemEnviado: 09 Fev 2013 13:14
por Red Neck Guy
proex escreveu:Nossa, como os caras conseguem complicar um coisa tão simples.

Eu faria por soft mesmo, seria bem mais simples, inteligível e enxuto.


.


E bem mais lento...

Código: Selecionar todos
/*************************************************************************
 *
*    Used with ICCARM and AARM.
 *
 *    (c) Copyright IAR Systems 2007
 *
 *    File name   : i2c_drv.c
 *    Description : I2C driver
 *
 *    History :
 *    1. Date        : 13, February 2008
 *       Author      : Stanimir Bonev
 *       Description : Create
 *
 *
 *    $Revision: 28532 $
 **************************************************************************/
//#include "includes.h"
#include <nxp\iolpc1768.h>
#include <intrinsics.h>
#include "i2c0.h"

volatile int     I2CState;
LPC_I2C_Msg_t     I2CMsg;


// PCLK offset
#define WDT_PCLK_OFFSET     0
#define TIMER0_PCLK_OFFSET  2
#define TIMER1_PCLK_OFFSET  4
#define UART0_PCLK_OFFSET   6
#define UART1_PCLK_OFFSET   8
#define PWM0_PCLK_OFFSET    10
#define PWM1_PCLK_OFFSET    12
#define I2C0_PCLK_OFFSET    14
#define SPI_PCLK_OFFSET     16
#define RTC_PCLK_OFFSET     18
#define SSP1_PCLK_OFFSET    20
#define DAC_PCLK_OFFSET     22
#define ADC_PCLK_OFFSET     24
#define CAN1_PCLK_OFFSET    26
#define CAN2_PCLK_OFFSET    28
#define ACF_PCLK_OFFSET     30
#define BAT_RAM_PCLK_OFFSET 32
#define GPIO_PCLK_OFFSET    34
#define PCB_PCLK_OFFSET     36
#define I2C1_PCLK_OFFSET    38
//#define                   40
#define SSP0_PCLK_OFFSET    42
#define TIMER2_PCLK_OFFSET  44
#define TIMER3_PCLK_OFFSET  46
#define UART2_PCLK_OFFSET   48
#define UART3_PCLK_OFFSET   50
#define I2C2_PCLK_OFFSET    52
#define I2S_PCLK_OFFSET     54
#define MCI_PCLK_OFFSET     56
/*************************************************************************
 * Function Name: I2C_EnableI2C
 * Parameters: void
 * Return: void
 * Description: Enable I2C device.
 *************************************************************************/
#pragma inline
void I2C_EnableI2C(void)
{
  I2C0CONSET |= I2CON_I2EN;
}

/*************************************************************************
 * Function Name: I2C_DisableI2C
 * Parameters: void
 * Return: void
 * Description: Disable I2C device.
 *************************************************************************/
#pragma inline
void I2C_DisableI2C(void)
{
  I2C0CONCLR = I2CON_I2ENC;
}

/*************************************************************************
 * Function Name: __I2C_SetFlag
 * Parameters: int FlagType -- AA, INT and START and STOP
 *
 * Return: void
 * Description: Set the flag.
 *
 *************************************************************************/
#pragma inline
void __I2C_SetFlag (int FlagType)
{
  I2C0CONSET |= FlagType;
}

/*************************************************************************
 * Function Name: __I2C_ClearFlag
 * Parameters: int FlagType -- AA, INT and START (Excl. STOP)
 *
 * Return: void
 * Description: Clear the flag.
 *
 *************************************************************************/
#pragma inline
void __I2C_ClearFlag (int FlagType)
{
  I2C0CONCLR = FlagType;
}

/*************************************************************************
 * Function Name: __I2C_SendData
 * Parameters: unsigned char data
 * Return: void
 * Description: Load data to I2CDAT. Just used in I2C module.
 *************************************************************************/
#pragma inline
void __I2C_SendData(unsigned char data)
{
  I2C0DAT = data;
}

/*************************************************************************
 * Function Name: __I2C_ReceiveData
 * Parameters: void
 * Return: unsigned char
 * Description: Load data from I2CDAT. Just used in I2C module.
 *************************************************************************/
#pragma inline
unsigned char __I2C_ReceiveData(void)
{
  return I2C0DAT;
}

/*************************************************************************
 * Function Name: I2C_InitMaster
 * Parameters: unsigned long BusSpeed
 *
 * Return: int
 *                0: success
 *    non-zero: error number
 * Description: Initialize the current device as I2C bus master.
 *
 *************************************************************************/
int I2C_InitMaster (unsigned long BusSpeed)
{

  PCONP_bit.PCI2C0 = 1;      // enable I2C0 clock

  if (BusSpeed > I2C_MAXSPEED)
    return 1;
  I2C_DisableI2C();

  // Bit Frequency = Fplk / (I2C_I2SCLH + I2C_I2SCLL)
  // value of I2SCLH and I2SCLL must be different
  I2C0SCLH = ((/*(SYS_GetFpclk(I2C0_PCLK_OFFSET)*/80000000 / BusSpeed)>>1) +1;
  I2C0SCLL =  (/*(SYS_GetFpclk(I2C0_PCLK_OFFSET)*/80000000 / BusSpeed)>>1;

  if (I2C0SCLH < 4 || I2C0SCLL < 4)
    return 1;

  I2CState = I2C_IDLE;

  // Assign pins to SCL and SDA (P0_27, P0_28)
  PINSEL1_bit.P0_27 = 1;
  PINSEL1_bit.P0_28 = 1;
   
   // Enable I2C
  I2C_EnableI2C();
  __I2C_ClearFlag(I2CON_STAC | I2CON_SIC | I2CON_AAC);

  return 0;
}

/*************************************************************************
 * Function Name: I2C_MasterWrite
 * Parameters:  unsigned char addr -- the slave address which you send message to
 *      unsigned char *pMsg -- the point to the message
 *      unsigned long numMsg -- the byte number of the message
 * Return: int
 *                0: success
 *       non-zero: error number
 *
 * Description: Transmit messages
 *
 *************************************************************************/
int I2C_MasterWrite (unsigned char addr, unsigned char *pMsg , unsigned long numMsg)
{
  return I2C_Transfer (addr, pMsg , numMsg, WRITE, 0);
}


/*************************************************************************
 * Function Name: I2C_MasterRead
 * Parameters:  unsigned char addr -- the slave address which you send message to
 *      unsigned char *pMsg -- the point to the message
 *      unsigned long numMsg -- the byte number of the message
 * Return: int
 *                0: success
 *    non-zero: error number
 *
 * Description: Receive messages
 *
 *************************************************************************/
int I2C_MasterRead (unsigned char addr, unsigned char *pMsg , unsigned long numMsg)
{
  return I2C_Transfer (addr, pMsg , numMsg, READ, 0);
}

/*************************************************************************
 * Function Name: I2C_Transfer
 * Parameters:  unsigned char addr -- the slave address which you send message to
 *      unsigned char *pMsg -- the point to the message
 *      unsigned long numMsg -- the byte number of the message
 *      LPC_I2C_TransMode_t transMode -- Read, Write, Write then read
 *      unsigned long numWrite -- this is only for "Write then read" mode
 *         
 * Return: int
 *                0: success
 *       non-zero: error number
 *
 * Description: Transfer messages
 *
 *************************************************************************/
int I2C_Transfer (unsigned char addr, unsigned char *pMsg , unsigned long numMsg,
             LPC_I2C_TransMode_t transMode, unsigned long numWrite)
{
  unsigned int timeout = DLY_I2C_TIME_OUT;
  if (transMode == WRITETHENREAD)
  {
    if (numWrite >= numMsg)
      return 1;
    else
      I2CMsg.nrWriteBytes = numWrite;
  }
  else
    I2CMsg.nrWriteBytes = 0;
   
  I2CMsg.buf       = pMsg;
  I2CMsg.nrBytes   = numMsg;
  I2CMsg.address   = addr;
  I2CMsg.transMode = transMode;
  I2CMsg.dataCount = 0;

  __I2C_SetFlag(I2CON_STA);

  I2CState = I2C_BUSY;   

  while(I2CState == I2C_BUSY)
  {
    // Wait the interrupt
    if (I2C0CONSET & 0x08)
    {
      I2C_HandleMasterState();    // Master Mode
      timeout = DLY_I2C_TIME_OUT;
    }
    if (timeout-- == 0)
    {
      I2CState = I2C_TIME_OUT;
    }
  }

#ifdef __DEBUG__
  if (I2C_OK != I2CState) {
    printf("I2C error : %d\n",I2CState);
    I2C_InitMaster(I2C_SPEED);
  }
#endif
  __I2C_ClearFlag(I2CON_STAC | I2CON_AAC);

  return I2CState;
}


/*************************************************************************
 * Function Name: I2C_HandleMasterState
 * Parameters: void
 * Return: void
 * Description: Master mode state handler for I2C bus.
 *
 *************************************************************************/
void I2C_HandleMasterState(void)
{
unsigned long I2Cstatus = I2C0STAT & 0xF8;

  switch (I2Cstatus)
  {
/* ------- MASTER TRANSMITTER FUNCTIONS ----------- */
  case 0x08 : // start condition transmitted
  case 0x10 : // restart condition transmitted
    if (I2CMsg.transMode == WRITETHENREAD)
    {
      if (I2CMsg.dataCount < I2CMsg.nrWriteBytes)
        __I2C_SendData((I2CMsg.address<<1) | WRITE);
      else
      {
        __I2C_SendData((I2CMsg.address<<1) | READ );
      }
    }
    else
    {
      __I2C_SendData((I2CMsg.address<<1) | I2CMsg.transMode);
    }
    __I2C_ClearFlag(I2CON_STAC);   // STA bit
    break;
  case 0x18 : // SLA+W transmitted and ACK received
    if ( I2CMsg.nrBytes == 0 )
    {
      __I2C_SetFlag  (I2CON_STO);             // STO bit clear automatically
      I2CState = I2C_NO_DATA;
    }
    else
    {
      // Send next data byte
      __I2C_SendData(I2CMsg.buf[I2CMsg.dataCount++]);   
    }
    break;   
  case 0x20 : // SLA+W transmitted, but no ACK received
    __I2C_SetFlag  (I2CON_STO);
    I2CState = I2C_NACK_ON_ADDRESS;
    break;      
  case 0x28 : //Data byte transmitted and ACK received
    if (I2CMsg.transMode == WRITE)
    {
      if (I2CMsg.dataCount < I2CMsg.nrBytes)
      {
        __I2C_SendData (I2CMsg.buf[I2CMsg.dataCount++]);   
      }
      else
      {
        __I2C_SetFlag  (I2CON_STO); // data transmit finished, stop transmit
        I2CState = I2C_OK;
      }
    }
    else if (I2CMsg.transMode == WRITETHENREAD)
    {
      if (I2CMsg.dataCount < I2CMsg.nrWriteBytes)
      {
        __I2C_SendData (I2CMsg.buf[I2CMsg.dataCount++]);   
      }
      else      // send start condition
      {
        __I2C_SetFlag  (I2CON_STA);
      }
    }
    break;
  case 0x30 : // no ACK for data byte
    __I2C_SetFlag  (I2CON_STO);
    I2CState = I2C_NACK_ON_DATA;
    break;
  case 0x38 : // arbitration lost in Slave Address or Data bytes
    I2CState = I2C_ARBITRATION_LOST;
    break;

/* ------- MASTER RECEIVER FUNCTIONS ----------- */
  case 0x40 : // ACK for slave address + R
    if (I2CMsg.nrBytes>1)
    {
      __I2C_SetFlag  (I2CON_AA );   // send acknowledge byte
    }
    else
    {
      __I2C_ClearFlag(I2CON_AAC); // return NACK
    }
    break;
  case 0x48 : // no ACK for slave address + R
    __I2C_SetFlag  (I2CON_STO);
    I2CState = I2C_NACK_ON_ADDRESS;
    break;
  case 0x50 : // ACK for data byte
    I2CMsg.buf[I2CMsg.dataCount++] = __I2C_ReceiveData();
    if (I2CMsg.dataCount + 1 < I2CMsg.nrBytes)
    {
      __I2C_SetFlag(I2CON_AA );     // send acknowledge byte
    }
    else
    {
      __I2C_ClearFlag(I2CON_AAC); // return NACK
    }
    break;
  case 0x58 : // no ACK for data byte
    I2CMsg.buf[I2CMsg.dataCount++] = __I2C_ReceiveData();

    __I2C_SetFlag  (I2CON_STO);
    I2CState = I2C_OK;
    break;
  default : // undefined error
    __I2C_SetFlag  (I2CON_STO);
    __I2C_ClearFlag(I2CON_STAC | I2CON_AAC);
    I2CState = I2C_ERROR;
    break;
  } // switch - I2C_I2STAT & 0xF8
  __I2C_ClearFlag(I2CON_SIC);
}



Copiei de algum lugar, então quem fez leva o crédito e tal.

MensagemEnviado: 09 Fev 2013 17:39
por proex
Bem mais lento por que?

MensagemEnviado: 10 Fev 2013 18:18
por Red Neck Guy
proex escreveu:Bem mais lento por que?


Pq por hw dá pra configurar o clk a 400khz.
Fazendo na munheca, não rola....
(Claro, se for uma aplicação de uma única thread que não faz nada além disso, talvez consiga manipular o pino de clk nessa frequência..
Mas me refiro a uma aplicação complexa onde não há nenhum loop parado e vários serviços de int rodando, então por hw, tu coloca o byte no registrador e ele é clocado a 400khz e tu está livre por esse período de tempo pra fazer um NOP)

MensagemEnviado: 11 Fev 2013 06:55
por fabim
nossa, este 45 é tão diferente assim dos 1768 2378 1788 ?

Eu passei o zói no manual do 45 e não vi diferenças gritantes.

Qual é a dificulidade ?

Fabim

MensagemEnviado: 11 Fev 2013 07:23
por proex
Aquino escreveu:
proex escreveu:Bem mais lento por que?


Pq por hw dá pra configurar o clk a 400khz.
Fazendo na munheca, não rola...


Aquino meu fio, fazendo na unha dá pra setar o clock em até 10Mhz se vc quiser. Bota as rotinas numa INT de algum Timer e pronto. Se me pagar bem eu faço pra vc em 3 minutos. :lol: :lol:

Te prometo que o codigo fica 100 vezes mais enxuto que aquele e 1000 vezes mais inteligivel.

.

MensagemEnviado: 11 Fev 2013 07:27
por KrafT
Pôxa Proex... Pagando bem tem que ser para bem mais tempo que isso... :?

MensagemEnviado: 11 Fev 2013 19:46
por Red Neck Guy
proex escreveu:
Aquino escreveu:
proex escreveu:Bem mais lento por que?


Pq por hw dá pra configurar o clk a 400khz.
Fazendo na munheca, não rola...


Aquino meu fio, fazendo na unha dá pra setar o clock em até 10Mhz se vc quiser. Bota as rotinas numa INT de algum Timer e pronto. Se me pagar bem eu faço pra vc em 3 minutos. :lol: :lol:

Te prometo que o codigo fica 100 vezes mais enxuto que aquele e 1000 vezes mais inteligivel.

.


Eu não sei não...
Eu prefiro usar esses ciclos de CPU pra outra coisa (nem que seja NOPs)
E tem outra, como eu ganho mal eu faço por hw.

MensagemEnviado: 11 Fev 2013 20:20
por proex
Aquino meu fio (de novo), se vc reparar naquele codigo, verá que pelo menos uns 70% é I2C executado por soft. Vê lá .

.

MensagemEnviado: 11 Fev 2013 20:22
por proex
KrafT escreveu:Pôxa Proex... Pagando bem tem que ser para bem mais tempo que isso... :?


Kraft meu brother, se eu cobrasse por hora, estaria ferrado.

Não cobro por hora.

.

MensagemEnviado: 12 Fev 2013 12:14
por Red Neck Guy
proex escreveu:Aquino meu fio (de novo), se vc reparar naquele codigo, verá que pelo menos uns 70% é I2C executado por soft. Vê lá .

.


Tá bom...
Por exemplo isso:

Código: Selecionar todos
for(int i=0;i<8;i++){
  PIN_DATA = (data&(0x01<<i)):1:0;
  PIN_CLK = 1;
  PIN_CLK = 0;
}



várias iterações desse tipo gastam quantos ciclos?

por hardware basta

Código: Selecionar todos
REG = Data;


Esse exemplo que postei aí uso básico do periférico.. Sem contar que dá pra utilizar como multimestre e implementar uma rede de sincronismo entre MCUs encapsulando os dados nesse protocolo.

Eu sei que sou novato, mas ao menos uma vez na vida, tenta ver que o que eu digo não é tão absurdo assim.

MensagemEnviado: 12 Fev 2013 17:15
por proex
Num chip de 200Mhz, isso nao tem muita relevancia quando vc coloca seu I2C dentro de uma INT.

INT_TIMER0
{
for(int i=0;i<8;i++){
PIN_DATA = (data&(0x01<<i)):1:0;
PIN_CLK = 1;
PIN_CLK = 0;
}


}

MensagemEnviado: 13 Fev 2013 07:08
por fabim
agora estou pensando em uma tomada simples de decisão.
onde você obrigatóriamente (maioria quase absoluta das aplicações), envia mais de um byte ou recebe mais de um byte, e obrigatoriamente fica parado.
Qual a relevância de usar hw ao invés de sw, se tu vai ficar parado da mesma forma ? e tudo que é int vai continuar operando da mesma forma ?

Software da na mesma, o junior mesmo ja fez 2 projetos grandes recentes e fez por software.