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

No comments:

Post a Comment