2014-02-03

Coocox I2C learning notes

CooCox I2C files - 2014feb0301

/***********************************************************************//**

 * @file : lpc11xx_i2c.h
 * @brief : Contains all macro definitions and function prototypes
 * support for I2C firmware library on LPC11xx
 * @version : 1.0
 * @date : 22. Jan. 2010
 * @author : Coocox
 **************************************************************************/

/* Peripheral group ----------------------------------------------------------- */

/** @defgroup I2C
 * @ingroup LPC1100CMSIS_FwLib_Drivers
 * @{
 */

#ifndef __LPC11XX_I2C_H_

#define __LPC11XX_I2C_H_

/* Includes ------------------------------------------------------------------- */

#include "LPC11xx.h"
#include "lpc11xx_iocon.h"
#include "lpc_types.h"


#ifdef __cplusplus

extern "C"
{
#endif


/* Private Macros ------------------------------------------------------------- */

/** @defgroup I2C_Private_Macros
 * @{
 */

/** @defgroup I2C_REGISTER_BIT_DEFINITIONS

 * @{
 */

/*******************************************************************//**

 * I2C Control Set register description
 *********************************************************************/
#define I2C_I2CONSET_AA ((0x04)) /*!< Assert acknowledge flag */
#define I2C_I2CONSET_SI ((0x08)) /*!< I2C interrupt flag */
#define I2C_I2CONSET_STO ((0x10)) /*!< STOP flag */
#define I2C_I2CONSET_STA ((0x20)) /*!< START flag */
#define I2C_I2CONSET_I2EN ((0x40)) /*!< I2C interface enable */


/*******************************************************************//**

 * I2C Control Clear register description
 *********************************************************************/
/** Assert acknowledge Clear bit */
#define I2C_I2CONCLR_AAC ((1<<2))
/** I2C interrupt Clear bit */
#define I2C_I2CONCLR_SIC ((1<<3))
/** START flag Clear bit */
#define I2C_I2CONCLR_STAC ((1<<5))
/** I2C interface Disable bit */
#define I2C_I2CONCLR_I2ENC ((1<<6))


/********************************************************************//**

 * I2C Status Code definition (I2C Status register)
 *********************************************************************/
/* Return Code in I2C status register */
#define I2C_STAT_CODE_BITMASK ((0xF8))

/* I2C return status code definitions ----------------------------- */


/** No relevant information */

#define I2C_I2STAT_NO_INF ((0xF8))

/* Master transmit mode -------------------------------------------- */

/** A start condition has been transmitted */
#define I2C_I2STAT_M_TX_START ((0x08))
/** A repeat start condition has been transmitted */
#define I2C_I2STAT_M_TX_RESTART ((0x10))
/** SLA+W has been transmitted, ACK has been received */
#define I2C_I2STAT_M_TX_SLAW_ACK ((0x18))
/** SLA+W has been transmitted, NACK has been received */
#define I2C_I2STAT_M_TX_SLAW_NACK ((0x20))
/** Data has been transmitted, ACK has been received */
#define I2C_I2STAT_M_TX_DAT_ACK ((0x28))
/** Data has been transmitted, NACK has been received */
#define I2C_I2STAT_M_TX_DAT_NACK ((0x30))
/** Arbitration lost in SLA+R/W or Data bytes */
#define I2C_I2STAT_M_TX_ARB_LOST ((0x38))

/* Master receive mode -------------------------------------------- */

/** A start condition has been transmitted */
#define I2C_I2STAT_M_RX_START ((0x08))
/** A repeat start condition has been transmitted */
#define I2C_I2STAT_M_RX_RESTART ((0x10))
/** Arbitration lost */
#define I2C_I2STAT_M_RX_ARB_LOST ((0x38))
/** SLA+R has been transmitted, ACK has been received */
#define I2C_I2STAT_M_RX_SLAR_ACK ((0x40))
/** SLA+R has been transmitted, NACK has been received */
#define I2C_I2STAT_M_RX_SLAR_NACK ((0x48))
/** Data has been received, ACK has been returned */
#define I2C_I2STAT_M_RX_DAT_ACK ((0x50))
/** Data has been received, NACK has been return */
#define I2C_I2STAT_M_RX_DAT_NACK ((0x58))

/* Slave receive mode -------------------------------------------- */

/** Own slave address has been received, ACK has been returned */
#define I2C_I2STAT_S_RX_SLAW_ACK ((0x60))

/** Arbitration lost in SLA+R/W as master */

#define I2C_I2STAT_S_RX_ARB_LOST_M_SLA ((0x68))
/** Own SLA+W has been received, ACK returned */
//#define I2C_I2STAT_S_RX_SLAW_ACK ((0x68))

/** General call address has been received, ACK has been returned */

#define I2C_I2STAT_S_RX_GENCALL_ACK ((0x70))

/** Arbitration lost in SLA+R/W (GENERAL CALL) as master */

#define I2C_I2STAT_S_RX_ARB_LOST_M_GENCALL ((0x78))
/** General call address has been received, ACK has been returned */
//#define I2C_I2STAT_S_RX_GENCALL_ACK ((0x78))

/** Previously addressed with own SLV address;

 * Data has been received, ACK has been return */
#define I2C_I2STAT_S_RX_PRE_SLA_DAT_ACK ((0x80))
/** Previously addressed with own SLA;
 * Data has been received and NOT ACK has been return */
#define I2C_I2STAT_S_RX_PRE_SLA_DAT_NACK ((0x88))
/** Previously addressed with General Call;
 * Data has been received and ACK has been return */
#define I2C_I2STAT_S_RX_PRE_GENCALL_DAT_ACK ((0x90))
/** Previously addressed with General Call;
 * Data has been received and NOT ACK has been return */
#define I2C_I2STAT_S_RX_PRE_GENCALL_DAT_NACK ((0x98))
/** A STOP condition or repeated START condition has
 * been received while still addressed as SLV/REC
 * (Slave Receive) or SLV/TRX (Slave Transmit) */
#define I2C_I2STAT_S_RX_STA_STO_SLVREC_SLVTRX ((0xA0))

/** Slave transmit mode -------------------------------------------- */

/** Own SLA+R has been received, ACK has been returned */
#define I2C_I2STAT_S_TX_SLAR_ACK ((0xA8))

/** Arbitration lost in SLA+R/W as master */

#define I2C_I2STAT_S_TX_ARB_LOST_M_SLA ((0xB0))
/** Own SLA+R has been received, ACK has been returned */
//#define I2C_I2STAT_S_TX_SLAR_ACK ((0xB0))

/** Data has been transmitted, ACK has been received */

#define I2C_I2STAT_S_TX_DAT_ACK ((0xB8))
/** Data has been transmitted, NACK has been received */
#define I2C_I2STAT_S_TX_DAT_NACK ((0xC0))
/** Last data byte in I2DAT has been transmitted (AA = 0);
 ACK has been received */
#define I2C_I2STAT_S_TX_LAST_DAT_ACK ((0xC8))

/** Time out in case of using I2C slave mode */

#define I2C_SLAVE_TIME_OUT 0x10000UL

/********************************************************************//**

 * I2C Data register definition
 *********************************************************************/
/** Mask for I2DAT register*/
#define I2C_I2DAT_BITMASK ((0xFF))

/** Idle data value will be send out in slave mode in case of the actual

 * expecting data requested from the master is greater than its sending data
 * length that can be supported */
#define I2C_I2DAT_IDLE_CHAR (0xFF)


/********************************************************************//**

 * I2C Monitor mode control register description
 *********************************************************************/
#define I2C_I2MMCTRL_MM_ENA ((1<<0)) /**< Monitor mode enable */
#define I2C_I2MMCTRL_ENA_SCL ((1<<1)) /**< SCL output enable */
#define I2C_I2MMCTRL_MATCH_ALL ((1<<2)) /**< Select interrupt register match */
#define I2C_I2MMCTRL_BITMASK ((0x07)) /**< Mask for I2MMCTRL register */


/********************************************************************//**

 * I2C Data buffer register description
 *********************************************************************/
/** I2C Data buffer register bit mask */
#define I2DATA_BUFFER_BITMASK ((0xFF))


/********************************************************************//**

 * I2C Slave Address registers definition
 *********************************************************************/
/** General Call enable bit */
#define I2C_I2ADR_GC ((1<<0))
/** I2C Slave Address registers bit mask */
#define I2C_I2ADR_BITMASK ((0xFF))


/********************************************************************//**

 * I2C Mask Register definition
 *********************************************************************/
/** I2C Mask Register mask field */
#define I2C_I2MASK_MASK(n) ((n&0xFE))


/********************************************************************//**

 * I2C SCL HIGH duty cycle Register definition
 *********************************************************************/
/** I2C SCL HIGH duty cycle Register bit mask */
#define I2C_I2SCLH_BITMASK ((0xFFFF))


/********************************************************************//**

 * I2C SCL LOW duty cycle Register definition
 *********************************************************************/
/** I2C SCL LOW duty cycle Register bit mask */
#define I2C_I2SCLL_BITMASK ((0xFFFF))

/**

 * @}
 */

/**

 * @}
 */



/* Public Types --------------------------------------------------------------- */

/** @defgroup I2C_Public_Types
 * @{
 */

/** @brief I2C Own slave address setting structure */

typedef struct {
uint8_t SlaveAddrChannel; /**< Slave Address channel in I2C control,
should be in range from 0..3
*/
uint8_t SlaveAddr_7bit; /**< Value of 7-bit slave address */
uint8_t GeneralCallState; /**< Enable/Disable General Call Functionality
when I2C control being in Slave mode, should be:
- ENABLE: Enable General Call function.
- DISABLE: Disable General Call function.
*/
uint8_t SlaveAddrMaskValue; /**< Any bit in this 8-bit value (bit 7:1)
which is set to '1' will cause an automatic compare on
the corresponding bit of the received address when it
is compared to the SlaveAddr_7bit value associated with this
mask register. In other words, bits in SlaveAddr_7bit value
which are masked are not taken into account in determining
an address match
*/
} I2C_OWNSLAVEADDR_CFG_Type;


/** @brief Master transfer setup data structure definitions */

typedef struct
{
  uint32_t          sl_addr7bit; /**< Slave address in 7bit mode */
  uint8_t*          tx_data; /**< Pointer to Transmit data - NULL if data transmit
 is not used */
  uint32_t          tx_length; /**< Transmit data length - 0 if data transmit
 is not used*/
  uint32_t          tx_count; /**< Current Transmit data counter */
  uint8_t*          rx_data; /**< Pointer to Receive data - NULL if data receive
 is not used */
  uint32_t          rx_length; /**< Receive data length - 0 if data receive is
  not used */
  uint32_t          rx_count; /**< Current Receive data counter */
  uint32_t          retransmissions_max; /**< Max Re-Transmission value */
  uint32_t          retransmissions_count; /**< Current Re-Transmission counter */
  uint32_t          status; /**< Current status of I2C activity */
  void (*callback)(void); /**< Pointer to Call back function when transmission complete
used in interrupt transfer mode */
} I2C_M_SETUP_Type;


/** @brief Slave transfer setup data structure definitions */

typedef struct
{
  uint8_t*          tx_data;
  uint32_t          tx_length;
  uint32_t          tx_count;
  uint8_t*          rx_data;
  uint32_t          rx_length;
  uint32_t          rx_count;
  uint32_t          status;
  void (*callback)(void);
} I2C_S_SETUP_Type;

/**

 * @brief Transfer option type definitions
 */
typedef enum {
I2C_TRANSFER_POLLING = 0, /**< Transfer in polling mode */
I2C_TRANSFER_INTERRUPT /**< Transfer in interrupt mode */
} I2C_TRANSFER_OPT_Type;


/**

 * @}
 */


/* Public Macros -------------------------------------------------------------- */

/** @defgroup I2C_Public_Macros
 * @{
 */

#define PARAM_I2C_SLAVEADDR_CH(n) ((n<=3))


/** Macro to determine if it is valid SSP port number */

#define PARAM_I2Cx(n) (((uint32_t *)n)==((uint32_t *)LPC_I2C)) 

/* I2C status values */

#define I2C_SETUP_STATUS_ARBF   (1<<8) /**< Arbitration false */
#define I2C_SETUP_STATUS_NOACKF (1<<9) /**< No ACK returned */
#define I2C_SETUP_STATUS_DONE   (1<<10) /**< Status DONE */


/*********************************************************************//**

 * I2C monitor control configuration defines
 **********************************************************************/
#define I2C_MONITOR_CFG_SCL_OUTPUT I2C_I2MMCTRL_ENA_SCL /**< SCL output enable */
#define I2C_MONITOR_CFG_MATCHALL I2C_I2MMCTRL_MATCH_ALL /**< Select interrupt register match */

#define PARAM_I2C_MONITOR_CFG(n) ((n==I2C_MONITOR_CFG_SCL_OUTPUT) || (I2C_MONITOR_CFG_MATCHALL))


/**

 * @}
 */


/* Public Functions ----------------------------------------------------------- */

/** @defgroup I2C_Public_Functions
 * @{
 */

void I2C_SetClock (I2C_TypeDef *I2Cx, uint32_t target_clock);

void I2C_DeInit(I2C_TypeDef* I2Cx);
void I2C_PinsInit(I2CMODE_Typedef mod);
void I2C_Init(I2C_TypeDef *I2Cx, uint32_t clockrate);
void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState);

