Tiva I2C: Driver is code complete but untested

This commit is contained in:
Gregory Nutt 2014-12-10 12:43:46 -06:00
parent 03e1ecd6aa
commit 58d0e169c7
2 changed files with 322 additions and 372 deletions

View File

@ -543,7 +543,7 @@
/* I2C Master Interrupt Mask (I2CM_IMR) */ /* I2C Master Interrupt Mask (I2CM_IMR) */
#define I2CM_IMR_IM (1 << 0) /* Bit 0: Interrupt Mask */ #define I2CM_IMR_MIM (1 << 0) /* Bit 0: Master Interrupt Mask */
#if defined(CONFIG_ARCH_CHIP_TM4C123GH6ZRB) || \ #if defined(CONFIG_ARCH_CHIP_TM4C123GH6ZRB) || \
defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT) defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT)
@ -565,68 +565,68 @@
/* I2C Master Raw Interrupt Status (I2CM_RIS) */ /* I2C Master Raw Interrupt Status (I2CM_RIS) */
#define I2CM_RIS_RIS (1 << 0) /* Bit 0: Raw Interrupt Status */ #define I2CM_RIS_MRIS (1 << 0) /* Bit 0: Master Raw Interrupt Status */
#if defined(CONFIG_ARCH_CHIP_TM4C123GH6ZRB) || \ #if defined(CONFIG_ARCH_CHIP_TM4C123GH6ZRB) || \
defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT) defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT)
# define I2CM_RIS_CLKRIS (1 << 1) /* Bit 1: Clock Timeout Raw Interrupt Status */ # define I2CM_RIS_CLKRIS (1 << 1) /* Bit 1: Clock Timeout Raw Interrupt Status */
#endif #endif
#if defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT) #if defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT)
# define I2CM_RIS_DMARXRIS (1 << 2) /* Bit 2: Receive DMA Interrupt Mask */ # define I2CM_RIS_DMARXRIS (1 << 2) /* Bit 2: Receive DMA Interrupt Status */
# define I2CM_RIS_DMATXRIS (1 << 3) /* Bit 3: Transmit DMA Interrupt Mask */ # define I2CM_RIS_DMATXRIS (1 << 3) /* Bit 3: Transmit DMA Interrupt Status */
# define I2CM_RIS_NACKRIS (1 << 4) /* Bit 4: Address/Data NACK Interrupt Mask */ # define I2CM_RIS_NACKRIS (1 << 4) /* Bit 4: Address/Data NACK Interrupt Status */
# define I2CM_RIS_STARTRIS (1 << 5) /* Bit 5: START Detection Interrupt Mask */ # define I2CM_RIS_STARTRIS (1 << 5) /* Bit 5: START Detection Interrupt Status */
# define I2CM_RIS_STOPRIS (1 << 6) /* Bit 6: STOP Detection Interrupt Mask */ # define I2CM_RIS_STOPRIS (1 << 6) /* Bit 6: STOP Detection Interrupt Status */
# define I2CM_RIS_ARBLOSTRIS (1 << 7) /* Bit 7: Arbitration Lost Interrupt Mask */ # define I2CM_RIS_ARBLOSTRIS (1 << 7) /* Bit 7: Arbitration Lost Interrupt Status */
# define I2CM_RIS_TXRIS (1 << 8) /* Bit 8: Transmit FIFO Request Interrupt Mask */ # define I2CM_RIS_TXRIS (1 << 8) /* Bit 8: Transmit FIFO Request Interrupt Status */
# define I2CM_RIS_RXRIS (1 << 9) /* Bit 9: Receive FIFO Request Interrupt Mask */ # define I2CM_RIS_RXRIS (1 << 9) /* Bit 9: Receive FIFO Request Interrupt Status */
# define I2CM_RIS_TXFERIS (1 << 10) /* Bit 10: Transmit FIFO Empty Interrupt Mask */ # define I2CM_RIS_TXFERIS (1 << 10) /* Bit 10: Transmit FIFO Empty Interrupt Status */
# define I2CM_RIS_RXFFRIS (1 << 11) /* Bit 11: Receive FIFO Full Interrupt Mask */ # define I2CM_RIS_RXFFRIS (1 << 11) /* Bit 11: Receive FIFO Full Interrupt Status */
#endif #endif
/* I2C Master Masked Interrupt Status (I2CM_MIS) */ /* I2C Master Masked Interrupt Status (I2CM_MIS) */
#define I2CM_MIS_MIS (1 << 0) /* Bit 0: Masked Interrupt Status */ #define I2CM_MIS_MMIS (1 << 0) /* Bit 0: Maseter Masked Interrupt Status */
#if defined(CONFIG_ARCH_CHIP_TM4C123GH6ZRB) || \ #if defined(CONFIG_ARCH_CHIP_TM4C123GH6ZRB) || \
defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT) defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT)
# define I2CM_MIS_CLKMIS (1 << 1) /* Bit 1: Clock Timeout Masked Interrupt Status */ # define I2CM_MIS_CLKMIS (1 << 1) /* Bit 1: Clock Timeout Masked Interrupt Status */
#endif #endif
#if defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT) #if defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT)
# define I2CM_MIS_DMARXMIS (1 << 2) /* Bit 2: Receive DMA Interrupt Mask */ # define I2CM_MIS_DMARXMIS (1 << 2) /* Bit 2: Receive DMA Interrupt Status */
# define I2CM_MIS_DMATXMIS (1 << 3) /* Bit 3: Transmit DMA Interrupt Mask */ # define I2CM_MIS_DMATXMIS (1 << 3) /* Bit 3: Transmit DMA Interrupt Status */
# define I2CM_MIS_NACKMIS (1 << 4) /* Bit 4: Address/Data NACK Interrupt Mask */ # define I2CM_MIS_NACKMIS (1 << 4) /* Bit 4: Address/Data NACK Interrupt Status */
# define I2CM_MIS_STARTMIS (1 << 5) /* Bit 5: START Detection Interrupt Mask */ # define I2CM_MIS_STARTMIS (1 << 5) /* Bit 5: START Detection Interrupt Status */
# define I2CM_MIS_STOPMIS (1 << 6) /* Bit 6: STOP Detection Interrupt Mask */ # define I2CM_MIS_STOPMIS (1 << 6) /* Bit 6: STOP Detection Interrupt Status */
# define I2CM_MIS_ARBLOSTMIS (1 << 7) /* Bit 7: Arbitration Lost Interrupt Mask */ # define I2CM_MIS_ARBLOSTMIS (1 << 7) /* Bit 7: Arbitration Lost Interrupt Status */
# define I2CM_MIS_TXMIS (1 << 8) /* Bit 8: Transmit FIFO Request Interrupt Mask */ # define I2CM_MIS_TXMIS (1 << 8) /* Bit 8: Transmit FIFO Request Interrupt Status */
# define I2CM_MIS_RXMIS (1 << 9) /* Bit 9: Receive FIFO Request Interrupt Mask */ # define I2CM_MIS_RXMIS (1 << 9) /* Bit 9: Receive FIFO Request Interrupt Status */
# define I2CM_MIS_TXFEMIS (1 << 10) /* Bit 10: Transmit FIFO Empty Interrupt Mask */ # define I2CM_MIS_TXFEMIS (1 << 10) /* Bit 10: Transmit FIFO Empty Interrupt Status */
# define I2CM_MIS_RXFFMIS (1 << 11) /* Bit 11: Receive FIFO Full Interrupt Mask */ # define I2CM_MIS_RXFFMIS (1 << 11) /* Bit 11: Receive FIFO Full Interrupt Status */
#endif #endif
/* I2C Master Masked Interrupt Status (I2CM_ICR) */ /* I2C Master Masked Interrupt Status (I2CM_ICR) */
#define I2CM_ICR_IC (1 << 0) /* Bit 0: Masked Interrupt Status */ #define I2CM_ICR_MIC (1 << 0) /* Bit 0: Master Masked Interrupt Clear */
#if defined(CONFIG_ARCH_CHIP_TM4C123GH6ZRB) || \ #if defined(CONFIG_ARCH_CHIP_TM4C123GH6ZRB) || \
defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT) defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT)
# define I2CM_ICR_CLKIC (1 << 1) /* Bit 1: Clock Timeout Interrupt Clear */ # define I2CM_ICR_CLKC (1 << 1) /* Bit 1: Clock Timeout Interrupt Clear */
#endif #endif
#if defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT) #if defined(CONFIG_ARCH_CHIP_TM4C1294NCPDT)
# define I2CM_ICR_DMARXIC (1 << 2) /* Bit 2: Receive DMA Interrupt Mask */ # define I2CM_ICR_DMARXIC (1 << 2) /* Bit 2: Receive DMA Interrupt Clear */
# define I2CM_ICR_DMATXIC (1 << 3) /* Bit 3: Transmit DMA Interrupt Mask */ # define I2CM_ICR_DMATXIC (1 << 3) /* Bit 3: Transmit DMA Interrupt Clear */
# define I2CM_ICR_NACKIC (1 << 4) /* Bit 4: Address/Data NACK Interrupt Mask */ # define I2CM_ICR_NACKIC (1 << 4) /* Bit 4: Address/Data NACK Interrupt Clear */
# define I2CM_ICR_STARTIC (1 << 5) /* Bit 5: START Detection Interrupt Mask */ # define I2CM_ICR_STARTIC (1 << 5) /* Bit 5: START Detection Interrupt Clear */
# define I2CM_ICR_STOPIC (1 << 6) /* Bit 6: STOP Detection Interrupt Mask */ # define I2CM_ICR_STOPIC (1 << 6) /* Bit 6: STOP Detection Interrupt Clear */
# define I2CM_ICR_ARBLOSTIC (1 << 7) /* Bit 7: Arbitration Lost Interrupt Mask */ # define I2CM_ICR_ARBLOSTIC (1 << 7) /* Bit 7: Arbitration Lost Interrupt Clear */
# define I2CM_ICR_TXIC (1 << 8) /* Bit 8: Transmit FIFO Request Interrupt Mask */ # define I2CM_ICR_TXIC (1 << 8) /* Bit 8: Transmit FIFO Request Interrupt Clear */
# define I2CM_ICR_RXIC (1 << 9) /* Bit 9: Receive FIFO Request Interrupt Mask */ # define I2CM_ICR_RXIC (1 << 9) /* Bit 9: Receive FIFO Request Interrupt Clear */
# define I2CM_ICR_TXFEIC (1 << 10) /* Bit 10: Transmit FIFO Empty Interrupt Mask */ # define I2CM_ICR_TXFEIC (1 << 10) /* Bit 10: Transmit FIFO Empty Interrupt Mask */
# define I2CM_ICR_RXFFIC (1 << 11) /* Bit 11: Receive FIFO Full Interrupt Mask */ # define I2CM_ICR_RXFFIC (1 << 11) /* Bit 11: Receive FIFO Full Interrupt Clear */
#endif #endif
/* I2C Master Configuration (I2CM_CR) */ /* I2C Master Configuration (I2CM_CR) */

