338 lines
12 KiB
C
338 lines
12 KiB
C
/*
|
|
* @brief LPC8XX I2C slave driver
|
|
*
|
|
* @note
|
|
* Copyright(C) NXP Semiconductors, 2014
|
|
* All rights reserved.
|
|
*
|
|
* @par
|
|
* Software that is described herein is for illustrative purposes only
|
|
* which provides customers with programming information regarding the
|
|
* LPC products. This software is supplied "AS IS" without any warranties of
|
|
* any kind, and NXP Semiconductors and its licensor disclaim any and
|
|
* all warranties, express or implied, including all implied warranties of
|
|
* merchantability, fitness for a particular purpose and non-infringement of
|
|
* intellectual property rights. NXP Semiconductors assumes no responsibility
|
|
* or liability for the use of the software, conveys no license or rights under any
|
|
* patent, copyright, mask work right, or any other intellectual property rights in
|
|
* or to any products. NXP Semiconductors reserves the right to make changes
|
|
* in the software without notification. NXP Semiconductors also makes no
|
|
* representation or warranty that such application will be suitable for the
|
|
* specified use without further testing or modification.
|
|
*
|
|
* @par
|
|
* Permission to use, copy, modify, and distribute this software and its
|
|
* documentation is hereby granted, under NXP Semiconductors' and its
|
|
* licensor's relevant copyrights in the software, without fee, provided that it
|
|
* is used in conjunction with NXP Semiconductors microcontrollers. This
|
|
* copyright, permission, and disclaimer notice must appear in all copies of
|
|
* this code.
|
|
*/
|
|
|
|
#ifndef __I2CS_8XX_H_
|
|
#define __I2CS_8XX_H_
|
|
|
|
#include "i2c_common_8xx.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/** @defgroup I2CS_8XX CHIP: LPC8XX I2C slave-only driver
|
|
* @ingroup I2C_8XX
|
|
* This driver only works in slave mode.
|
|
* @{
|
|
*/
|
|
|
|
/** @brief I2C slave service start callback
|
|
* This callback is called from the I2C slave handler when an I2C slave address is
|
|
* received and needs servicing. It's used to indicate the start of a slave transfer
|
|
* that will happen on the slave bus.
|
|
*/
|
|
typedef void (*I2CSlaveXferStart)(uint8_t addr);
|
|
|
|
/** @brief I2C slave send data callback
|
|
* This callback is called from the I2C slave handler when an I2C slave address needs
|
|
* data to send. Return 0 to NACK the master and terminate the transfer, or return
|
|
* a non-0 value with the value to send in *data.
|
|
*/
|
|
typedef uint8_t (*I2CSlaveXferSend)(uint8_t *data);
|
|
|
|
/** @brief I2C slave receive data callback
|
|
* This callback is called from the I2C slave handler when an I2C slave address has
|
|
* receive data. Return 0 to NACK the master and terminate the transfer, or return
|
|
* a non-0 value to continue the transfer.
|
|
*/
|
|
typedef uint8_t (*I2CSlaveXferRecv)(uint8_t data);
|
|
|
|
/** @brief I2C slave service done callback
|
|
* This callback is called from the I2C slave handler when an I2C slave transfer is
|
|
* completed. It's used to indicate the end of a slave transfer.
|
|
*/
|
|
typedef void (*I2CSlaveXferDone)(void);
|
|
|
|
/**
|
|
* Slave transfer are performed using 3 callbacks. These 3 callbacks handle most I2C
|
|
* slave transfer cases. When the slave is setup and a slave interrupt is receive
|
|
* and processed with the Chip_I2CS_XferHandler() function in the I2C interrupt handler,
|
|
* one of these 3 callbacks is called. The callbacks can be used for unsized transfers
|
|
* from the master.
|
|
*
|
|
* When an address is received, the SlaveXferAddr() callback is called with the
|
|
* received address. Only addresses enabled in the slave controller will be handled.
|
|
* The slave controller can support up to 4 slave addresses.
|
|
*
|
|
* If the master is going to perform a read operation, the SlaveXferSend() callback
|
|
* is called. Place the data byte to send in *data and return a non-0 value to the
|
|
* caller, or return 0 to NACK the master. (Note the master ACKS/NACKS to slave
|
|
* on reads, so this won't necessarily stop the slave transfer.)<br>
|
|
*
|
|
* If the master performs a write operation, the SlaveXferRecv() callback is called
|
|
* with the received data. Return a non-0 value to the caller, or return 0 to NACK
|
|
* the master.<br>
|
|
*
|
|
* Once the transfer completes, the SlaveXferDone() callback will be called.<br>
|
|
*/
|
|
typedef struct {
|
|
I2CSlaveXferStart slaveStart; /*!< Called when an matching I2C slave address is received */
|
|
I2CSlaveXferSend slaveSend; /*!< Called when a byte is needed to send to master */
|
|
I2CSlaveXferRecv slaveRecv; /*!< Called when a byte is received from master */
|
|
I2CSlaveXferDone slaveDone; /*!< Called when a slave transfer is complete */
|
|
} I2CS_XFER_T;
|
|
|
|
/**
|
|
* @brief Enable I2C slave interface
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @return Nothing
|
|
* @note Do not call this function until the slave interface is fully configured.
|
|
*/
|
|
STATIC INLINE void Chip_I2CS_Enable(LPC_I2C_T *pI2C)
|
|
{
|
|
pI2C->CFG = (pI2C->CFG & I2C_CFG_MASK) | I2C_CFG_SLVEN;
|
|
}
|
|
|
|
/**
|
|
* @brief Disable I2C slave interface
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @return Nothing
|
|
*/
|
|
STATIC INLINE void Chip_I2CS_Disable(LPC_I2C_T *pI2C)
|
|
{
|
|
pI2C->CFG = (pI2C->CFG & I2C_CFG_MASK) & ~I2C_CFG_SLVEN;
|
|
}
|
|
|
|
/**
|
|
* @brief Get I2C Status
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @return I2C Status register value
|
|
* @note This function returns the value of the status register.
|
|
*/
|
|
STATIC INLINE uint32_t Chip_I2CS_GetStatus(LPC_I2C_T *pI2C)
|
|
{
|
|
return pI2C->STAT & ~I2C_STAT_RESERVED;
|
|
}
|
|
|
|
/**
|
|
* @brief Clear I2C status bits (slave)
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @param clrStatus : Status bit to clear, must be I2C_STAT_SLVDESEL
|
|
* @return Nothing
|
|
* @note This function clears selected status flags.
|
|
*/
|
|
STATIC INLINE void Chip_I2CS_ClearStatus(LPC_I2C_T *pI2C, uint32_t clrStatus)
|
|
{
|
|
pI2C->STAT = clrStatus & I2C_STAT_SLVDESEL;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if I2C slave is pending
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @return Returns TRUE if the slave is pending else returns FALSE
|
|
* @note
|
|
*/
|
|
STATIC INLINE bool Chip_I2CS_IsSlavePending(LPC_I2C_T *pI2C)
|
|
{
|
|
return (pI2C->STAT & I2C_STAT_SLVPENDING) != 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if I2C slave is selected
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @return Returns TRUE if the slave is is selected, otherwise FALSE
|
|
* @note
|
|
*/
|
|
STATIC INLINE bool Chip_I2CS_IsSlaveSelected(LPC_I2C_T *pI2C)
|
|
{
|
|
return (pI2C->STAT & I2C_STAT_SLVSEL) != 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if I2C slave is deselected
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @return Returns TRUE if the slave is is deselected, otherwise FALSE
|
|
* @note
|
|
*/
|
|
STATIC INLINE bool Chip_I2CS_IsSlaveDeSelected(LPC_I2C_T *pI2C)
|
|
{
|
|
return (pI2C->STAT & I2C_STAT_SLVDESEL) != 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Get current state of the I2C slave
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @return slave State Code, a value of type I2C_STAT_SLVCODE_*
|
|
* @note After the slave is pending this state code tells the reason
|
|
* for slave pending.
|
|
*/
|
|
STATIC INLINE uint32_t Chip_I2CS_GetSlaveState(LPC_I2C_T *pI2C)
|
|
{
|
|
return (pI2C->STAT & I2C_STAT_SLVSTATE) >> 9;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the current slave address match index
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @return slave match index, 0 - 3
|
|
*/
|
|
STATIC INLINE uint32_t Chip_I2CS_GetSlaveMatchIndex(LPC_I2C_T *pI2C)
|
|
{
|
|
return (pI2C->STAT & I2C_STAT_SLVIDX) >> 12;
|
|
}
|
|
|
|
/**
|
|
* @brief Slave Continue transfer operation (ACK)
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @return Nothing
|
|
* @note This function sets the slave controller to continue transmission.
|
|
* This should be called only when slave is pending. The function writes a
|
|
* complete value to slave Control register, ORing is not advised.
|
|
*/
|
|
STATIC INLINE void Chip_I2CS_SlaveContinue(LPC_I2C_T *pI2C)
|
|
{
|
|
pI2C->SLVCTL = I2C_SLVCTL_SLVCONTINUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Slave NACK operation
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @return Nothing
|
|
* @note This function sets the slave controller to NAK the master.
|
|
*/
|
|
STATIC INLINE void Chip_I2CS_SlaveNACK(LPC_I2C_T *pI2C)
|
|
{
|
|
pI2C->SLVCTL = I2C_SLVCTL_SLVNACK;
|
|
}
|
|
|
|
/**
|
|
* @brief Transmit a single data byte through the I2C peripheral (slave)
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @param data : Byte to transmit
|
|
* @return Nothing
|
|
* @note This function attempts to place a byte into the I2C slave
|
|
* Data Register
|
|
*
|
|
*/
|
|
STATIC INLINE void Chip_I2CS_WriteByte(LPC_I2C_T *pI2C, uint8_t data)
|
|
{
|
|
pI2C->SLVDAT = (uint32_t) data;
|
|
}
|
|
|
|
/**
|
|
* @brief Read a single byte data from the I2C peripheral (slave)
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @return A single byte of data read
|
|
* @note This function reads a byte from the I2C receive hold register
|
|
* regardless of I2C state.
|
|
*/
|
|
STATIC INLINE uint8_t Chip_I2CS_ReadByte(LPC_I2C_T *pI2C)
|
|
{
|
|
return (uint8_t) (pI2C->SLVDAT & I2C_SLVDAT_DATAMASK);
|
|
}
|
|
|
|
/**
|
|
* @brief Set a I2C slave address for slave operation
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @param slvNum : Possible slave address number, between 0 - 3
|
|
* @param slvAddr : Slave Address for the index (7-bits, bit 7 = 0)
|
|
* @return Nothing
|
|
* @note Setting a slave address also enables the slave address. Do
|
|
* not 'pre-shift' the slave address.
|
|
*/
|
|
STATIC INLINE void Chip_I2CS_SetSlaveAddr(LPC_I2C_T *pI2C, uint8_t slvNum, uint8_t slvAddr)
|
|
{
|
|
pI2C->SLVADR[slvNum] = (uint32_t) (slvAddr << 1);
|
|
}
|
|
|
|
/**
|
|
* @brief Return a I2C programmed slave address
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @param slvNum : Possible slave address number, between 0 - 3
|
|
* @return Nothing
|
|
*/
|
|
STATIC INLINE uint8_t Chip_I2CS_GetSlaveAddr(LPC_I2C_T *pI2C, uint8_t slvNum)
|
|
{
|
|
return (pI2C->SLVADR[slvNum] >> 1) & 0x7F;
|
|
}
|
|
|
|
/**
|
|
* @brief Enable a I2C address
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @param slvNum : Possible slave address number, between 0 - 3
|
|
* @return Nothing
|
|
*/
|
|
STATIC INLINE void Chip_I2CS_EnableSlaveAddr(LPC_I2C_T *pI2C, uint8_t slvNum)
|
|
{
|
|
pI2C->SLVADR[slvNum] = (pI2C->SLVADR[slvNum] & I2C_SLVADR_MASK) & ~I2C_SLVADR_SADISABLE;
|
|
}
|
|
|
|
/**
|
|
* @brief Disable a I2C address
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @param slvNum : Possible slave address number, between 0 - 3
|
|
* @return Nothing
|
|
*/
|
|
STATIC INLINE void Chip_I2CS_DisableSlaveAddr(LPC_I2C_T *pI2C, uint8_t slvNum)
|
|
{
|
|
pI2C->SLVADR[slvNum] = (pI2C->SLVADR[slvNum] & I2C_SLVADR_MASK) | I2C_SLVADR_SADISABLE;
|
|
}
|
|
|
|
/**
|
|
* @brief Setup slave qialifier address
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @param extend : true to extend I2C slave detect address 0 range, or false to match to corresponding bits
|
|
* @param slvAddr : Slave address qualifier, see SLVQUAL0 register in User Manual
|
|
* @return Nothing
|
|
* @note Do not 'pre-shift' the slave address.
|
|
*/
|
|
STATIC INLINE void Chip_I2CS_SetSlaveQual0(LPC_I2C_T *pI2C, bool extend, uint8_t slvNum)
|
|
{
|
|
slvNum = slvNum << 1;
|
|
if (extend) {
|
|
slvNum |= I2C_SLVQUAL_QUALMODE0;
|
|
}
|
|
|
|
pI2C->SLVQUAL0 = slvNum;
|
|
}
|
|
|
|
/**
|
|
* @brief Slave transfer state change handler
|
|
* @param pI2C : Pointer to selected I2C peripheral
|
|
* @param xfers : Pointer to a I2CS_MULTI_XFER_T structure see notes below
|
|
* @return Returns non-zero value on completion of transfer
|
|
* @note See @ref I2CS_XFER_T for more information on this function. When using
|
|
* this function, the I2C_INTENSET_SLVPENDING and I2C_INTENSET_SLVDESEL interrupts
|
|
* should be enabled and setup in the I2C interrupt handler to call this function
|
|
* when they fire.
|
|
*/
|
|
uint32_t Chip_I2CS_XferHandler(LPC_I2C_T *pI2C, const I2CS_XFER_T *xfers);
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* __I2CS_8XX_H_ */
|