Status I2C_MasterTransferData(I2C_TypeDef *I2Cx, \

I2C_M_SETUP_Type *TransferCfg, I2C_TRANSFER_OPT_Type Opt);
Status I2C_SlaveTransferData(I2C_TypeDef *I2Cx, \
I2C_S_SETUP_Type *TransferCfg, I2C_TRANSFER_OPT_Type Opt);

void I2C_SetOwnSlaveAddr(I2C_TypeDef *I2Cx, I2C_OWNSLAVEADDR_CFG_Type *OwnSlaveAddrConfigStruct);

uint8_t I2C_GetLastStatusCode(I2C_TypeDef* I2Cx);

void I2C_MonitorModeConfig(I2C_TypeDef *I2Cx, uint32_t MonitorCfgType, FunctionalState NewState);

void I2C_MonitorModeCmd(I2C_TypeDef *I2Cx, FunctionalState NewState);
uint8_t I2C_MonitorGetDatabuffer(I2C_TypeDef *I2Cx);

void I2C_StdIntHandler(void);



/**

 * @}
 */


#ifdef __cplusplus

}
#endif

#endif /* __LPC11XX_I2C_H_ */


/**

 * @}
 */

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



/***********************************************************************//**

 * @file : lpc11xx_i2c.c
 * @brief : Contains all functions support for I2C firmware library on LPC11xx
 * @version : 1.0
 * @date : 21. Jan. 2010
 * @author : Coocox
 **********************************************************************/

