Skip to content
Snippets Groups Projects
Commit 4c72f572 authored by Gregory Nutt's avatar Gregory Nutt
Browse files

arch/arm/src/lpc54xx: I2C now appears to be functional. Needs more testing.

parent c8a8eb02
No related branches found
No related tags found
No related merge requests found
......@@ -86,7 +86,11 @@
/* 20 Millisecond timeout in system clock ticks. */
#define I2C_WDOG_TIMEOUT MSEC2TICK(20)
#ifdef CONFIG_DEBUG_I2C_INFO
# define I2C_WDOG_TIMEOUT MSEC2TICK(50)
#else
# define I2C_WDOG_TIMEOUT MSEC2TICK(20)
#endif
/* Default I2C frequency */
......@@ -114,7 +118,7 @@ enum lpc54_i2cstate_e
I2CSTATE_RECEIVE,
I2CSTATE_START,
I2CSTATE_STOP,
I2CSTATE_WAITDONE
I2CSTATE_WAITSTOP
};
/* This structure provides the overall state of the I2C driver */
......@@ -261,6 +265,8 @@ static void lpc54_i2c_setfrequency(struct lpc54_i2cdev_s *priv,
uint32_t best_err;
uint32_t regval;
i2cinfo("frequency %ld (%ld)\n", (long)frequency, (long)priv->frequency);
/* Has the I2C frequency changed? */
if (frequency != priv->frequency)
......@@ -338,13 +344,19 @@ static void lpc54_i2c_timeout(int argc, uint32_t arg, ...)
irqstate_t flags = enter_critical_section();
#endif
i2cerr("ERROR: Timeout! state=%u\n", priv->state);
/* Disable further I2C interrupts and return to the IDLE state with the
* timeout result.
*/
lpc54_i2c_putreg(priv, LPC54_I2C_INTENCLR_OFFSET, I2C_MASTER_INTS);
priv->state = I2CSTATE_IDLE;
priv->result = -ETIMEDOUT;
if (priv->result == OK)
{
priv->result = -ETIMEDOUT;
}
#ifndef CONFIG_I2C_POLLED
/* Wake up any waiters */
......@@ -443,15 +455,18 @@ static bool lpc54_i2c_nextmsg(struct lpc54_i2cdev_s *priv)
flags = enter_critical_section();
i2cinfo("nmsgs=%u\n", priv->nmsgs - 1);
/* Decrement the number of messages remaining. */
if (--priv->nmsgs > 0)
if (--priv->nmsgs > 0 && priv->result == OK)
{
/* There are more messages, set up for the next message */
priv->msgs++;
lpc54_i2c_xfrsetup(priv);
i2cinfo("state=%u\n", priv->state);
leave_critical_section(flags);
return false;
}
......@@ -467,6 +482,7 @@ static bool lpc54_i2c_nextmsg(struct lpc54_i2cdev_s *priv)
lpc54_i2c_putreg(priv, LPC54_I2C_INTENCLR_OFFSET, I2C_MASTER_INTS);
priv->state = I2CSTATE_IDLE;
i2cinfo("state=%u\n", priv->state);
leave_critical_section(flags);
return true;
}
......@@ -491,10 +507,14 @@ static bool lpc54_i2c_statemachine(struct lpc54_i2cdev_s *priv)
DEBUGASSERT(priv != NULL && priv->msgs != NULL);
msg = priv->msgs;
i2cinfo("state=%u\n", priv->state);
status = lpc54_i2c_getreg(priv, LPC54_I2C_STAT_OFFSET);
if (status & I2C_INT_MSTARBLOSS)
{
i2cerr("ERROR: Arbitation loss\n");
lpc54_i2c_putreg(priv, LPC54_I2C_STAT_OFFSET, I2C_INT_MSTARBLOSS);
priv->result = -EIO;
return true;
......@@ -502,6 +522,8 @@ static bool lpc54_i2c_statemachine(struct lpc54_i2cdev_s *priv)
if (status & I2C_INT_MSTSTSTPERR)
{
i2cerr("ERROR: Start/stop error\n");
lpc54_i2c_putreg(priv, LPC54_I2C_STAT_OFFSET, I2C_INT_MSTSTSTPERR);
priv->result = -EIO;
return true;
......@@ -509,6 +531,8 @@ static bool lpc54_i2c_statemachine(struct lpc54_i2cdev_s *priv)
if ((status & I2C_INT_MSTPENDING) == 0)
{
i2cerr("ERROR: Busy\n");
priv->result = -EBUSY;
return true;
}
......@@ -516,6 +540,7 @@ static bool lpc54_i2c_statemachine(struct lpc54_i2cdev_s *priv)
/* Get the state of the I2C module */
mstate = (status & I2C_STAT_MSTSTATE_MASK) >> I2C_STAT_MSTSTATE_SHIFT;
i2cinfo("mstate=%u\n", mstate);
if ((mstate == I2C_MASTER_STATE_ADDRNAK) ||
(mstate == I2C_MASTER_STATE_DATANAK))
......@@ -524,7 +549,9 @@ static bool lpc54_i2c_statemachine(struct lpc54_i2cdev_s *priv)
lpc54_i2c_putreg(priv, LPC54_I2C_MSTCTL_OFFSET, I2C_MSTCTL_MSTSTOP);
priv->result = -EPERM;
priv->state = I2CSTATE_WAITDONE;
priv->state = I2CSTATE_WAITSTOP;
i2cerr("ERROR: NAKed, state=%u\n", priv->state);
return false;
}
......@@ -538,13 +565,13 @@ static bool lpc54_i2c_statemachine(struct lpc54_i2cdev_s *priv)
{
lpc54_i2c_putreg(priv, LPC54_I2C_MSTDAT_OFFSET,
I2C_READADDR8(msg->addr));
newstate = I2CSTATE_TRANSMIT;
newstate = I2CSTATE_RECEIVE;
}
else
{
lpc54_i2c_putreg(priv, LPC54_I2C_MSTDAT_OFFSET,
I2C_WRITEADDR8(msg->addr));
newstate = I2CSTATE_RECEIVE;
newstate = I2CSTATE_TRANSMIT;
}
if (priv->xfrd >= msg->length)
......@@ -567,6 +594,9 @@ static bool lpc54_i2c_statemachine(struct lpc54_i2cdev_s *priv)
{
if (mstate != I2C_MASTER_STATE_TXOK)
{
i2cerr("ERROR bad state=%u, expected %u\n",
mstate, I2C_MASTER_STATE_TXOK);
priv->result = -EINVAL;
return true;
}
......@@ -590,6 +620,9 @@ static bool lpc54_i2c_statemachine(struct lpc54_i2cdev_s *priv)
{
if (mstate != I2C_MASTER_STATE_RXAVAIL)
{
i2cerr("ERROR bad state=%u, expected %u\n",
mstate, I2C_MASTER_STATE_RXAVAIL);
priv->result = -EINVAL;
return true;
}
......@@ -609,7 +642,7 @@ static bool lpc54_i2c_statemachine(struct lpc54_i2cdev_s *priv)
lpc54_i2c_putreg(priv, LPC54_I2C_MSTCTL_OFFSET,
I2C_MSTCTL_MSTSTOP);
priv->state = I2CSTATE_WAITDONE;
priv->state = I2CSTATE_WAITSTOP;
}
}
break;
......@@ -646,12 +679,12 @@ static bool lpc54_i2c_statemachine(struct lpc54_i2cdev_s *priv)
lpc54_i2c_putreg(priv, LPC54_I2C_MSTCTL_OFFSET,
I2C_MSTCTL_MSTSTOP);
priv->state = I2CSTATE_WAITDONE;
priv->state = I2CSTATE_WAITSTOP;
}
}
break;
case I2CSTATE_WAITDONE:
case I2CSTATE_WAITSTOP:
{
/* Start the next message (or return to the IDLE state if none). */
......@@ -665,6 +698,7 @@ static bool lpc54_i2c_statemachine(struct lpc54_i2cdev_s *priv)
return true;
}
i2cinfo("state=%u\n", priv->state);
return false;
}
......@@ -716,7 +750,8 @@ static int lpc54_i2c_transfer(FAR struct i2c_master_s *dev,
struct lpc54_i2cdev_s *priv = (struct lpc54_i2cdev_s *)dev;
int ret;
DEBUGASSERT(dev != NULL);
i2cinfo("count=%d\n", count);
DEBUGASSERT(dev != NULL && msgs != NULL);
/* Get exclusive access to the I2C bus */
......@@ -724,15 +759,16 @@ static int lpc54_i2c_transfer(FAR struct i2c_master_s *dev,
/* Set up for the transfer */
priv->xfrd = 0;
priv->msgs = msgs;
priv->nmsgs = count;
priv->xfrd = 0;
priv->msgs = msgs;
priv->nmsgs = count;
priv->result = OK;
/* Set up the transfer timeout */
/* wd_start(priv->timeout ...); */
wd_start(priv->timeout, I2C_WDOG_TIMEOUT, lpc54_i2c_timeout, 1,
(uint32_t)priv);
wd_start(priv->timeout, priv->nmsgs * I2C_WDOG_TIMEOUT, lpc54_i2c_timeout,
1, (uint32_t)priv);
/* Initiate the transfer */
......@@ -751,6 +787,8 @@ static int lpc54_i2c_transfer(FAR struct i2c_master_s *dev,
while (priv->state != I2CSTATE_IDLE);
ret = priv->result;
i2cinfo("Done, result=%d\n", ret);
nxsem_post(&priv->exclsem);
return ret;
}
......@@ -795,6 +833,8 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
irqstate_t flags;
uint32_t regval;
i2cinfo("port=%d\n", port);
flags = enter_critical_section();
/* Configure the requestin I2C peripheral */
......@@ -1143,6 +1183,7 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
else
#endif
{
i2cerr("ERROR: Unsupported port=%d\n", port);
return NULL;
}
......
......@@ -48,21 +48,7 @@ STATUS
were configured. Now the LCD appears to be fully functional.
2017-12-15: Added an I2C driver. This is the first step on the road
to getting support for the capacitive touchscreen on the TFT panel.
Not yet functional:
nsh> i2c dev -b 2 3 77
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
I believe that the on-board Accelerometer, Audio Codec, and touch panel controller should have been detected (but perhaps that are not properly
powered in this configuration?)
The I2C driver appears to be functional but is not yet well-tested.
Configurations
==============
......@@ -213,3 +199,21 @@ Configurations
Bus 7: NO
Bus 8: NO
Bus 9: NO
nsh> i2c dev -b 2 3 77
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- 1a -- -- 1d -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
I believe that the on-board Accelerometer, Audio Codec, and touch
panel controller should have been detected (but perhaps the touch
panel is not powered in this configuration?)
Codec I2C address: 0x1a
Accel I2C address: 0x1d
Touch panel I2C address: 0x38
......@@ -110,7 +110,8 @@
(GPIO_PORT3 | GPIO_PIN31 | GPIO_VALUE_ZERO | GPIO_OUTPUT | \
GPIO_MODE_DIGITAL | GPIO_FILTER_OFF | GPIO_PUSHPULL | GPIO_PULLUP)
/* The integrated touchscreen uses one GPIO out and one GPIO interrupting GPIO input;
/* The integrated touchscreen uses one GPIO out and one GPIO interrupting
* GPIO input:
*
* P2.27 CT_RSTn
* P4.0 INTR
......@@ -120,6 +121,12 @@
(GPIO_PORT2 | GPIO_PIN27 | GPIO_VALUE_ZERO | GPIO_OUTPUT | \
GPIO_MODE_DIGITAL | GPIO_FILTER_OFF | GPIO_PUSHPULL | GPIO_PULLUP)
/* I2C addresses (7-bit): */
#define CODEC_I2C_ADDRESS 0x1a
#define ACCEL_I2C_ADDRESS 0x1d
#define TSC_I2C_ADDRESS 0x38
/****************************************************************************
* Public Types
****************************************************************************/
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment