lpcware

LPC1768 + AT24C08 - Timeout problem

Discussion created by lpcware Employee on Jun 15, 2016
Content originally posted in LPCWare by mtgtech on Fri Jul 20 11:00:47 MST 2012
Hello, I am using a AT24C08 for store some datas and I'm having trouble. I am using code sample for I2C. The data is being written and read perfectly, but the function I2CStart() return always "timeout". This "problem" causes a delay in my routines of W/R. I believe it is necessary some modification in I2C0_IRQHandler() function. Someone could review my code?

I implemented a matricial keypad for tests of write and read.

main.c

int main (void)
{
char temp[16];
unsigned char c = 0;
unsigned int i = 0;

SystemInit();
SysTick_Config(SystemFrequency/100);  /* Generate interrupt each 10 ms      */

if ( I2CInit( (uint32_t)I2CMASTER ) == FALSE )/* initialize I2c */
{
while ( 1 );/* Fatal error */
}

/* Initialize RTC with RTCCAL and RTCDIR values */
InitRTC();
/* start RTC */
StartRTC();

init_KEYPAD();
lcd_clear();

while(1)
{
c = get_KEYPAD();
if(c == '1')
{
for ( i = 0; i < BUFSIZE; i++ )/* clear buffer */
{
I2CMasterBuffer = 0;
}

I2CWriteLength = 5;
I2CReadLength = 0;
I2CMasterBuffer[0] = AT24C08_ADDR;
I2CMasterBuffer[1] = 0x00;/* address offset for user seq. */

I2CMasterBuffer[2] = LPC_RTC->HOUR;
I2CMasterBuffer[3] = LPC_RTC->MIN;
I2CMasterBuffer[4] = LPC_RTC->SEC;
I2CEngine();
}
if(c == '2')
{
for ( i = 0; i < BUFSIZE; i++ )
{
I2CSlaveBuffer = 0x00;
}
/* Write SLA(W), address, SLA(R), and read one byte back. */
I2CWriteLength = 2;
I2CReadLength = 20;
I2CMasterBuffer[0] = AT24C08_ADDR;
I2CMasterBuffer[1] = 0x00;/* address */
I2CMasterBuffer[2] = AT24C08_ADDR | RD_BIT;
I2CEngine();

}
lcd_gotoxy(0,0);
sprintf(temp,"%d:%d:%d",I2CSlaveBuffer[0],I2CSlaveBuffer[1],I2CSlaveBuffer[2]);
lcd_print(temp);
}

return 0;


i2c.c


#include "lpc17xx.h"
#include "type.h"
#include "i2c.h"
#include "lcd.h"

volatile uint32_t I2CMasterState = I2C_IDLE;
volatile uint32_t I2CSlaveState = I2C_IDLE;

volatile uint32_t I2CCmd;
volatile uint32_t I2CMode;

volatile uint8_t I2CMasterBuffer[BUFSIZE];
volatile uint8_t I2CSlaveBuffer[BUFSIZE];
volatile uint32_t I2CCount = 0;
volatile uint32_t I2CReadLength;
volatile uint32_t I2CWriteLength;

volatile uint32_t RdIndex = 0;
volatile uint32_t WrIndex = 0;


void I2C0_IRQHandler(void) 
{
  uint8_t StatValue;

  /* this handler deals with master read and master write only */
  StatValue = LPC_I2C0->I2STAT;

switch ( StatValue )
  {
case 0x08:/* A Start condition is issued. */
WrIndex = 0;
LPC_I2C0->I2DAT = I2CMasterBuffer[WrIndex++];
LPC_I2C0->I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);
break;

case 0x10:/* A repeated started is issued */
RdIndex = 0;
/* Send SLA with R bit set, */
LPC_I2C0->I2DAT = I2CMasterBuffer[WrIndex++];
LPC_I2C0->I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);
break;

case 0x18:/* Regardless, it's a ACK */
if ( I2CWriteLength == 1 )
{
  LPC_I2C0->I2CONSET = I2CONSET_STO;      /* Set Stop flag */
  I2CMasterState = I2C_NO_DATA;
}
else
{
  LPC_I2C0->I2DAT = I2CMasterBuffer[WrIndex++];
}
LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
break;

case 0x28:/* Data byte has been transmitted, regardless ACK or NACK */
if ( WrIndex < I2CWriteLength )
{  
  LPC_I2C0->I2DAT = I2CMasterBuffer[WrIndex++]; /* this should be the last one */
}
else
{
  if ( I2CReadLength != 0 )
  {
LPC_I2C0->I2CONSET = I2CONSET_STA;/* Set Repeated-start flag */
  }
  else
  {
LPC_I2C0->I2CONSET = I2CONSET_STO;      /* Set Stop flag */
I2CMasterState = I2C_OK;
  }
}
LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
break;

case 0x30:
LPC_I2C0->I2CONSET = I2CONSET_STO;      /* Set Stop flag */
I2CMasterState = I2C_NACK_ON_DATA;
LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
break;

case 0x40:/* Master Receive, SLA_R has been sent */
if ( (RdIndex + 1) < I2CReadLength )
{
  /* Will go to State 0x50 */
  LPC_I2C0->I2CONSET = I2CONSET_AA;/* assert ACK after data is received */
}
else
{
  /* Will go to State 0x58 */
  LPC_I2C0->I2CONCLR = I2CONCLR_AAC;/* assert NACK after data is received */
}
LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
break;

case 0x50:/* Data byte has been received, regardless following ACK or NACK */
I2CSlaveBuffer[RdIndex++] = LPC_I2C0->I2DAT;
if ( (RdIndex + 1) < I2CReadLength )
{  
  LPC_I2C0->I2CONSET = I2CONSET_AA;/* assert ACK after data is received */
}
else
{
  LPC_I2C0->I2CONCLR = I2CONCLR_AAC;/* assert NACK on last byte */
}
LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
break;

case 0x58:
I2CSlaveBuffer[RdIndex++] = LPC_I2C0->I2DAT;
I2CMasterState = I2C_OK;
LPC_I2C0->I2CONSET = I2CONSET_STO;/* Set Stop flag */
LPC_I2C0->I2CONCLR = I2CONCLR_SIC;/* Clear SI flag */
break;

case 0x20:/* regardless, it's a NACK */
case 0x48:
LPC_I2C0->I2CONSET = I2CONSET_STO;      /* Set Stop flag */
I2CMasterState = I2C_NACK_ON_ADDRESS;
LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
break;

case 0x38:/* Arbitration lost, in this example, we don't
deal with multiple master situation */
default:
I2CMasterState = I2C_ARBITRATION_LOST;
LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
break;
  }
}