/* Peripheral group ----------------------------------------------------------- */

/** @addtogroup I2C
 * @{
 */

/* Includes ------------------------------------------------------------------- */

#include "lpc11xx_i2c.h"
#include "lpc11xx_syscon.h"
#include "lpc11xx_libcfg.h"


#if _I2C



/* Private Types -------------------------------------------------------------- */

/** @defgroup I2C_Private_Types
 * @{
 */

/**

 * @brief I2C device configuration structure type
 */
typedef struct
{
  uint32_t      txrx_setup; /* Transmission setup */
  int32_t dir; /* Current direction phase, 0 - write, 1 - read */
  void (*inthandler)(I2C_TypeDef *I2Cx);   /* Transmission interrupt handler */
} I2C_CFG_T;

/**

 * @}
 */

/* Private Variables ---------------------------------------------------------- */

/** @defgroup I2C_Private_Variables
 * @{
 */

/* I2C driver data for I2C0, I2C1 and I2C2 */

static I2C_CFG_T i2cdat[1];


/**

 * @}
 */


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

/** @defgroup I2C_Private_Functions
 * @{
 */

/* Generate a start condition on I2C bus (in master mode only) */

static uint32_t I2C_Start (I2C_TypeDef *I2Cx);

/* Generate a stop condition on I2C bus (in master mode only) */

