260 lines
7.4 KiB
C
260 lines
7.4 KiB
C
/*
|
|
* @brief LPC13xx I2C master driver
|
|
*
|
|
* @note
|
|
* Copyright(C) NXP Semiconductors, 2013
|
|
* 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.
|
|
*/
|
|
|
|
#include "chip.h"
|
|
|
|
/*****************************************************************************
|
|
* Private types/enumerations/variables
|
|
****************************************************************************/
|
|
|
|
/* Control flags */
|
|
#define I2C_CON_FLAGS (I2C_CON_AA | I2C_CON_SI | I2C_CON_STO | I2C_CON_STA)
|
|
|
|
/*****************************************************************************
|
|
* Public types/enumerations/variables
|
|
****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* Private functions
|
|
****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* Public functions
|
|
****************************************************************************/
|
|
|
|
/* Initializes the LPC_I2C peripheral with specified parameter */
|
|
void Chip_I2CM_Init(LPC_I2C_T *pI2C)
|
|
{
|
|
/* Enable I2C clock */
|
|
Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_I2C);
|
|
|
|
/* Peripheral reset control to I2C */
|
|
Chip_SYSCTL_PeriphReset(RESET_I2C0);
|
|
}
|
|
|
|
/* De-initializes the I2C peripheral registers to their default reset values */
|
|
void Chip_I2CM_DeInit(LPC_I2C_T *pI2C)
|
|
{
|
|
/* Disable I2C clock */
|
|
Chip_Clock_DisablePeriphClock(SYSCTL_CLOCK_I2C);
|
|
}
|
|
|
|
/* Set up bus speed for LPC_I2C interface */
|
|
void Chip_I2CM_SetBusSpeed(LPC_I2C_T *pI2C, uint32_t busSpeed)
|
|
{
|
|
uint32_t clockDiv = (Chip_Clock_GetMainClockRate() / busSpeed);
|
|
|
|
Chip_I2CM_SetDutyCycle(pI2C, (clockDiv >> 1), (clockDiv - (clockDiv >> 1)));
|
|
}
|
|
|
|
/* Master transfer state change handler handler */
|
|
uint32_t Chip_I2CM_XferHandler(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer)
|
|
{
|
|
uint32_t cclr = I2C_CON_FLAGS;
|
|
|
|
switch (Chip_I2CM_GetCurState(pI2C)) {
|
|
case 0x08: /* Start condition on bus */
|
|
case 0x10: /* Repeated start condition */
|
|
pI2C->DAT = (xfer->slaveAddr << 1) | (xfer->txSz == 0);
|
|
break;
|
|
|
|
/* Tx handling */
|
|
case 0x20: /* SLA+W sent NAK received */
|
|
case 0x30: /* DATA sent NAK received */
|
|
if ((xfer->options & I2CM_XFER_OPTION_IGNORE_NACK) == 0) {
|
|
xfer->status = I2CM_STATUS_NAK;
|
|
cclr &= ~I2C_CON_STO;
|
|
break;
|
|
}
|
|
|
|
case 0x18: /* SLA+W sent and ACK received */
|
|
case 0x28: /* DATA sent and ACK received */
|
|
if (!xfer->txSz) {
|
|
if (xfer->rxSz) {
|
|
cclr &= ~I2C_CON_STA;
|
|
}
|
|
else {
|
|
xfer->status = I2CM_STATUS_OK;
|
|
cclr &= ~I2C_CON_STO;
|
|
}
|
|
|
|
}
|
|
else {
|
|
pI2C->DAT = *xfer->txBuff++;
|
|
xfer->txSz--;
|
|
}
|
|
break;
|
|
|
|
/* Rx handling */
|
|
case 0x58: /* Data Received and NACK sent */
|
|
case 0x50: /* Data Received and ACK sent */
|
|
*xfer->rxBuff++ = pI2C->DAT;
|
|
xfer->rxSz--;
|
|
|
|
case 0x40: /* SLA+R sent and ACK received */
|
|
if ((xfer->rxSz > 1) || (xfer->options & I2CM_XFER_OPTION_LAST_RX_ACK)) {
|
|
cclr &= ~I2C_CON_AA;
|
|
}
|
|
if (xfer->rxSz == 0) {
|
|
xfer->status = I2CM_STATUS_OK;
|
|
cclr &= ~I2C_CON_STO;
|
|
}
|
|
break;
|
|
|
|
/* NAK Handling */
|
|
case 0x48: /* SLA+R sent NAK received */
|
|
xfer->status = I2CM_STATUS_SLAVE_NAK;
|
|
cclr &= ~I2C_CON_STO;
|
|
break;
|
|
|
|
case 0x38: /* Arbitration lost */
|
|
xfer->status = I2CM_STATUS_ARBLOST;
|
|
break;
|
|
|
|
case 0x00: /* Bus Error */
|
|
xfer->status = I2CM_STATUS_BUS_ERROR;
|
|
cclr &= ~I2C_CON_STO;
|
|
break;
|
|
|
|
default:
|
|
xfer->status = I2CM_STATUS_ERROR;
|
|
cclr &= ~I2C_CON_STO;
|
|
break;
|
|
}
|
|
|
|
/* Set clear control flags */
|
|
pI2C->CONSET = cclr ^ I2C_CON_FLAGS;
|
|
pI2C->CONCLR = cclr;
|
|
|
|
return xfer->status != I2CM_STATUS_BUSY;
|
|
}
|
|
|
|
/* Transmit and Receive data in master mode */
|
|
void Chip_I2CM_Xfer(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer)
|
|
{
|
|
/* set the transfer status as busy */
|
|
xfer->status = I2CM_STATUS_BUSY;
|
|
/* Clear controller state. */
|
|
Chip_I2CM_ResetControl(pI2C);
|
|
/* Enter to Master Transmitter mode */
|
|
Chip_I2CM_SendStart(pI2C);
|
|
}
|
|
|
|
/* Transmit and Receive data in master mode */
|
|
uint32_t Chip_I2CM_XferBlocking(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer)
|
|
{
|
|
uint32_t ret = 0;
|
|
/* start transfer */
|
|
Chip_I2CM_Xfer(pI2C, xfer);
|
|
|
|
while (ret == 0) {
|
|
/* wait for status change interrupt */
|
|
while ( Chip_I2CM_StateChanged(pI2C) == 0) {}
|
|
/* call state change handler */
|
|
ret = Chip_I2CM_XferHandler(pI2C, xfer);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* Master tx only */
|
|
uint32_t Chip_I2CM_Write(LPC_I2C_T *pI2C, const uint8_t *buff, uint32_t len)
|
|
{
|
|
uint32_t txLen = 0, err = 0;
|
|
|
|
/* clear state change interrupt status */
|
|
Chip_I2CM_ClearSI(pI2C);
|
|
/* generate START condition */
|
|
Chip_I2CM_SendStart(pI2C);
|
|
|
|
while ((txLen < len) && (err == 0)) {
|
|
/* wait for status change interrupt */
|
|
while ( Chip_I2CM_StateChanged(pI2C) == 0) {}
|
|
|
|
/* check status and send data */
|
|
switch (Chip_I2CM_GetCurState(pI2C)) {
|
|
case 0x08: /* Start condition on bus */
|
|
case 0x10: /* Repeated start condition */
|
|
case 0x18: /* SLA+W sent and ACK received */
|
|
case 0x28: /* DATA sent and ACK received */
|
|
Chip_I2CM_WriteByte(pI2C, buff[txLen++]);
|
|
break;
|
|
|
|
case 0x38: /* Arbitration lost */
|
|
break;
|
|
|
|
default: /* we shouldn't be in any other state */
|
|
err = 1;
|
|
break;
|
|
}
|
|
/* clear state change interrupt status */
|
|
Chip_I2CM_ClearSI(pI2C);
|
|
}
|
|
|
|
return txLen;
|
|
}
|
|
|
|
/* Sequential master read */
|
|
uint32_t Chip_I2CM_Read(LPC_I2C_T *pI2C, uint8_t *buff, uint32_t len)
|
|
{
|
|
uint32_t rxLen = 0, err = 0;
|
|
|
|
/* clear state change interrupt status */
|
|
Chip_I2CM_ClearSI(pI2C);
|
|
/* generate START condition and auto-ack data received */
|
|
pI2C->CONSET = I2C_CON_AA | I2C_CON_STA;
|
|
|
|
while ((rxLen < len) && (err == 0)) {
|
|
/* wait for status change interrupt */
|
|
while ( Chip_I2CM_StateChanged(pI2C) == 0) {}
|
|
|
|
/* check status and send data */
|
|
switch (Chip_I2CM_GetCurState(pI2C)) {
|
|
case 0x08: /* Start condition on bus */
|
|
case 0x10: /* Repeated start condition */
|
|
case 0x40: /* SLA+R sent and ACK received */
|
|
case 0x50: /* Data Received and ACK sent */
|
|
buff[rxLen++] = Chip_I2CM_ReadByte(pI2C);
|
|
break;
|
|
|
|
case 0x38: /* Arbitration lost */
|
|
break;
|
|
|
|
default: /* we shouldn't be in any other state */
|
|
err = 1;
|
|
break;
|
|
}
|
|
/* clear state change interrupt status */
|
|
Chip_I2CM_ClearSI(pI2C);
|
|
}
|
|
|
|
return rxLen;
|
|
}
|