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