static void I2C_Stop (I2C_TypeDef *I2Cx);

/* I2C send byte subroutine */

static uint32_t I2C_SendByte (I2C_TypeDef *I2Cx, uint8_t databyte);

/* I2C get byte subroutine */

static uint32_t I2C_GetByte (I2C_TypeDef *I2Cx, uint8_t *retdat, Bool ack);

/* I2C interrupt master handler */

void I2C_MasterHandler (I2C_TypeDef *I2Cx);

/* I2C interrupt master handler */

void I2C_SlaveHandler (I2C_TypeDef *I2Cx);

/* Enable interrupt for I2C device */

void I2C_IntCmd (I2C_TypeDef *I2Cx, Bool NewState);

/*--------------------------------------------------------------------------------*/


/**

 * @brief Convert from I2C peripheral to number
 */
static int32_t I2C_getNum(I2C_TypeDef *I2Cx){
if (I2Cx == LPC_I2C) {
return (0);
}

return (-1);

}

/***********************************************************************

 * Function: I2C_Start
 * Purpose: Generate a start condition on I2C bus (in master mode only)
 * Parameters:
 *     i2cdev: Pointer to I2C register
 *     blocking: blocking or none blocking mode
 * Returns: value of I2C status register after generate a start condition
 **********************************************************************/
