arch/arm/src/lpc54xx: Complete coding of the I2C driver. It is not yet functional and has not yet been seriously tested. config/lpcxpresso-lpc54628: Add support for I2C2 and for the I2C tool to the nsh configuration.

This commit is contained in:
Gregory Nutt 2017-12-15 11:38:55 -06:00
parent 9638f3f065
commit c8a8eb028f
8 changed files with 642 additions and 191 deletions

View File

@ -313,6 +313,8 @@
#define I2C_SLAVE_STATE_RXAVAIL (1) /* Received data is available (Slave Receiver mode) */
#define I2C_SLAVE_STATE_TXOK (2) /* Data can be transmitted (Slave Transmitter mode) */
/* Interrupt status, set and read, and clear registers */
#define I2C_INT_MSTPENDING (1 << 0) /* Bit 0 Master Pending interrupt */
#define I2C_STAT_MSTSTATE_SHIFT (1) /* Bits 1-3: Master State code (status only) */
#define I2C_STAT_MSTSTATE_MASK (7 << I2C_STAT_MSTSTATE_SHIFT)
@ -345,7 +347,7 @@
#define I2C_INT_EVENTTIMEOUT (1 << 24) /* Bit 24: Event time-out interrupt */
#define I2C_INT_SCLTIMEOUT (1 << 25) /* Bit 25: SCL time-out interrupt */
#define I2C_INT_MSTPENDING (1 << 0) /* Bit 0 Master Pending interrupt */
#define I2C_INT_MSTPENDING (1 << 0) /* Bit 0 Master Pending interrupt */
#define I2C_INT_MSTARBLOSS (1 << 4) /* Bit 4: Master Arbitration Loss interrupt */
#define I2C_INT_MSTSTSTPERR (1 << 6) /* Bit 6: Master Start/Stop Error interrupt */
#define I2C_INT_SLVPENDING (1 << 8) /* Bit 8: Slave Pending interrupt */
@ -360,7 +362,11 @@
#define I2C_INT_ALL 0x030b8951
/* Time-out value */
#define I2C_TIMEOUT_
#define I2C_TIMEOUT_SHIFT (0) /* Bits 0-15: Time out value
* Bits 0-3 hardwired to 0xff */
#define I2C_TIMEOUT_MASK (0xffff << I2C_TIMEOUT_SHIFT)
# define I2C_TIMEOUT(n) ((uint32_t)((n)-1) << I2C_TIMEOUT_SHIFT)
/* Clock pre-divider for the entire I2C interface */
@ -368,9 +374,6 @@
#define I2C_CLKDIV_MASK (0xffff << I2C_CLKDIV_SHIFT)
# define I2C_CLKDIV(n) ((uint32_t)((n)-1) << I2C_CLKDIV_SHIFT)
/* Interrupt status register for shared functions */
#define I2C_INTSTAT_
/* Master control */
#define I2C_MSTCTL_MSTCONTINUE (1 << 0) /* Bit 0: Master Continue */
@ -388,7 +391,11 @@
# define I2C_MSTTIME_SCLHIGH(n) ((uint32_t)((n)-2) << I2C_MSTTIME_SCLHIGH_SHIFT)
/* Combined Master receiver and transmitter data */
#define I2C_MSTDAT_
#define I2C_MSTDAT_SHIFT (0) /* Bits 0-7: Master function data */
#define I2C_MSTDAT_MASK (0xff << I2C_MSTDAT_SHIFT)
# define I2C_MSTDAT(n) ((uint32_t)(n) << I2C_MSTDAT_SHIFT)
/* Slave control */
#define I2C_SLVCTL_
/* Combined Slave receiver and transmitter data */

View File

@ -184,11 +184,11 @@
#undef HAVE_I2C_MASTER_DEVICE
#if defined(CONFIG_LPC54_I2C0_MASTER) || defined(CONFIG_LPC54_I2C1_MASTER) || \
defined(CONFIG_LPC54_I2C1_MASTER) || defined(CONFIG_LPC54_I2C3_MASTER) || \
defined(CONFIG_LPC54_I2C_MASTER4) || defined(CONFIG_LPC54_I2C5_MASTER) || \
defined(CONFIG_LPC54_I2C2_MASTER) || defined(CONFIG_LPC54_I2C3_MASTER) || \
defined(CONFIG_LPC54_I2C4_MASTER) || defined(CONFIG_LPC54_I2C5_MASTER) || \
defined(CONFIG_LPC54_I2C6_MASTER) || defined(CONFIG_LPC54_I2C7_MASTER) || \
defined(CONFIG_LPC54_I2C8_MASTER) || defined(CONFIG_LPC54_I2C9_MASTER)
# define HAVE_MASTER_I2C_MASTER_DEVICE 1
# define HAVE_I2C_MASTER_DEVICE 1
#endif
/* Check if we have an SPI device */

View File

