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.
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
#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_I2C 0x00000000 /* I2C Data Reg */ #define I2ADR_I2C 0x00000000 /* I2C Slave Address Reg */ #define I2SCLH_SCLH 0x00000080 /* I2C SCL Duty Cycle High Reg */ #define I2SCLL_SCLL 0x00000080 /* I2C SCL Duty Cycle Low Reg */ #define I2SCLH_HS_SCLH 0x00000008 /* Fast Plus I2C SCL Duty Cycle High Reg */ #define I2SCLL_HS_SCLL 0x00000008 /* 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 */
=> but the function I2CStart() return always "timeout". Do you mean that I2CStart() returns FALSE due to timeout?
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; }
But it seems you never assign an I2C_STARTED to I2CMasterState.
Search "I2CMasterState" (10 hits in 1 files) new 1 (10 hits) Line 6: volatile uint32_t I2CMasterState = I2C_IDLE; Line 48: I2CMasterState = I2C_NO_DATA; Line 71: I2CMasterState = I2C_OK; Line 79: I2CMasterState = I2C_NACK_ON_DATA; Line 112: I2CMasterState = I2C_OK; Line 120: I2CMasterState = I2C_NACK_ON_ADDRESS; Line 127: I2CMasterState = I2C_ARBITRATION_LOST; Line 146: if ( I2CMasterState == I2C_STARTED ) Line 201: I2CMasterState = I2C_IDLE; Line 213: if ( I2CMasterState == DATA_NACK )
An old thread may be relevant: http://www.keil.com/forum/19195/
Yes, the I2CStart() returns FALSE. This code is a driver sample of NXP for PCA8581, but don't work with my 24C08. I tried using the code below, but don't work. There is some error in I2C0_IRQHandler() that I can't find.
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. */ LPC_I2C0->I2DAT = I2CMasterBuffer[0]; LPC_I2C0->I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC); I2CMasterState = I2C_STARTED; break; case 0x10: /* A repeated started is issued */ LPC_I2C0->I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC); I2CMasterState = I2C_RESTARTED; break; case 0x18: /* Regardless, it's a ACK */ if ( I2CMasterState == I2C_STARTED ) { LPC_I2C0->I2DAT = I2CMasterBuffer[1+WrIndex]; WrIndex++; I2CMasterState = DATA_ACK; } LPC_I2C0->I2CONCLR = I2CONCLR_SIC; break; case 0x28: /* Data byte has been transmitted, regardless ACK or NACK */ case 0x30: if ( WrIndex != I2CWriteLength ) { LPC_I2C0->I2DAT = I2CMasterBuffer[1+WrIndex]; /* this should be the last one */ WrIndex++; if ( WrIndex != I2CWriteLength ) { I2CMasterState = DATA_ACK; } else { I2CMasterState = DATA_NACK; if ( I2CReadLength != 0 ) { LPC_I2C0->I2CONSET = I2CONSET_STA; /* Set Repeated-start flag */ I2CMasterState = I2C_REPEATED_START; } } } else { if ( I2CReadLength != 0 ) { LPC_I2C0->I2CONSET = I2CONSET_STA; /* Set Repeated-start flag */ I2CMasterState = I2C_REPEATED_START; } else { I2CMasterState = DATA_NACK; LPC_I2C0->I2CONSET = I2CONSET_STO; /* Set Stop flag */ } } LPC_I2C0->I2CONCLR = I2CONCLR_SIC; break; case 0x40: /* Master Receive, SLA_R has been sent */ LPC_I2C0->I2CONSET = I2CONSET_AA; /* assert ACK after data is received */ LPC_I2C0->I2CONCLR = I2CONCLR_SIC; break; case 0x50: /* Data byte has been received, regardless following ACK or NACK */ case 0x58: I2CMasterBuffer[3+RdIndex] = LPC_I2C0->I2DAT; RdIndex++; if ( RdIndex != I2CReadLength ) { I2CMasterState = DATA_ACK; } else { RdIndex = 0; I2CMasterState = DATA_NACK; } LPC_I2C0->I2CONSET = I2CONSET_AA; /* assert ACK after data is received */ LPC_I2C0->I2CONCLR = I2CONCLR_SIC; break; case 0x20: /* regardless, it's a NACK */ case 0x48: LPC_I2C0->I2CONCLR = I2CONCLR_SIC; I2CMasterState = DATA_NACK; break; case 0x38: /* Arbitration lost, in this example, we don't deal with multiple master situation */ default: LPC_I2C0->I2CONCLR = I2CONCLR_SIC; break; } }
=> I tried using the code below, but don't work
What do you mean by [but don't work] in this case?