static uint32_t I2C_Start (I2C_TypeDef *I2Cx)
{
I2Cx->CONCLR = I2C_I2CONCLR_SIC;
I2Cx->CONSET = I2C_I2CONSET_STA;

// Wait for complete

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


/***********************************************************************

 * Function: I2C_Stop
 * Purpose: Generate a stop condition on I2C bus (in master mode only)
 * Parameters:
 *     I2Cx: Pointer to I2C register
 * Returns: None
 **********************************************************************/
static void I2C_Stop (I2C_TypeDef *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;
}


/***********************************************************************

 * Function: I2C_SendByte
 * Purpose: Send a byte
 * Parameters:
 *     I2Cx: Pointer to I2C register
 * Returns: value of I2C status register after sending
 **********************************************************************/
static uint32_t I2C_SendByte (I2C_TypeDef *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);
}


/***********************************************************************

 * Function: I2C_GetByte
 * Purpose: Get a byte
 * Parameters:
 *     I2Cx: Pointer to I2C register
 * Returns: value of I2C status register after receiving
 **********************************************************************/
static uint32_t I2C_GetByte (I2C_TypeDef *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);
}



/*********************************************************************//**

 * @brief Enable/Disable interrupt for I2C peripheral
 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
 * @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 (I2C_TypeDef *I2Cx, Bool NewState)
{
if (NewState)
{
        NVIC_EnableIRQ(I2C_IRQn);
}
else
{
NVIC_DisableIRQ(I2C_IRQn);
}
    return;
}


/*********************************************************************//**

 * @brief General Master Interrupt handler for I2C peripheral
 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
 * @return None
 **********************************************************************/
void I2C_MasterHandler (I2C_TypeDef  *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;
//break;
/* 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;
//break;
}
}

/* ----------------------------- 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;
//break;

/* 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;
//break;

/* 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);
// Call callback if installed
if (txrx_setup->callback != NULL){
txrx_setup->callback();
}
}
break;
}
}
}


/*********************************************************************//**

 * @brief General Slave Interrupt handler for I2C peripheral
 * @param[in] I2Cx I2C peripheral selected, should be LPC_I2C
 * @return None
 **********************************************************************/
void I2C_SlaveHandler (I2C_TypeDef  *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;
//break;

// 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;
// Call callback if installed
if (txrx_setup->callback != NULL){
txrx_setup->callback();
}
break;
}
}

/**

 * @}
 */


/* Public Functions ----------------------------------------------------------- */

/** @addtogroup I2C_Public_Functions
 * @{
 */

/*********************************************************************//**

 * @brief Setup clock rate for I2C peripheral
 * @param[in] I2Cx I2C peripheral selected, should be LPC_I2C
 * @param[in] target_clock : clock of SSP (Hz)
 * @return None
 ***********************************************************************/
void I2C_SetClock (I2C_TypeDef *I2Cx, uint32_t target_clock)
{
uint32_t temp;

CHECK_PARAM(PARAM_I2Cx(I2Cx));


// Get PCLK of I2C controller

if (I2Cx == LPC_I2C)
{
temp = SystemAHBFrequency / target_clock;
}

/* Set the I2C clock value to register */
I2Cx->SCLH = (uint32_t)(temp / 2);
I2Cx->SCLL = (uint32_t)(temp - I2Cx->SCLH);
}