@ -4,6 +4,12 @@
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Parts of this file were adapted from sample code provided for the LPC54xx
* family from NXP which has a compatible BSD license.
*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@ -49,6 +55,7 @@
#include <nuttx/arch.h>
#include <nuttx/wdog.h>
#include <nuttx/clock.h>
#include <nuttx/semaphore.h>
#include <nuttx/i2c/i2c_master.h>
@ -64,21 +71,54 @@
#include "chip/lpc54_flexcomm.h"
#include "chip/lpc54_i2c.h"
#include "lpc54_config.h"
#include "lpc54_clockconfig.h"
#include "lpc54_enableclk.h"
#include "lpc54_gpio.h"
#include "lpc54_i2c_master.h"
#include <arch/board/board.h>
#ifdef HAVE_SPI_MASTER_DEVICE
#ifdef HAVE_I2C_MASTER_DEVICE
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* 20 Millisecond timeout in system clock ticks. */
#define I2C_WDOG_TIMEOUT MSEC2TICK(20)
/* Default I2C frequency */
#if defined(CONFIG_LPC54_I2C_FAST) || defined(CONFIG_LPC54_I2C_HIGH)
# define I2C_DEFAULT_FREQUENCY 1000000
#else
# define I2C_DEFAULT_FREQUENCY 400000
#endif
/* I2C Master Interrupts */
#define I2C_MASTER_INTS \
(I2C_INT_MSTPENDING | I2C_INT_MSTARBLOSS | I2C_INT_MSTSTSTPERR)
/****************************************************************************
* Private Data
* Private Types
****************************************************************************/
/* I2C state */
enum lpc54_i2cstate_e
{
I2CSTATE_IDLE = 0,
I2CSTATE_TRANSMIT,
I2CSTATE_RECEIVE,
I2CSTATE_START,
I2CSTATE_STOP,
I2CSTATE_WAITDONE
};
/* This structure provides the overall state of the I2C driver */
struct lpc54_i2cdev_s
{
struct i2c_master_s dev; /* Generic I2C device */
@ -89,13 +129,15 @@ struct lpc54_i2cdev_s
uint32_t fclock; /* Flexcomm function clock frequency */
struct i2c_msg_s *msgs; /* Remaining transfers (first is in progress) */
unsigned int nmsg; /* Number of transfer remaining */
int16_t nmsgs; /* Number of transfer remaining */
int16_t result; /* The result of the transfer */
sem_t exclsem; /* Only one thread can access at a time */
#ifndef CONFIG_I2C_POLLED
sem_t waitsem; /* Supports wait for state machine completion */
uint16_t irq; /* Flexcomm IRQ number */
uint16_t wrcnt; /* Number of bytes sent to tx fifo */
uint16_t rdcnt; /* Number of bytes read from rx fifo */
#endif
uint16_t xfrd; /* Number of bytes transferred */
volatile uint8_t state; /* State of state machine */
};
@ -103,16 +145,26 @@ struct lpc54_i2cdev_s
* Private Functions
****************************************************************************/
static int lpc54_i2c_start(struct lpc54_i2cdev_s *priv);
static void lpc54_i2c_stop(struct lpc54_i2cdev_s *priv);
static int lpc54_i2c_interrupt(int irq, FAR void *context, FAR void *arg);
static void lpc54_i2c_timeout(int argc, uint32_t arg, ...);
static inline void lpc54_i2c_putreg(struct lpc54_i2cdev_s *priv,
unsigned int regoffset, uint32_t regval);
static inline uint32_t lpc54_i2c_getreg(struct lpc54_i2cdev_s *priv,
unsigned int regoffset);
static void lpc54_i2c_setfrequency(struct lpc54_i2cdev_s *priv,
uint32_t frequency);
static void lpc54_i2c_timeout(int argc, uint32_t arg, ...);
static void lpc54_i2c_xfrsetup(struct lpc54_i2cdev_s *priv);
static bool lpc54_i2c_nextmsg(struct lpc54_i2cdev_s *priv);
static bool lpc54_i2c_statemachine(struct lpc54_i2cdev_s *priv);
#ifndef CONFIG_I2C_POLLED
static int lpc54_i2c_interrupt(int irq, FAR void *context, FAR void *arg);
#else
static int lpc54_i2c_poll(struct lpc54_i2cdev_s *priv);
#endif
static int lpc54_i2c_transfer(FAR struct i2c_master_s *dev,
FAR struct i2c_msg_s *msgs, int count);
#ifdef CONFIG_I2C_RESET
static int lpc54_i2c_reset(FAR struct i2c_master_s * dev);
static int lpc54_i2c_reset(FAR struct i2c_master_s * dev);
#endif
/****************************************************************************
@ -173,7 +225,7 @@ static struct lpc54_i2cdev_s g_i2c9_dev;
static inline void lpc54_i2c_putreg(struct lpc54_i2cdev_s *priv,
unsigned int regoffset, uint32_t regval)
{
putreg32(value, priv->base + regoffset);
putreg32(regval, priv->base + regoffset);
}
/****************************************************************************
@ -184,39 +236,12 @@ static inline void lpc54_i2c_putreg(struct lpc54_i2cdev_s *priv,
*
****************************************************************************/
static inline void lpc54_i2c_getreg(struct lpc54_i2cdev_s *priv,
unsigned int regoffset)
static inline uint32_t lpc54_i2c_getreg(struct lpc54_i2cdev_s *priv,
unsigned int regoffset)
{
return getreg32(priv->base + regoffset);
}
/****************************************************************************
* Name: lpc54_wait_pendingstatus
*
* Description:
* Wait for status update to complete and clear the I2C state.
*
****************************************************************************/
static uint32_t lpc54_wait_pendingstatus(struct lpc54_i2cdev_s *priv)
{
uint32_t regval;
/* Wait until status is no longer pending */
do
{
regval = lpc54_i2c_getreg(priv, LPC54_I2C_STAT_OFFSET);
}
while ((regval & I2C_INT_MSTPENDING) == 0);
/* Clear controller state and return the last status */
lpc43_i2c_putreg(priv, LPC54_I2C_STAT_OFFSET,
(I2C_STAT_MSTARBLOSS_MASK | I2C_STAT_MSTSTSTPERR_MASK));
return regval;
}
/****************************************************************************
* Name: lpc54_i2c_setfrequency
*
@ -291,59 +316,12 @@ static void lpc54_i2c_setfrequency(struct lpc54_i2cdev_s *priv,
lpc54_i2c_putreg(priv, LPC54_I2C_CLKDIV_OFFSET, regval);
regval = I2C_MSTTIME_SCLLOW(best_scl) | I2C_MSTTIME_SCLHIGH(best_scl);
lpc54_i2c_putreg(LPC54_I2C_MSTTIME_OFFSET, regval);
lpc54_i2c_putreg(priv, LPC54_I2C_MSTTIME_OFFSET, regval);
priv->frequency = frequency;
}
}
/****************************************************************************
* Name: lpc54_i2c_start
*
* Description:
* Perform a I2C transfer start
*
****************************************************************************/
static int lpc54_i2c_start(struct lpc54_i2cdev_s *priv)
{
struct i2c_msg_s *msg = priv->msgs;
uint32_t regval;
/* Write the address with the R/W bit */
if ((I2C_M_READ & msg->flags) == I2C_M_READ)
{
regval = I2C_READADDR8(msg->addr);
}
else
{
regval = I2C_WRITEADDR8(msg->addr);
}
lpc54_i2c_putreg(priv, LPC54_I2C_MSTDAT_OFFSET, regval);
/* Initiate the Start */
lpc54_i2c_putreg(priv, LPC54_I2C_MSTCTL_OFFSET, I2C_MSTCTL_MSTSTART);
return priv->nmsg;
}
/****************************************************************************
* Name: lpc54_i2c_stop
*
* Description:
* Perform a I2C transfer stop
*
****************************************************************************/
static void lpc54_i2c_stop(struct lpc54_i2cdev_s *priv)
{
(void)lpc54_wait_pendingstatus(priv);
lpc54_i2c_putreg(priv, LPC54_I2C_MSTCTL_OFFSET, I2C_MSTCTL_MSTSTOP);
nxsem_post(&priv->waitsem);
}
/****************************************************************************
* Name: lpc54_i2c_timeout
*
@ -356,32 +334,141 @@ static void lpc54_i2c_timeout(int argc, uint32_t arg, ...)
{
struct lpc54_i2cdev_s *priv = (struct lpc54_i2cdev_s *)arg;
#ifndef CONFIG_I2C_POLLED
irqstate_t flags = enter_critical_section();
priv->state = 0xff;
#endif
/* 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;
#ifndef CONFIG_I2C_POLLED
/* Wake up any waiters */
nxsem_post(&priv->waitsem);
leave_critical_section(flags);
#endif
}
/****************************************************************************
* Name: lpc32_i2c_nextmsg
* Name: lpc54_i2c_xfrsetup
*
* Description:
* Setup for the next message.
* Setup to initiate a transfer.
*
****************************************************************************/
void lpc32_i2c_nextmsg(struct lpc54_i2cdev_s *priv)
static void lpc54_i2c_xfrsetup(struct lpc54_i2cdev_s *priv)
{
priv->nmsg--;
struct i2c_msg_s *msg;
if (priv->nmsg > 0)
DEBUGASSERT(priv != NULL && priv->msgs != NULL);
msg = priv->msgs;
/* Disable I2C interrupts while configuring for the transfer */
lpc54_i2c_putreg(priv, LPC54_I2C_INTENCLR_OFFSET, I2C_MASTER_INTS);
/* Set up for the transfer */
priv->xfrd = 0;
/* Select the initial state */
if ((msg->flags & I2C_M_NORESTART) != 0)
{
priv->msgs++;
#warning Missing logic
/* Start condition will be ommited. Begin the tranfer in the data
* phase.
*/
if (msg->length == 0)
{
priv->state = I2CSTATE_STOP;
}
else if ((I2C_M_READ & msg->flags) == I2C_M_READ)
{
priv->state = I2CSTATE_RECEIVE;
}
else
{
priv->state = I2CSTATE_TRANSMIT;
}
}
else
{
lpc54_i2c_stop(priv);
priv->state = I2CSTATE_START;
}
/* Set the I2C frequency if provided in this message. Otherwise, use the
* current I2C frequency setting.
*/
if (msg->frequency > 0)
{
(void)lpc54_i2c_setfrequency(priv, msg->frequency);
}
/* Clear error status bits */
lpc54_i2c_putreg(priv, LPC54_I2C_STAT_OFFSET, I2C_INT_MSTARBLOSS |
I2C_INT_MSTSTSTPERR);
#ifndef CONFIG_I2C_POLLED
/* Enable I2C master interrupts */
lpc54_i2c_putreg(priv, LPC54_I2C_INTENSET_OFFSET, I2C_MASTER_INTS);
#endif
}
/****************************************************************************
* Name: lpc54_i2c_nextmsg
*
* Description:
* Called at the completion of each message. If there are more messages,
* this function will perform the setup for the next message.
*
****************************************************************************/
static bool lpc54_i2c_nextmsg(struct lpc54_i2cdev_s *priv)
{
irqstate_t flags;
/* Disable interrupts to prevent the timeout while we make the decision
* here.
*/
flags = enter_critical_section();
/* Decrement the number of messages remaining. */
if (--priv->nmsgs > 0)
{
/* There are more messages, set up for the next message */
priv->msgs++;
lpc54_i2c_xfrsetup(priv);
leave_critical_section(flags);
return false;
}
else
{
/* That was the last message... we are done. */
/* Cancel any timeout */
wd_cancel(priv->timeout);
/* Disable further I2C interrupts and return to the IDLE state */
lpc54_i2c_putreg(priv, LPC54_I2C_INTENCLR_OFFSET, I2C_MASTER_INTS);
priv->state = I2CSTATE_IDLE;
leave_critical_section(flags);
return true;
}
}
@ -395,9 +482,190 @@ void lpc32_i2c_nextmsg(struct lpc54_i2cdev_s *priv)
*
****************************************************************************/
static void lpc54_i2c_statemachine(struct lpc54_i2cdev_s *priv)
static bool lpc54_i2c_statemachine(struct lpc54_i2cdev_s *priv)
{
#warning Missing logic
struct i2c_msg_s *msg;
uint32_t status;
uint32_t mstate;
DEBUGASSERT(priv != NULL && priv->msgs != NULL);
msg = priv->msgs;
status = lpc54_i2c_getreg(priv, LPC54_I2C_STAT_OFFSET);
if (status & I2C_INT_MSTARBLOSS)
{
lpc54_i2c_putreg(priv, LPC54_I2C_STAT_OFFSET, I2C_INT_MSTARBLOSS);
priv->result = -EIO;
return true;
}
if (status & I2C_INT_MSTSTSTPERR)
{
lpc54_i2c_putreg(priv, LPC54_I2C_STAT_OFFSET, I2C_INT_MSTSTSTPERR);
priv->result = -EIO;
return true;
}
if ((status & I2C_INT_MSTPENDING) == 0)
{
priv->result = -EBUSY;
return true;
}
/* Get the state of the I2C module */
mstate = (status & I2C_STAT_MSTSTATE_MASK) >> I2C_STAT_MSTSTATE_SHIFT;
if ((mstate == I2C_MASTER_STATE_ADDRNAK) ||
(mstate == I2C_MASTER_STATE_DATANAK))
{
/* Slave NACKed last byte, issue stop and return error */
lpc54_i2c_putreg(priv, LPC54_I2C_MSTCTL_OFFSET, I2C_MSTCTL_MSTSTOP);
priv->result = -EPERM;
priv->state = I2CSTATE_WAITDONE;
return false;
}
switch (priv->state)
{
case I2CSTATE_START:
{
enum lpc54_i2cstate_e newstate;
if ((msg->flags & I2C_M_READ) == I2C_M_READ)
{
lpc54_i2c_putreg(priv, LPC54_I2C_MSTDAT_OFFSET,
I2C_READADDR8(msg->addr));
newstate = I2CSTATE_TRANSMIT;
}
else
{
lpc54_i2c_putreg(priv, LPC54_I2C_MSTDAT_OFFSET,
I2C_WRITEADDR8(msg->addr));
newstate = I2CSTATE_RECEIVE;
}
if (priv->xfrd >= msg->length)
{
/* No more data, setup for STOP */
newstate = I2CSTATE_STOP;
}
priv->state = newstate;
/* Send START condition */
lpc54_i2c_putreg(priv, LPC54_I2C_MSTCTL_OFFSET,
I2C_MSTCTL_MSTSTART);
}
break;
case I2CSTATE_TRANSMIT:
{
if (mstate != I2C_MASTER_STATE_TXOK)
{
priv->result = -EINVAL;
return true;
}
lpc54_i2c_putreg(priv, LPC54_I2C_MSTDAT_OFFSET,
msg->buffer[priv->xfrd]);
lpc54_i2c_putreg(priv, LPC54_I2C_MSTCTL_OFFSET,
I2C_MSTCTL_MSTCONTINUE);
priv->xfrd++;
if (priv->xfrd >= msg->length)
{
/* No more data, schedule stop condition */
priv->state = I2CSTATE_STOP;
}
}
break;
case I2CSTATE_RECEIVE:
{
if (mstate != I2C_MASTER_STATE_RXAVAIL)
{
priv->result = -EINVAL;
return true;
}
msg->buffer[priv->xfrd] =
lpc54_i2c_getreg(priv, LPC54_I2C_MSTDAT_OFFSET);
priv->xfrd++;
if (priv->xfrd < msg->length)
{
lpc54_i2c_putreg(priv, LPC54_I2C_MSTCTL_OFFSET,
I2C_MSTCTL_MSTCONTINUE);
}
else
{
/* No more data expected, issue NACK and STOP right away */
lpc54_i2c_putreg(priv, LPC54_I2C_MSTCTL_OFFSET,
I2C_MSTCTL_MSTSTOP);
priv->state = I2CSTATE_WAITDONE;
}
}
break;
case I2CSTATE_STOP:
{
bool dostop = true;
/* Is this the last message? */
if (priv->nmsgs > 1)
{
struct i2c_msg_s *nextmsg;
/* No.. Is there a start on the next message? If so, it
* should be preceded by a STOP.
*/
nextmsg = msg + 1;
dostop = ((nextmsg->flags & I2C_M_NORESTART) != 0);
}
if (dostop)
{
/* Stop condition is omitted, we are done. Start the next
* message (or return to the IDLE state if none).
*/
return lpc54_i2c_nextmsg(priv);
}
else
{
/* Send stop condition */
lpc54_i2c_putreg(priv, LPC54_I2C_MSTCTL_OFFSET,
I2C_MSTCTL_MSTSTOP);
priv->state = I2CSTATE_WAITDONE;
}
}
break;
case I2CSTATE_WAITDONE:
{
/* Start the next message (or return to the IDLE state if none). */
return lpc54_i2c_nextmsg(priv);
}
break;
case I2CSTATE_IDLE:
default:
priv->result = -EINVAL;
return true;
}
return false;
}
/****************************************************************************
@ -408,30 +676,31 @@ static void lpc54_i2c_statemachine(struct lpc54_i2cdev_s *priv)
*
****************************************************************************/
#ifndef CONFIG_I2C_POLLED
static int lpc54_i2c_interrupt(int irq, FAR void *context, FAR void *arg)
{
struct lpc54_i2cdev_s *priv = (struct lpc54_i2cdev_s *)arg;
struct i2c_msg_s *msg;
uint32_t state;
bool done;
DEBUGASSERT(priv != NULL);
state = lpc54_i2c_getreg(priv, LPC54_I2C_STAT_OFFSET);
msg = priv->msgs;
#warning Missing logic
/* Run the I2C state machine */
priv->state = state;
switch (state)
done = lpc54_i2c_statemachine(priv);
if (done)
{
#warning Missing logic
default:
lpc54_i2c_stop(priv);
break;
/* Disable further I2C interrupts. */
lpc54_i2c_putreg(priv, LPC54_I2C_INTENCLR_OFFSET, I2C_MASTER_INTS);
/* Wake up wake up any waiters */
nxsem_post(&priv->waitsem);
}
#warning Missing logic
return OK;
}
#endif /* CONFIG_I2C_POLLED */
/****************************************************************************
* Name: lpc54_i2c_transfer
@ -455,23 +724,33 @@ static int lpc54_i2c_transfer(FAR struct i2c_master_s *dev,
/* Set up for the transfer */
priv->wrcnt = 0;
priv->rdcnt = 0;
priv->xfrd = 0;
priv->msgs = msgs;
priv->nmsg = count;
priv->nmsgs = count;
/* Configure the I2C frequency.
* REVISIT: Note that the frequency is set only on the first message.
* This could be extended to support different transfer frequencies for
* each message segment.
*/
/* Set up the transfer timeout */
/* wd_start(priv->timeout ...); */
lpc54_i2c_setfrequency(priv, msgs->frequency);
wd_start(priv->timeout, I2C_WDOG_TIMEOUT, lpc54_i2c_timeout, 1,
(uint32_t)priv);
/* Perform the transfer */
/* Initiate the transfer */
ret = lpc54_i2c_start(priv);
lpc54_i2c_xfrsetup(priv);
/* Loop until the transfer is complete or until a timeout occurs */
do
{
#ifndef CONFIG_I2C_POLLED
nxsem_wait(&priv->waitsem);
#else
(void)lpc54_i2c_statemachine(priv);
#endif
}
while (priv->state != I2CSTATE_IDLE);
ret = priv->result;
nxsem_post(&priv->exclsem);
return ret;
}
@ -515,7 +794,6 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
struct lpc54_i2cdev_s *priv;
irqstate_t flags;
uint32_t regval;
uint32_t deffreq;
flags = enter_critical_section();
@ -542,8 +820,10 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
priv = &g_i2c0_dev;
priv->base = LPC54_FLEXCOMM0_BASE;
priv->irq = LPC54_IRQ_FLEXCOMM0;
priv->fclock = BOARD_FLEXCOMM0_FCLK;
#ifndef CONFIG_I2C_POLLED
priv->irq = LPC54_IRQ_FLEXCOMM0;
#endif
/* Configure I2C pins (defined in board.h) */
@ -553,10 +833,6 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
/* Set up the FLEXCOMM0 function clock */
putreg32(BOARD_FLEXCOMM0_CLKSEL, LPC54_SYSCON_FCLKSEL0);
/* Set the default I2C frequency */
deffreq = I2C0_DEFAULT_FREQUENCY;
}
else
#endif
@ -578,8 +854,10 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
priv = &g_i2c1_dev;
priv->base = LPC54_FLEXCOMM1_BASE;
priv->irq = LPC54_IRQ_FLEXCOMM1;
priv->fclock = BOARD_FLEXCOMM1_FCLK;
#ifndef CONFIG_I2C_POLLED
priv->irq = LPC54_IRQ_FLEXCOMM1;
#endif
/* Configure I2C pins (defined in board.h) */
@ -589,10 +867,6 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
/* Set up the FLEXCOMM1 function clock */
putreg32(BOARD_FLEXCOMM1_CLKSEL, LPC54_SYSCON_FCLKSEL1);
/* Set the default I2C frequency */
deffreq = I2C1_DEFAULT_FREQUENCY;
}
else
#endif
@ -614,8 +888,10 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
priv = &g_i2c2_dev;
priv->base = LPC54_FLEXCOMM2_BASE;
priv->irq = LPC54_IRQ_FLEXCOMM2;
priv->fclock = BOARD_FLEXCOMM2_FCLK;
#ifndef CONFIG_I2C_POLLED
priv->irq = LPC54_IRQ_FLEXCOMM2;
#endif
/* Configure I2C pins (defined in board.h) */
@ -625,10 +901,6 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
/* Set up the FLEXCOMM2 function clock */
putreg32(BOARD_FLEXCOMM2_CLKSEL, LPC54_SYSCON_FCLKSEL2);
/* Set the default I2C frequency */
deffreq = I2C2_DEFAULT_FREQUENCY;
}
else
#endif
@ -650,8 +922,10 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
priv = &g_i2c3_dev;
priv->base = LPC54_FLEXCOMM3_BASE;
priv->irq = LPC54_IRQ_FLEXCOMM3;
priv->fclock = BOARD_FLEXCOMM3_FCLK;
#ifndef CONFIG_I2C_POLLED
priv->irq = LPC54_IRQ_FLEXCOMM3;
#endif
/* Configure I2C pins (defined in board.h) */
@ -661,10 +935,6 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
/* Set up the FLEXCOMM3 function clock */
putreg32(BOARD_FLEXCOMM3_CLKSEL, LPC54_SYSCON_FCLKSEL3);
/* Set the default I2C frequency */
deffreq = I2C3_DEFAULT_FREQUENCY;
}
else
#endif
@ -686,8 +956,10 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
priv = &g_i2c4_dev;
priv->base = LPC54_FLEXCOMM4_BASE;
priv->irq = LPC54_IRQ_FLEXCOMM4;
priv->fclock = BOARD_FLEXCOMM4_FCLK;
#ifndef CONFIG_I2C_POLLED
priv->irq = LPC54_IRQ_FLEXCOMM4;
#endif
/* Configure I2C pins (defined in board.h) */
@ -697,10 +969,6 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
/* Set up the FLEXCOMM4 function clock */
putreg32(BOARD_FLEXCOMM4_CLKSEL, LPC54_SYSCON_FCLKSEL4);
/* Set the default I2C frequency */
deffreq = I2C4_DEFAULT_FREQUENCY;
}
else
#endif
@ -722,8 +990,10 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
priv = &g_i2c5_dev;
priv->base = LPC54_FLEXCOMM5_BASE;
priv->irq = LPC54_IRQ_FLEXCOMM5;
priv->fclock = BOARD_FLEXCOMM5_FCLK;
#ifndef CONFIG_I2C_POLLED
priv->irq = LPC54_IRQ_FLEXCOMM5;
#endif
/* Configure I2C pins (defined in board.h) */
@ -733,10 +1003,6 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
/* Set up the FLEXCOMM5 function clock */
putreg32(BOARD_FLEXCOMM5_CLKSEL, LPC54_SYSCON_FCLKSEL5);
/* Set the default I2C frequency */
deffreq = I2C5_DEFAULT_FREQUENCY;
}
else
#endif
@ -758,8 +1024,10 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
priv = &g_i2c6_dev;
priv->base = LPC54_FLEXCOMM6_BASE;
priv->irq = LPC54_IRQ_FLEXCOMM6;
priv->fclock = BOARD_FLEXCOMM6_FCLK;
#ifndef CONFIG_I2C_POLLED
priv->irq = LPC54_IRQ_FLEXCOMM6;
#endif
/* Configure I2C pins (defined in board.h) */
@ -769,10 +1037,6 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
/* Set up the FLEXCOMM6 function clock */
putreg32(BOARD_FLEXCOMM6_CLKSEL, LPC54_SYSCON_FCLKSEL6);
/* Set the default I2C frequency */
deffreq = I2C6_DEFAULT_FREQUENCY;
}
else
#endif
@ -794,8 +1058,10 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
priv = &g_i2c7_dev;
priv->base = LPC54_FLEXCOMM7_BASE;
priv->irq = LPC54_IRQ_FLEXCOMM7;
priv->fclock = BOARD_FLEXCOMM7_FCLK;
#ifndef CONFIG_I2C_POLLED
priv->irq = LPC54_IRQ_FLEXCOMM7;
#endif
/* Configure I2C pins (defined in board.h) */
@ -805,10 +1071,6 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
/* Set up the FLEXCOMM7 function clock */
putreg32(BOARD_FLEXCOMM7_CLKSEL, LPC54_SYSCON_FCLKSEL7);
/* Set the default I2C frequency */
deffreq = I2C7_DEFAULT_FREQUENCY;
}
else
#endif
@ -830,8 +1092,10 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
priv = &g_i2c8_dev;
priv->base = LPC54_FLEXCOMM8_BASE;
priv->irq = LPC54_IRQ_FLEXCOMM8;
priv->fclock = BOARD_FLEXCOMM8_FCLK;
#ifndef CONFIG_I2C_POLLED
priv->irq = LPC54_IRQ_FLEXCOMM8;
#endif
/* Configure I2C pins (defined in board.h) */
@ -841,10 +1105,6 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
/* Set up the FLEXCOMM8 function clock */
putreg32(BOARD_FLEXCOMM8_CLKSEL, LPC54_SYSCON_FCLKSEL8);
/* Set the default I2C frequency */
deffreq = I2C8_DEFAULT_FREQUENCY;
}
else
#endif
@ -866,8 +1126,10 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
priv = &g_i2c9_dev;
priv->base = LPC54_FLEXCOMM9_BASE;
priv->irq = LPC54_IRQ_FLEXCOMM9;
priv->fclock = BOARD_FLEXCOMM9_FCLK;
#ifndef CONFIG_I2C_POLLED
priv->irq = LPC54_IRQ_FLEXCOMM9;
#endif
/* Configure I2C pins (defined in board.h) */
@ -877,10 +1139,6 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
/* Set up the FLEXCOMM9 function clock */
putreg32(BOARD_FLEXCOMM9_CLKSEL, LPC54_SYSCON_FCLKSEL9);
/* Set the default I2C frequency */
deffreq = I2C9_DEFAULT_FREQUENCY;
}
else
#endif
@ -899,15 +1157,16 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
regval = lpc54_i2c_getreg(priv, LPC54_I2C_CFG_OFFSET);
regval &= I2C_CFG_ALLENABLES;
regval |= I2C_CFG_MSTEN;
lpc54_i2c_putreg(priv, LPC54_I2C_CFG_OFFSET, regval)
lpc54_i2c_putreg(priv, LPC54_I2C_CFG_OFFSET, regval);
/* Set the default I2C frequency */
lpc54_i2c_setfrequency(priv, deffreq);
lpc54_i2c_setfrequency(priv, I2C_DEFAULT_FREQUENCY);
/* Initialize semaphores */
nxsem_init(&priv->exclsem, 0, 1);
#ifndef CONFIG_I2C_POLLED
nxsem_init(&priv->waitsem, 0, 0);
/* The waitsem semaphore is used for signaling and, hence, should not have
@ -915,23 +1174,28 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
*/
nxsem_setprotocol(&priv->waitsem, SEM_PRIO_NONE);
#endif
/* Allocate a watchdog timer */
priv->timeout = wd_create();
DEBUGASSERT(priv->timeout != 0);
#ifndef CONFIG_I2C_POLLED
/* Attach Interrupt Handler */
irq_attach(priv->irq, lpc54_i2c_interrupt, priv);
#endif
/* Disable interrupts at the I2C peripheral */
lpc54_i2c_putreg(priv, LPC54_I2C_INTENCLR_OFFSET, I2C_INT_ALL);
#ifndef CONFIG_I2C_POLLED
/* Enable interrupts at the NVIC */
up_enable_irq(priv->irq);
#endif
return &priv->dev;
}
@ -949,22 +1213,24 @@ int lpc54_i2cbus_uninitialize(FAR struct i2c_master_s * dev)
uint32_t regval;
/* Disable I2C interrupts */
#warning Missing logic
lpc54_i2c_putreg(priv, LPC54_I2C_INTENCLR_OFFSET, I2C_MASTER_INTS);
/* Disable the I2C peripheral */
regval = lpc54_i2c_getreg(priv, LPC54_I2C_CFG_OFFSET);
regval &= I2C_CFG_ALLENABLES;
regval &= ~I2C_CFG_MSTEN;
lpc54_i2c_putreg(priv, LPC54_I2C_CFG_OFFSET, regval)
#warning Missing logic
lpc54_i2c_putreg(priv, LPC54_I2C_CFG_OFFSET, regval);
#ifndef CONFIG_I2C_POLLED
/* Disable the Flexcomm interface at the NVIC and detach the interrupt. */
up_disable_irq(priv->irq);
irq_detach(priv->irq);
#endif
return OK;
}
#endif /* HAVE_SPI_MASTER_DEVICE */
#endif /* HAVE_I2C_MASTER_DEVICE */