uint32_t I2CStart( void )
{
  uint32_t timeout = 0;
  uint32_t retVal = FALSE;

  /*--- Issue a start condition ---*/
  LPC_I2C0->I2CONSET = I2CONSET_STA;/* Set Start flag */


   
  /*--- Wait until START transmitted ---*/
  while( 1 )
  {
if ( I2CMasterState == I2C_STARTED )
{
  retVal = TRUE;
  break;
}
if ( timeout >= MAX_TIMEOUT )
{
  lcd_gotoxy(1,0);
lcd_print("MAX_TIMEOUT");
  retVal = FALSE;
  break;
}
timeout++;
  }
  return( retVal );
}


uint32_t I2CStop( void )
{
  LPC_I2C0->I2CONSET = I2CONSET_STO;  /* Set Stop flag */
  LPC_I2C0->I2CONCLR = I2CONCLR_SIC;  /* Clear SI flag */
           
  /*--- Wait for STOP detected ---*/
  while( LPC_I2C0->I2CONSET & I2CONSET_STO );
  return TRUE;
}


uint32_t I2CInit( uint32_t I2cMode )
{
  LPC_SC->PCONP |= (1 << 7);

  /* set PIO0.27 and PIO0.28 to I2C0 SDA and SCL */
  /* function to 01 on both SDA and SCL. */
  LPC_PINCON->PINSEL1 &= ~((0x03<<22)|(0x03<<24));
  LPC_PINCON->PINSEL1 |= ((0x01<<22)|(0x01<<24));

  /*--- Clear flags ---*/
  LPC_I2C0->I2CONCLR = I2CONCLR_AAC | I2CONCLR_SIC | I2CONCLR_STAC | I2CONCLR_I2ENC;   

  LPC_PINCON->I2CPADCFG &= ~((0x1<<0)|(0x1<<2));
  LPC_I2C0->I2SCLL   = I2SCLL_SCLL;
  LPC_I2C0->I2SCLH   = I2SCLH_SCLH;

  /* Install interrupt handler */
  NVIC_EnableIRQ(I2C0_IRQn);

  LPC_I2C0->I2CONSET = I2CONSET_I2EN;
  return( TRUE );
}


uint32_t I2CEngine( void )
{
  I2CMasterState = I2C_IDLE;
  RdIndex = 0;
  WrIndex = 0;
  lcd_clear();
  if ( I2CStart() != TRUE )
  {
I2CStop();
return ( FALSE );
  }

  while ( 1 )
  {
if ( I2CMasterState == DATA_NACK )
{
  I2CStop();
  break;
}
  }

  return ( TRUE );     
}


i2c.h


#ifndef __I2C_H
#define __I2C_H

#define BUFSIZE             64
#define MAX_TIMEOUT         0x00FFFFFF

#define I2CMASTER           0x01
#define I2CSLAVE            0x02

#define AT24C08_ADDR        0xA0

#define RD_BIT              0x01

#define I2C_IDLE              0
#define I2C_STARTED           1
#define I2C_RESTARTED         2
#define I2C_REPEATED_START    3
#define DATA_ACK              4
#define DATA_NACK             5
#define I2C_BUSY              6
#define I2C_NO_DATA           7
#define I2C_NACK_ON_ADDRESS   8
#define I2C_NACK_ON_DATA      9
#define I2C_ARBITRATION_LOST  10
#define I2C_TIME_OUT          11
#define I2C_OK                12

#define I2CONSET_I2EN       (0x1<<6)  /* I2C Control Set Register */
#define I2CONSET_AA         (0x1<<2)
#define I2CONSET_SI         (0x1<<3)
#define I2CONSET_STO        (0x1<<4)
#define I2CONSET_STA        (0x1<<5)

#define I2CONCLR_AAC        (0x1<<2)  /* I2C Control clear Register */
#define I2CONCLR_SIC        (0x1<<3)
#define I2CONCLR_STAC       (0x1<<5)
#define I2CONCLR_I2ENC      (0x1<<6)

#define I2DAT_I2C0x00000000  /* I2C Data Reg */
#define I2ADR_I2C0x00000000  /* I2C Slave Address Reg */
#define I2SCLH_SCLH0x00000080  /* I2C SCL Duty Cycle High Reg */
#define I2SCLL_SCLL0x00000080  /* I2C SCL Duty Cycle Low Reg */
#define I2SCLH_HS_SCLH0x00000008  /* Fast Plus I2C SCL Duty Cycle High Reg */
#define I2SCLL_HS_SCLL0x00000008  /* Fast Plus I2C SCL Duty Cycle Low Reg */

extern void I2C0_IRQHandler( void );
extern uint32_t I2CInit( uint32_t I2cMode );
extern uint32_t I2CStart( void );
extern uint32_t I2CStop( void );
extern uint32_t I2CEngine( void );

#endif /* end __I2C_H */

Outcomes