/*********************************************************************//**

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

/* Disable I2C control */

I2Cx->CONCLR = I2C_I2CONCLR_I2ENC;

    /* Disable power for I2C0 module */

SYSCON_AHBPeriphClockCmd(SYSCON_AHBPeriph_I2C, DISABLE);

    /* Reset I2C */

    SYSCON_PeriphResetCmd(SYSCON_RSTPeriph_I2C, ENABLE);
    SYSCON_PeriphResetCmd(SYSCON_RSTPeriph_I2C, DISABLE);
}

/********************************************************************//**

 * @brief Init I2C SDA and SCL pins, pins assign:
 *                I2C SCL : PIO0_4
 *                I2C SDA : PIO0_5
 * @param[in] mod, i2c mode, it can be
 *               -I2CMODE_SF  : Standard mode/ Fast-mode I2C
 *               -I2CMODE_SIO : Standard I/O functionality
 *               -I2CMODE_FP  : Fast-mode Plus I2C
 * @return None
 *********************************************************************/
void I2C_PinsInit(I2CMODE_Typedef mod)
{
    IOCON_SetPinFunc(IOCON_PIO0_4, PIO0_4_FUN_SCL);   /* I2C SCL - PIO0_4 */
    IOCON_SetPinFunc(IOCON_PIO0_5, PIO0_5_FUN_SDA);   /* I2C SDA - PIO0_5 */

    IOCON_SetI2CMode(IOCON_PIO0_4, mod);

    IOCON_SetI2CMode(IOCON_PIO0_5, mod);
}

/********************************************************************//**

 * @brief Initializes the I2Cx peripheral with specified parameter.                
 *                
 * @param[in] I2Cx I2C peripheral selected, should be LPC_I2C
 * @param[in] clockrate Target clock rate value to initialized I2C
 * peripheral
 * @return None
 *********************************************************************/
void I2C_Init(I2C_TypeDef *I2Cx, uint32_t clockrate)
{
CHECK_PARAM(PARAM_I2Cx(I2Cx));

    /* Enable I2C clock */
SYSCON_AHBPeriphClockCmd (SYSCON_AHBPeriph_I2C, ENABLE);

    /* Set clock rate */
    I2C_SetClock(I2Cx, clockrate);
    /* Set I2C operation to default */
    I2Cx->CONCLR = (I2C_I2CONCLR_AAC | I2C_I2CONCLR_STAC | I2C_I2CONCLR_I2ENC);
}


/*********************************************************************//**

 * @brief Enable or disable I2C peripheral's operation
 * @param[in] I2Cx I2C peripheral selected, LPC_I2C
 * @param[in] NewState New State of I2Cx peripheral's operation
 * @return none
 **********************************************************************/
void I2C_Cmd(I2C_TypeDef* 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 Transmit and Receive data in master mode
 * @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 SUCCESS or 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(I2C_TypeDef *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;
i2cdat[tmp].inthandler = I2C_MasterHandler;
// 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);

return (SUCCESS);

}

return ERROR;

}

/*********************************************************************//**

 * @brief Receive and Transmit data in slave mode
 * @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 SUCCESS or ERROR
 *
 * 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(I2C_TypeDef *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;
//break;
}
} 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;
i2cdat[tmp].inthandler = I2C_SlaveHandler;
// 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 I2C0, I2C1 or I2C2
 * @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(I2C_TypeDef *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->MASK0 = I2C_I2MASK_MASK((uint32_t) \
(OwnSlaveAddrConfigStruct->SlaveAddrMaskValue));
break;
case 1:
I2Cx->ADR1 = tmp;
I2Cx->MASK1 = I2C_I2MASK_MASK((uint32_t) \
(OwnSlaveAddrConfigStruct->SlaveAddrMaskValue));
break;
case 2:
I2Cx->ADR2 = tmp;
I2Cx->MASK2 = I2C_I2MASK_MASK((uint32_t) \
(OwnSlaveAddrConfigStruct->SlaveAddrMaskValue));
break;
case 3:
I2Cx->ADR3 = tmp;
I2Cx->MASK3 = I2C_I2MASK_MASK((uint32_t) \
(OwnSlaveAddrConfigStruct->SlaveAddrMaskValue));
break;
}
}


/*********************************************************************//**

 * @brief Configures functionality in I2C monitor mode
 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
 * @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(I2C_TypeDef *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 I2C0, I2C1 or I2C2
 * @param[in] NewState New State of this function, should be:
 * - ENABLE: Enable monitor mode.
 * - DISABLE: Disable monitor mode.
 * @return None
 **********************************************************************/