View File

@ -4,7 +4,8 @@
* Copyright (C) 2014 Gregory Nutt. All rights reserved. * Copyright (C) 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org> * Author: Gregory Nutt <gnutt@nuttx.org>
* *
* Derives in spirit if nothing more from the NuttX STM32 I2C driver which has: * The basic structure of this driver derives in spirit (if nothing more) from the
* NuttX STM32 I2C driver which has:
* *
* Copyright (C) 2011 Uros Platise. All rights reserved. * Copyright (C) 2011 Uros Platise. All rights reserved.
* Author: Uros Platise <uros.platise@isotel.eu> * Author: Uros Platise <uros.platise@isotel.eu>
@ -147,8 +148,9 @@
enum tiva_intstate_e enum tiva_intstate_e
{ {
INTSTATE_IDLE = 0, /* No I2C activity */ INTSTATE_IDLE = 0, /* No I2C activity */
INTSTATE_WAITING, /* Waiting for completion of interrupt activity */ INTSTATE_ADDRESS, /* Address sent, waiting for completion */
INTSTATE_DONE, /* Interrupt activity complete */ INTSTATE_XFRWAIT, /* Waiting for data transfer to complete */
INTSTATE_DONE /* Interrupt activity complete */
}; };
/* Trace events */ /* Trace events */
@ -156,16 +158,15 @@ enum tiva_intstate_e
enum tiva_trace_e enum tiva_trace_e
{ {
I2CEVENT_NONE = 0, /* No events have occurred with this status */ I2CEVENT_NONE = 0, /* No events have occurred with this status */
I2CEVENT_SENDADDR, /* Start/Master bit set and address sent, param = msgc */ I2CEVENT_SENDADDRESS, /* Address sent, param = address */
I2CEVENT_ERROR, /* Error occurred, param = MCS */
I2CEVENT_BUSY, /* Still busy, param = MCS */
I2CEVENT_XFRDONE, /* Transfer completed without error, param = dcnt */
I2CEVENT_RECVSETUP, /* Setup to receive the next byte, param = dcnt */
I2CEVENT_SENDBYTE, /* Send byte, param = dcnt */ I2CEVENT_SENDBYTE, /* Send byte, param = dcnt */
I2CEVENT_ITBUFEN, /* Enable buffer interrupts, param = 0 */ I2CEVENT_SPURIOUS, /* Spurious interrupt received, param = msgc */
I2CEVENT_RCVBYTE, /* Read more dta, param = dcnt */ I2CEVENT_NEXTMSG, /* Starting next message, param = msgc */
I2CEVENT_REITBUFEN, /* Re-enable buffer interrupts, param = 0 */ I2CEVENT_DONE /* All messages transferred, param = intstate */
I2CEVENT_DISITBUFEN, /* Disable buffer interrupts, param = 0 */
I2CEVENT_BTFNOSTART, /* BTF on last byte with no restart, param = msgc */
I2CEVENT_BTFRESTART, /* Last byte sent, re-starting, param = msgc */
I2CEVENT_BTFSTOP, /* Last byte sten, send stop, param = 0 */
I2CEVENT_ERROR /* Error occurred, param = 0 */
}; };
/* Trace data */ /* Trace data */
@ -213,6 +214,7 @@ struct tiva_i2c_priv_s
uint8_t *ptr; /* Current message buffer */ uint8_t *ptr; /* Current message buffer */
int dcnt; /* Current message length */ int dcnt; /* Current message length */
uint16_t flags; /* Current message flags */ uint16_t flags; /* Current message flags */
uint32_t status; /* MCS register at the end of the transfer */
/* I2C trace support */ /* I2C trace support */
@ -234,7 +236,7 @@ struct tiva_i2c_inst_s
struct tiva_i2c_priv_s *priv; /* Common driver private data structure */ struct tiva_i2c_priv_s *priv; /* Common driver private data structure */
uint32_t frequency; /* Frequency used in this instantiation */ uint32_t frequency; /* Frequency used in this instantiation */
int address; /* Address used in this instantiation */ uint16_t address; /* Address used in this instantiation */
uint16_t flags; /* Flags used in this instantiation */ uint16_t flags; /* Flags used in this instantiation */
}; };
@ -256,7 +258,6 @@ static useconds_t tiva_i2c_tousecs(int msgc, struct i2c_msg_s *msgs);
#endif /* CONFIG_TIVA_I2C_DYNTIMEO */ #endif /* CONFIG_TIVA_I2C_DYNTIMEO */
static inline int tiva_i2c_sem_waitdone(struct tiva_i2c_priv_s *priv); static inline int tiva_i2c_sem_waitdone(struct tiva_i2c_priv_s *priv);
static inline void tiva_i2c_sem_waitstop(struct tiva_i2c_priv_s *priv);
static inline void tiva_i2c_sem_post(struct i2c_dev_s *dev); static inline void tiva_i2c_sem_post(struct i2c_dev_s *dev);
static inline void tiva_i2c_sem_init(struct i2c_dev_s *dev); static inline void tiva_i2c_sem_init(struct i2c_dev_s *dev);
static inline void tiva_i2c_sem_destroy(struct i2c_dev_s *dev); static inline void tiva_i2c_sem_destroy(struct i2c_dev_s *dev);
@ -269,10 +270,8 @@ static void tiva_i2c_traceevent(struct tiva_i2c_priv_s *priv,
static void tiva_i2c_tracedump(struct tiva_i2c_priv_s *priv); static void tiva_i2c_tracedump(struct tiva_i2c_priv_s *priv);
#endif /* CONFIG_I2C_TRACE */ #endif /* CONFIG_I2C_TRACE */
static inline void tiva_i2c_sendstart(struct tiva_i2c_priv_s *priv); static void tiva_i2c_sendaddress(struct tiva_i2c_priv_s *priv);
static inline void tiva_i2c_clrstart(struct tiva_i2c_priv_s *priv); static void tiva_i2c_nextxfr(struct tiva_i2c_priv_s *priv);
static inline void tiva_i2c_sendstop(struct tiva_i2c_priv_s *priv);
static int tiva_i2c_interrupt(struct tiva_i2c_priv_s * priv, uint32_t status); static int tiva_i2c_interrupt(struct tiva_i2c_priv_s * priv, uint32_t status);
#ifndef CONFIG_I2C_POLLED #ifndef CONFIG_I2C_POLLED
@ -565,24 +564,22 @@ static inline int tiva_i2c_sem_waitdone(struct tiva_i2c_priv_s *priv)
{ {
struct timespec abstime; struct timespec abstime;
irqstate_t flags; irqstate_t flags;
uint32_t regval;
int ret; int ret;
flags = irqsave(); flags = irqsave();
/* Enable the master interrupt. The I2C master module generates an interrupt when /* Enable the master interrupt. The I2C master module generates an interrupt when
* a transaction completes (either transmit or receive), when arbitration is lost, * a transaction completes (either transmit or receive), when arbitration is lost,
* or when an error occurs during a transaction. * or when an error occurs during a transaction.
*/ */
tiva_i2c_putreg(priv, TIVA_I2CM_IMR_OFFSET, I2CM_IMR_IM); tiva_i2c_putreg(priv, TIVA_I2CM_IMR_OFFSET, I2CM_IMR_MIM);
/* Signal the interrupt handler that we are waiting. NOTE: Interrupts /* Signal the interrupt handler that we are waiting. NOTE: Interrupts
* are currently disabled but will be temporarily re-enabled below when * are currently disabled but will be temporarily re-enabled below when
* sem_timedwait() sleeps. * sem_timedwait() sleeps.
*/ */
priv->intstate = INTSTATE_WAITING;
do do
{ {
/* Get the current time */ /* Get the current time */
@ -665,7 +662,6 @@ static inline int tiva_i2c_sem_waitdone(struct tiva_i2c_priv_s *priv)
* sem_timedwait() sleeps. * sem_timedwait() sleeps.
*/ */
priv->intstate = INTSTATE_WAITING;
start = clock_systimer(); start = clock_systimer();
do do
@ -700,60 +696,6 @@ static inline int tiva_i2c_sem_waitdone(struct tiva_i2c_priv_s *priv)
} }
#endif #endif
/************************************************************************************
* Name: tiva_i2c_sem_waitstop
*
* Description:
* Wait for a STOP to complete
*
************************************************************************************/
static inline void tiva_i2c_sem_waitstop(struct tiva_i2c_priv_s *priv)
{
uint32_t start;
uint32_t elapsed;
uint32_t timeout;
/* Select a timeout */
#ifdef CONFIG_TIVA_I2C_DYNTIMEO
timeout = USEC2TICK(CONFIG_TIVA_I2C_DYNTIMEO_STARTSTOP);
#else
timeout = CONFIG_TIVA_I2CTIMEOTICKS;
#endif
/* Wait as stop might still be in progress; but stop might also
* be set because of a timeout error: "The [STOP] bit is set and
* cleared by software, cleared by hardware when a Stop condition is
* detected, set by hardware when a timeout error is detected."
*/
start = clock_systimer();
do
{
/* Check for STOP condition */
#warning Missing logic
/* Check for timeout error */
#warning Missing logic
/* Calculate the elapsed time */
elapsed = clock_systimer() - start;
}
/* Loop until the stop is complete or a timeout occurs. */
while (elapsed < timeout);
/* If we get here then a timeout occurred with the STOP condition
* still pending.
*/
i2cvdbg("Timeout with CR1: %04x SR1: %04x\n", cr1, sr1);
}
/************************************************************************************ /************************************************************************************
* Name: tiva_i2c_sem_post * Name: tiva_i2c_sem_post
* *
@ -920,43 +862,115 @@ static void tiva_i2c_tracedump(struct tiva_i2c_priv_s *priv)
#endif /* CONFIG_I2C_TRACE */ #endif /* CONFIG_I2C_TRACE */
/************************************************************************************ /************************************************************************************
* Name: tiva_i2c_sendstart * Name: tiva_i2c_sendaddress
* *
* Description: * Description:
* Send the START conditions/force Master mode * Send the START conditions/force Master mode
* *
************************************************************************************/ ************************************************************************************/
static inline void tiva_i2c_sendstart(struct tiva_i2c_priv_s *priv) static void tiva_i2c_sendaddress(struct tiva_i2c_priv_s *priv)
{ {
/* Disable ACK on receive by default and generate START */ struct i2c_msg_s *msg;
#warning Missing logic uint32_t regval;
DEBUGASSERT(priv && priv->msgc > 0);
/* Check for new trace setup, post the SENADDRESS event */
tiva_i2c_tracenew(priv, 0);
/* Get run-time data for the next message */
msg = priv->msgv;
priv->ptr = msg->buffer;
priv->dcnt = msg->length;
priv->flags = msg->flags;
/* Set the Master Slave Address */
regval = (uint32_t)msg->addr << I2CM_SA_SA_SHIFT;
if ((msg->flags & I2C_M_READ) != 0)
{
regval |= I2CM_SA_RS;
}
tiva_i2c_putreg(priv, TIVA_I2CM_SA_OFFSET, regval);
/* Write the command to the control register */
regval = I2CM_CS_RUN;
if ((msg->flags & I2C_M_NORESTART) == 0)
{
regval |= I2CM_CS_START;
}
if (priv->dcnt < 1)
{
regval |= I2CM_CS_STOP;
}
tiva_i2c_putreg(priv, TIVA_I2CM_CS_OFFSET, regval);
tiva_i2c_traceevent(priv, I2CEVENT_SENDADDRESS, msg->addr);
priv->intstate = INTSTATE_ADDRESS;
} }
/************************************************************************************ /************************************************************************************
* Name: tiva_i2c_clrstart * Name: tiva_i2c_nextxfr
* *
* Description: * Description:
* Clear the STOP, START or PEC condition on certain error recovery steps. * Common Interrupt Service Routine
* *
************************************************************************************/ ************************************************************************************/
static inline void tiva_i2c_clrstart(struct tiva_i2c_priv_s *priv) static void tiva_i2c_nextxfr(struct tiva_i2c_priv_s *priv)
{ {
#warning Missing logic uint32_t cmd;
}
/************************************************************************************ /* Set up the basic command. The STOP bit should be set on the last transfer
* Name: tiva_i2c_sendstop * UNLESS this there is a repeated start.
* */
* Description:
* Send the STOP conditions
*
************************************************************************************/
static inline void tiva_i2c_sendstop(struct tiva_i2c_priv_s *priv) cmd = I2CM_CS_RUN;
{ if (priv->msgc < 2 && priv->dcnt < 2)
#warning Missing logic {
/* This is the last byte of the last message... add the STOP bit */
cmd |= I2CM_CS_STOP;
}
/* Set up to transfer the next byte. Are we sending or receiving? */
if ((priv->flags & I2C_M_READ) != 0)
{
/* We are receiving data. Write the command to the control register to
* receive the next byte.
*/
cmd |= I2CM_CS_ACK;
tiva_i2c_putreg(priv, TIVA_I2CM_CS_OFFSET, cmd);
tiva_i2c_traceevent(priv, I2CEVENT_RECVSETUP, priv->dcnt);
}
else
{
uint32_t dr;
/* We are sending data. Write the data to be sent to the DR register. */
dr = (uint32_t)*priv->ptr++;
tiva_i2c_putreg(priv, TIVA_I2CM_DR_OFFSET, dr << I2CM_DR_SHIFT);
/* Write the command to the control register to send the byte in the DR
* register.
*/
tiva_i2c_putreg(priv, TIVA_I2CM_CS_OFFSET, cmd);
tiva_i2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->dcnt);
}
priv->intstate = INTSTATE_XFRWAIT;
} }
/************************************************************************************ /************************************************************************************
@ -973,216 +987,199 @@ static int tiva_i2c_interrupt(struct tiva_i2c_priv_s *priv, uint32_t status)
tiva_i2c_tracenew(priv, status); tiva_i2c_tracenew(priv, status);
/* Was start bit sent */ /* Check for a master interrupt? The I2C master module generates an interrupt when
#warning Missing logic * a transaction completes (either transmit or receive), when arbitration is lost,
* or when an error occurs during a transaction.
{
tiva_i2c_traceevent(priv, I2CEVENT_SENDADDR, priv->msgc);
/* We check for msgc > 0 here as an unexpected interrupt with
* due to noise on the I2C cable can otherwise cause msgc to
* wrap causing memory overwrite
*/
if (priv->msgc > 0 && priv->msgv != NULL)
{
/* Get run-time data */
priv->ptr = priv->msgv->buffer;
priv->dcnt = priv->msgv->length;
priv->flags = priv->msgv->flags;
/* Send address byte and define addressing mode */
tiva_i2c_putreg(priv, TIVA_I2CM_SA_OFFSET,
(priv->msgv->addr << 1) | (priv->flags & I2C_M_READ));
/* Set ACK for receive mode */
#warning Missing logic
/* Increment to next pointer and decrement message count */
priv->msgv++;
priv->msgc--;
}
else
{
/* Clear ISR by writing to DR register */
#warning Missing logic
}
}
/* Was address sent, continue with either sending or reading data */
#warning Missing logic
else if ((priv->flags & I2C_M_READ) == 0 && 0 /* ? */ )
{
if (priv->dcnt > 0)
{
/* Send a byte */
#warning Missing logic
priv->dcnt--;
}
}
else if ((priv->flags & I2C_M_READ) != 0 && 0 /* ? */)
{
/* Enable in order to receive one or multiple bytes */
#warning Missing logic
}
/* More bytes to read */
#warning Missing logic
{
/* Read a byte, if dcnt goes < 0, then read dummy bytes to ack ISRs */
if (priv->dcnt > 0)
{
tiva_i2c_traceevent(priv, I2CEVENT_RCVBYTE, priv->dcnt);
/* No interrupts or context switches may occur in the following
* sequence. Otherwise, additional bytes may be sent by the
* device.
*/
#ifdef CONFIG_I2C_POLLED
irqstate_t state = irqsave();
#endif
/* Receive a byte */
#warning Missing logic
/* Disable acknowledge when last byte is to be received */
priv->dcnt--;
if (priv->dcnt == 1)
{
#warning Missing logic
}
#ifdef CONFIG_I2C_POLLED
irqrestore(state);
#endif
}
else
{
/* Throw away the unexpected byte */
#warning Missing logic
}
}
/* Do we have more bytes to send, enable/disable buffer interrupts
* (these ISRs could be replaced by DMAs)
*/ */
#ifndef CONFIG_I2C_POLLED if ((status & I2CM_RIS_MRIS) != 0)
if (priv->dcnt > 0)
{ {
tiva_i2c_traceevent(priv, I2CEVENT_REITBUFEN, 0); uint32_t mcs;
#warning Missing logic
}
else if (priv->dcnt == 0)
{
tiva_i2c_traceevent(priv, I2CEVENT_DISITBUFEN, 0);
#warning Missing logic
}
#endif
/* Was last byte received or sent? */ /* Clear the pending master interrupt */
if (priv->dcnt <= 0 && 0 /* ? */) tiva_i2c_putreg(priv, TIVA_I2CM_ICR_OFFSET, I2CM_ICR_MIC);
{ status &= ~I2CM_RIS_MRIS;
/* Acknowledge the pending interrupt */
#warning Missing logic
/* Do we need to terminate or restart after this byte? /* We need look at the Master Control/Status register to determine the cause
* If there are more messages to send, then we may: * of the master interrupt.
*
* - continue with repeated start
* - or just continue sending writeable part
* - or we close down by sending the stop bit
*/ */
if (priv->msgc > 0) mcs = tiva_i2c_getreg(priv, TIVA_I2CM_CS_OFFSET);
{
if (priv->msgv->flags & I2C_M_NORESTART)
{
tiva_i2c_traceevent(priv, I2CEVENT_BTFNOSTART, priv->msgc);
priv->ptr = priv->msgv->buffer;
priv->dcnt = priv->msgv->length;
priv->flags = priv->msgv->flags;
priv->msgv++;
priv->msgc--;
/* Restart this ISR! */ /* If the busy bit is set, then the other bits are not valid */
if ((mcs & I2CM_CS_BUSY) != 0)
{
tiva_i2c_traceevent(priv, I2CEVENT_BUSY, mcs);
}
/* Check for errors, in which case, stop the transfer and return. */
else if ((mcs & I2CM_CS_ERROR) != 0)
{
tiva_i2c_traceevent(priv, I2CEVENT_ERROR, mcs);
/* Disable further interrupts */
tiva_i2c_putreg(priv, TIVA_I2CM_IMR_OFFSET, 0);
#ifndef CONFIG_I2C_POLLED #ifndef CONFIG_I2C_POLLED
#warning Missing logic
#endif
}
else
{
tiva_i2c_traceevent(priv, I2CEVENT_BTFRESTART, priv->msgc);
tiva_i2c_sendstart(priv);
}
}
else if (priv->msgv)
{
tiva_i2c_traceevent(priv, I2CEVENT_BTFSTOP, 0);
tiva_i2c_sendstop(priv);
/* Is there a thread waiting for this event (there should be) */ /* Is there a thread waiting for this event (there should be) */
#ifndef CONFIG_I2C_POLLED if (priv->intstate != INTSTATE_IDLE &&
if (priv->intstate == INTSTATE_WAITING) priv->intstate != INTSTATE_DONE)
{ {
/* Yes.. inform the thread that the transfer is complete /* Yes.. inform the thread that the transfer is complete
* and wake it up. * and wake it up.
*/ */
sem_post(&priv->waitsem); sem_post(&priv->waitsem);
priv->status = mcs;
priv->intstate = INTSTATE_DONE; priv->intstate = INTSTATE_DONE;
} }
#else #else
priv->status = mcs;
priv->intstate = INTSTATE_DONE; priv->intstate = INTSTATE_DONE;
#endif #endif
/* Mark that we have stopped with this transaction */
priv->msgv = NULL;
} }
}
/* Check for errors, in which case, stop the transfer and return /* Otherwise, the last transfer must have completed successfully */
* Note that in master reception mode AF becomes set on last byte
* since ACK is not returned. We should ignore this error.
*/
#warning Missing logic
{ else
tiva_i2c_traceevent(priv, I2CEVENT_ERROR, 0); {
int dr;
/* Clear interrupt flags */ tiva_i2c_traceevent(priv, I2CEVENT_XFRDONE, priv->dcnt);
#warning Missing logic
/* Read from the DR register */
/* Is there a thread waiting for this event (there should be) */ dr = tiva_i2c_getreg(priv, TIVA_I2CM_DR_OFFSET);
/* We check for msgc > 0 here as an unexpected interrupt with
* due to noise on the I2C cable can otherwise cause msgc to
* wrap causing memory overwrite
*/
if (priv->msgc > 0 && priv->msgv != NULL)
{
/* Was this the completion of an address or of the data portion
* of the transfer?
*/
DEBUGASSERT(priv->dcnt > 0);
if (priv->intstate == INTSTATE_XFRWAIT)
{
/* Data transfer completed. Are we sending or receiving data? */
if ((priv->flags & I2C_M_READ) != 0)
{
/* We are receiving data. Copy the received data to
* the user buffer
*/
*priv->ptr++ = (uint8_t)dr;
}
/* Decrement the count of bytes remaining to be sent */
priv->dcnt--;
}
/* Was that the last byte of this message? */
if (priv->dcnt > 0)
{
/* Send the next byte */
tiva_i2c_nextxfr(priv);
}
else
{
/* Increment to next pointer and decrement message count */
priv->msgv++;
priv->msgc--;
/* Is there another message to be sent? */
if (priv->msgc > 0)
{
/* Do we need to terminate or restart after this byte?
* If there are more messages to send, then we may
* continue with or without the (repeated) start bit.
*/
tiva_i2c_traceevent(priv, I2CEVENT_NEXTMSG, priv->msgc);
if (priv->msgv->flags & I2C_M_NORESTART)
{
/* Just continue transferring data. In this case,
* no STOP was sent at the end of the last message
* and the there is no new address.
*
* REVISIT: In this case, the address or the
* direction of the transfer cannot be permitted to
* change
*/
tiva_i2c_nextxfr(priv);
}
else
{
/* Set the repeated start. No STOP was sent at the
* end of the previous message.
*/
tiva_i2c_sendaddress(priv);
}
}
else
{
/* No.. then we are finished */
tiva_i2c_traceevent(priv, I2CEVENT_DONE, priv->intstate);
/* Disable further interrupts */
tiva_i2c_putreg(priv, TIVA_I2CM_IMR_OFFSET, 0);
#ifndef CONFIG_I2C_POLLED #ifndef CONFIG_I2C_POLLED
if (priv->intstate == INTSTATE_WAITING) /* Is there a thread waiting for this event (there
{ * should be)
/* Yes.. inform the thread that the transfer is complete */
* and wake it up.
*/
sem_post(&priv->waitsem); if (priv->intstate != INTSTATE_IDLE &&
priv->intstate = INTSTATE_DONE; priv->intstate != INTSTATE_DONE)
} {
/* Yes.. inform the thread that the transfer is
* complete and wake it up.
*/
sem_post(&priv->waitsem);
priv->status = mcs;
priv->intstate = INTSTATE_DONE;
}
#else #else
priv->intstate = INTSTATE_DONE; priv->status = mcs;
priv->intstate = INTSTATE_DONE;
#endif #endif
}
}
}
/* There is no pending message? Must be a spurious interrupt */
else
{
tiva_i2c_traceevent(priv, I2CEVENT_SPURIOUS, priv->msgc);
}
}
} }
/* Make sure that all pending interrupts were handled */
DEBUGASSERT(status == 0);
return OK; return OK;
} }
@ -1465,8 +1462,8 @@ static uint32_t tiva_i2c_setclock(struct tiva_i2c_priv_s *priv, uint32_t frequen
regval = tiva_i2c_putreg(priv, TIVA_I2CSC_PP_OFFSET); regval = tiva_i2c_putreg(priv, TIVA_I2CSC_PP_OFFSET);
if ((regval & I2CSC_PP_HS) != 0) if ((regval & I2CSC_PP_HS) != 0)
{ {
regval = ((SYSCLK_FREQUENCY + tmp = (2 * 3 * 3400000)
(2 * 3 * 3400000) - 1) / (2 * 3 * 3400000)) - 1; regval = (((SYSCLK_FREQUENCY + tmp - 1) / tmp) - 1) << I2CM_TPR_SHIFT;
tiva_i2c_putreg(priv, TIVA_I2CM_TPR_OFFSET, I2CM_TPR_HS | regval); tiva_i2c_putreg(priv, TIVA_I2CM_TPR_OFFSET, I2CM_TPR_HS | regval);
} }
@ -1535,32 +1532,10 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
{ {
struct tiva_i2c_inst_s *inst = (struct tiva_i2c_inst_s *)dev; struct tiva_i2c_inst_s *inst = (struct tiva_i2c_inst_s *)dev;
struct tiva_i2c_priv_s *priv = inst->priv; struct tiva_i2c_priv_s *priv = inst->priv;
uint32_t status = 0;
int errval = 0; int errval = 0;
ASSERT(count); ASSERT(count);
/* Wait for any STOP in progress. NOTE: If we have to disable the FSMC
* then we cannot do this at the top of the loop, unfortunately. The STOP
* will not complete normally if the FSMC is enabled.
*/
tiva_i2c_sem_waitstop(priv);
/* Clear any pending error interrupts */
#warning Missing logic
/* "Note: When the STOP, START or PEC bit is set, the software must
* not perform any write access to I2C_CR1 before this bit is
* cleared by hardware. Otherwise there is a risk of setting a
* second STOP, START or PEC request." However, if the bits are
* not cleared by hardware, then we will have to do that from hardware.
*/
tiva_i2c_clrstart(priv);
/* Old transfers are done */
/* Reset ptr and dcnt to ensure an unexpected data interrupt doesn't /* Reset ptr and dcnt to ensure an unexpected data interrupt doesn't
* overwrite stale data. * overwrite stale data.
*/ */
@ -1571,6 +1546,8 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
priv->msgv = msgs; priv->msgv = msgs;
priv->msgc = count; priv->msgc = count;
priv->status = 0;
/* Reset I2C trace logic */ /* Reset I2C trace logic */
tiva_i2c_tracereset(priv); tiva_i2c_tracereset(priv);
@ -1579,11 +1556,11 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
tiva_i2c_setclock(priv, inst->frequency); tiva_i2c_setclock(priv, inst->frequency);
/* Trigger start condition, then the process moves into the ISR. I2C /* Send the address, then the process moves into the ISR. I2C
* interrupts will be enabled within tiva_i2c_waitdone(). * interrupts will be enabled within tiva_i2c_waitdone().
*/ */
tiva_i2c_sendstart(priv); tiva_i2c_sendaddress(priv);
/* Wait for an ISR, if there was a timeout, fetch latest status to get /* Wait for an ISR, if there was a timeout, fetch latest status to get
* the BUSY flag. * the BUSY flag.
@ -1591,64 +1568,36 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
if (tiva_i2c_sem_waitdone(priv) < 0) if (tiva_i2c_sem_waitdone(priv) < 0)
{ {
/* Read the raw interrupt status */ i2cdbg("ERROR: Timed out\n");
status = tiva_i2c_getreg(priv, TIVA_I2CM_RIS_OFFSET);
errval = ETIMEDOUT; errval = ETIMEDOUT;
i2cdbg("Timed out: status: 0x%08x\n", status);
/* "Note: When the STOP, START or PEC bit is set, the software must
* not perform any write access to I2C_CR1 before this bit is
* cleared by hardware. Otherwise there is a risk of setting a
* second STOP, START or PEC request."
*/
tiva_i2c_clrstart(priv);
} }
else if ((priv->status & I2CM_CS_ERROR) != 0)
/* Check for error status conditions */
#warning Missing logic
{ {
if ((priv->status & I2CM_CS_ARBLST) != 0)
{ {
/* Bus Error */ /* Arbitration Lost */
errval = EIO;
}
{
/* Arbitration Lost (master mode) */
errval = EAGAIN; errval = EAGAIN;
} }
else if ((priv->status & (I2CM_CS_ADRACK | I2CM_CS_DATACK)) != 0)
{ {
/* Acknowledge Failure */ /* Acknowledge Failure */
errval = ENXIO; errval = ENXIO;
} }
#ifdef I2CM_CS_CLKTO
else if ((priv->status & I2CM_CS_CLKTO) != 0)
{ {
/* Overrun/Underrun */ /* Timeout */
errval = EIO;
}
{
/* PEC Error in reception */
errval = EPROTO;
}
{
/* Timeout or Tlow Error */
errval = ETIME; errval = ETIME;
} }
#endif
/* This is not an error and should never happen since SMBus is not enabled */ else
{ {
/* SMBus alert is an optional signal with an interrupt line for devices /* Something else? */
* that want to trade their ability to master for a pin.
*/
errval = EINTR; errval = EIO;
} }
} }
@ -1657,7 +1606,8 @@ static int tiva_i2c_process(struct i2c_dev_s *dev, struct i2c_msg_s *msgs,
* NOTE: We will only see this busy indication if tiva_i2c_sem_waitdone() * NOTE: We will only see this busy indication if tiva_i2c_sem_waitdone()
* fails above; Otherwise it is cleared. * fails above; Otherwise it is cleared.
*/ */
#warning Missing logic
if ((tiva_i2c_getreg(priv, TIVA_I2CM_CS_OFFSET) & (I2CM_CS_BUSY | I2CM_CS_BUSBSY)) != 0)
{ {
/* I2C Bus is for some reason busy */ /* I2C Bus is for some reason busy */