View File

@ -46,6 +46,23 @@ STATUS
horizontal elongation.
2017-12-14: Corrected a misconception about how the video data lines
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?)
Configurations
==============
@ -118,7 +135,7 @@ Configurations
as NSH built-in applications.
NOTES:
1, This configuration enables SDRAM to hold the LCD framebuffer and
1. This configuration enables SDRAM to hold the LCD framebuffer and
enables the LPC54xx LCD driver in order to support the LPCXpresso's
TFT panel. In this configuration, the framebuffer resides in the
the lower half megabyte of SDRAM beginning at address 0xa0000000
@ -179,3 +196,20 @@ Configurations
RAMTest: Pattern test: a0000000 16777216 33333333 cccccccc
RAMTest: Address-in-address test: a0000000 16777216
nsh>
3. I2C2 is enabled (will be used with the capacitive touchscreen). In
order to verify I2C functionality, the I2C tool at apps/system/i2ctool
is enabled in this configuration.
nsh> i2c bus
BUS EXISTS?
Bus 0: NO
Bus 1: NO
Bus 2: YES
Bus 3: NO
Bus 4: NO
Bus 5: NO
Bus 6: NO
Bus 7: NO
Bus 8: NO
Bus 9: NO

View File

@ -173,11 +173,16 @@
# define BOARD_SYSTICK_CLOCK (BOARD_AHB_FREQUENCY / BOARD_SYSTICKCLKDIV)
#endif
/* Flexcomm0: REVIST */
/* Flexcomm0: USART0 (REVIST) */
#define BOARD_FLEXCOMM0_CLKSEL SYSCON_FCLKSEL_FRO12M
#define BOARD_FLEXCOMM0_FCLK LPC54_FRO_12MHZ
/* Flexcomm2: I2C2 (REVIST) */
#define BOARD_FLEXCOMM2_CLKSEL SYSCON_FCLKSEL_FRO12M
#define BOARD_FLEXCOMM2_FCLK LPC54_FRO_12MHZ
/* EMC */
#ifdef BOARD_220MHz
@ -273,6 +278,41 @@
#define GPIO_USART0_RXD (GPIO_FC0_RXD_SDA_MOSI_2 | GPIO_FILTER_OFF)
#define GPIO_USART0_TXD (GPIO_FC0_TXD_SCL_MISO_2 | GPIO_FILTER_OFF)
/* Flexomm2/I2C
*
* For I2C:
* Type A & D pins need:
* GPIO_OPENDRAIN + GPIO_FILTER_OFF
* Type I pins need for Standard mode I2C need:
* GPIO_FILTER_OFF + GPIO_I2C_FILTER_ON + GPIO_I2CDRIVE_LOW
* Type I pins need for fast speed I2C need:
* GPIO_FILTER_OFF + GPIO_I2C_FILTER_ON or OFF +
* GPIO_I2CDRIVE_LOW or HIGH
* Type I pins need for high speed I2C need:
* GPIO_FILTER_OFF + GPIO_I2C_FILTER_OFF + GPIO_I2CDRIVE_HIGH
*
* The touchscreen controller is on I2C2: SCL P3.24, SDA P3.23. These are
* both Type D/I pins.
*/
#if defined(CONFIG_LPC54_I2C_FAST)
# define _I2CFILTER GPIO_I2C_FILTER_OFF
# define _I2CDRIVE GPIO_I2CDRIVE_HIGH
#elif defined(CONFIG_LPC54_I2C_HIGH)
# define _I2CFILTER GPIO_I2C_FILTER_OFF
# define _I2CDRIVE GPIO_I2CDRIVE_HIGH
#else
# define _I2CFILTER GPIO_I2C_FILTER_ON
# define _I2CDRIVE GPIO_I2CDRIVE_LOW
#endif
#define GPIO_I2C2_SCL (GPIO_FC2_RTS_SCL_SSEL1_2 | \
GPIO_FILTER_OFF | _I2CFILTER | \
_I2CDRIVE)
#define GPIO_I2C2_SDA (GPIO_FC2_CTS_SDA_SSEL0_2 | \
GPIO_FILTER_OFF | _I2CFILTER | \
_I2CDRIVE)
/* LCD
*
* There are no alternatives for LCD pins except for the VD0-VD3 pins.

View File

@ -13,8 +13,11 @@ CONFIG_FAT_LCNAMES=y
CONFIG_FAT_LFN=y
CONFIG_FS_FAT=y
CONFIG_FS_PROCFS=y
CONFIG_I2C=y
CONFIG_I2CTOOL_MAXBUS=9
CONFIG_LPC54_EMC_DYNAMIC_CS0=y
CONFIG_LPC54_EMC=y
CONFIG_LPC54_I2C2_MASTER=y
CONFIG_LPC54_USART0=y
CONFIG_MAX_TASKS=16
CONFIG_MAX_WDOGPARMS=2
@ -38,6 +41,7 @@ CONFIG_SDCLONE_DISABLE=y
CONFIG_START_DAY=2
CONFIG_START_MONTH=12
CONFIG_SYMTAB_ORDEREDBYNAME=y
CONFIG_SYSTEM_I2CTOOL=y
CONFIG_SYSTEM_RAMTEST=y
CONFIG_TASK_NAME_SIZE=0
CONFIG_USART0_SERIAL_CONSOLE=y

View File

@ -44,9 +44,94 @@
#include <syslog.h>
#include <nuttx/video/fb.h>
#include <nuttx/i2c/i2c_master.h>
#include "lpc54_config.h"
#include "lpc54_i2c_master.h"
#include "lpcxpresso-lpc54628.h"
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: lpc54_i2c_register
*
* Description:
* Register one I2C drivers for the I2C tool.
*
****************************************************************************/
#ifdef HAVE_I2CTOOL
static void lpc54_i2c_register(int bus)
{
FAR struct i2c_master_s *i2c;
int ret;
i2c = lpc54_i2cbus_initialize(bus);
if (i2c == NULL)
{
syslog(LOG_ERR, "ERROR: Failed to get I2C%d interface\n", bus);
}
else
{
ret = i2c_register(i2c, bus);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to register I2C%d driver: %d\n",
bus, ret);
lpc54_i2cbus_uninitialize(i2c);
}
}
}
#endif
/****************************************************************************
* Name: lpc54_i2ctool
*
* Description:
* Register I2C drivers for the I2C tool.
*
****************************************************************************/
#ifdef HAVE_I2CTOOL
static void lpc54_i2ctool(void)
{
#ifdef CONFIG_LPC54_I2C0_MASTER
lpc54_i2c_register(0);
#endif
#ifdef CONFIG_LPC54_I2C1_MASTER
lpc54_i2c_register(1);
#endif
#ifdef CONFIG_LPC54_I2C2_MASTER
lpc54_i2c_register(2);
#endif
#ifdef CONFIG_LPC54_I2C3_MASTER
lpc54_i2c_register(3);
#endif
#ifdef CONFIG_LPC54_I2C4_MASTER
lpc54_i2c_register(4);
#endif
#ifdef CONFIG_LPC54_I2C5_MASTER
lpc54_i2c_register(5);
#endif
#ifdef CONFIG_LPC54_I2C6_MASTER
lpc54_i2c_register(6);
#endif
#ifdef CONFIG_LPC54_I2C7_MASTER
lpc54_i2c_register(7);
#endif
#ifdef CONFIG_LPC54_I2C8_MASTER
lpc54_i2c_register(8);
#endif
#ifdef CONFIG_LPC54_I2C9_MASTER
lpc54_i2c_register(9);
#endif
}
#else
# define lpc54_i2ctool()
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@ -79,6 +164,10 @@ int lpc54_bringup(void)
}
#endif
/* Register I2C drivers on behalf of the I2C tool */
lpc54_i2ctool();
#ifdef CONFIG_VIDEO_FB
/* Initialize and register the framebuffer driver */

View File

@ -43,10 +43,21 @@
#include <nuttx/config.h>
#include <nuttx/compiler.h>
#include "lpc54_config.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define HAVE_I2CTOOL 1
/* Do we need to register I2C drivers on behalf of the I2C tool? */
#if !defined(CONFIG_SYSTEM_I2CTOOL) || !defined(CONFIG_I2C_DRIVER) || \
!defined(HAVE_I2C_MASTER_DEVICE)
# undef HAVE_I2CTOOL
#endif
/* LED definitions **********************************************************/
/* The LPCXpress-LPC54628 has three user LEDs: D9, D11, and D12. These
* LEDs are for application use. They are illuminated when the driving