void I2C_MonitorModeCmd(I2C_TypeDef *I2Cx, FunctionalState NewState)
{
CHECK_PARAM(PARAM_I2Cx(I2Cx));
CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState));

if (NewState == ENABLE)

{
I2Cx->MMCTRL |= I2C_I2MMCTRL_MM_ENA;
}
else
{
I2Cx->MMCTRL &= (~I2C_I2MMCTRL_MM_ENA) & I2C_I2MMCTRL_BITMASK;
}
}


/*********************************************************************//**

 * @brief Get data from I2C data buffer in monitor mode.
 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
 * @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(I2C_TypeDef *I2Cx)
{
CHECK_PARAM(PARAM_I2Cx(I2Cx));
return ((uint8_t)(I2Cx->DATA_BUFFER));
}

/*********************************************************************//**

 * @brief Standard Interrupt handler for I2C peripheral
 * @param[in] None
 * @return None
 **********************************************************************/
void I2C_StdIntHandler(void)
{
i2cdat[0].inthandler(LPC_I2C);
}

/**

 * @}
 */

#endif /* _I2C */


/**

 * @}
 */

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


.END

CooCox I2C learning notes




CooCox I2C learning notes

.END

Four WuYinS LPC1114s on 19" rack mount top






















Four WuYinS LPC1114s on 19" rack mount top

.END

Old 19" rack mount photos to refresh memory








Old 19" rack mount photos to refresh memory

Google search "tlfong01 19" rack" results

https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoFuqXkfJXHIYcvRw0BmFIR2ombrFf6DQuA2L5Cqv9BoE1Y2Kk0ZR1UOJbzGD4DWOLcFLHa5MtWSkrS4AxP8pqsZQtlMAPeaV7RMIedKSB-amoeaXxMOqoJhyphenhyphenbotlneAtF3JFA8AZlpv4/s640/rpi_setup_2013feb2701.jpg

https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmFWDC-F1W8gFBYSFh0AU7hfvIHQTdKngG70ZQlxTd85VAEndZhtcOdEoQEJk_NgnyVIokdXbZoksxPJMklF4B6tgjwVlr7hCJ7lgCuU7BXBHDh950vk5UOLqhIDI3h3BrbgCHuDMsYbc/s640/rpi_pair_2013mar0101.jpg

https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjU4KyEfbNGruh064aT2oTCW9bzuA8n1QP-uGPR7Mzh8yDkNhFOMR19ofpbmLCT99HJhyphenhyphen-khUDMeD6n3SJM4zftB64rpeuASoHlqLUnCxi1a0G48miEQBI4q3A0hRSr-zYL4lsboEVqqxE/s640/rack_mount_power_supply_2013jan2701.jpg

https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIYay1EBjztZlrp6CDj-j0iK3TfnVAWe1jatFbisdOtjmqQmCAa5dAHK4uffEqZ4jIpOmAhX5SzjRnQf_hzWM8_CG86oS_lirmKD8UGfLXMtT3I-cVn8YabRftIQL_rYfHLRzhSVtAcvI/s640/rpi_linksys_wusb54gc_setup_2013apr1101.jpg

https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcTjP6X_kdHR5cDoPqfqV3wamhssN-mMnI9IqW1DX76ufqeKu0uZ

https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBNYt4oeSSGmdU_mPn1TaUJFT6TTYbKChkNF_z_9XX30Ml0IaP3FpLRwHkaAZpoxZhY-2XVBfOQjJJ8VYFcv6NxXfjJ-nghsssiba_wOoRg2yGdCFoArdOOBub41qjTCXZW2DB2-3ge_Y/s1600/rpi_system_c_2013feb0602.jpg

.END