EmbeddedRelated.com
Forums
Memfault Beyond the Launch

I2c repeat start generation problem.

Started by shailesh lomate December 6, 2006
Hi experts & users,

I am using the LPC2210 arm controller I2c interface
for interacting with AT24c512 eeprom. My write
operation seems succed with the status codes generated
in sequence (0x08-> 0x18 -> 0x28).
As users may be aware, in order to read from the
AT24C512 eeprom first i require to make a dummy write
and then generate a repeat start and then do the
reading in order to get the data from eeprom.
In this case, i am unable to generate the repeat
start condition.
In order to make a dummy write i am setting the
STA bit for generating the Start condition, then i get
the Interrupt with status code 0x08, then the slave
address is transmitted along with write condition,
then i get the status code as 0x18, then i send higher
address and get the status code as 0x28 and then send
the lower address and get the status code as 0x28.
After which i am not generating the stop condition,
instead i am generating the start condition again ,
but i am getting the status code as 0x08 ( which
should have been 0x10). and then the read proceeds
with status codes as 0x40 & 0x50.
I would like to know what must be going wrong in
my sequence and the exact registers to be manipulated
in order to generate the repeat start condition.
I would highly appreatiate any ready made code
bein g developed for AT24C512 with LPC controller.
Thanking you and waiting for a valuable reply...

Shailesh

____________________________________________________________________________________
Need a quick answer? Get one in minutes from people who know.
Ask your question on www.Answers.yahoo.com

An Engineer's Guide to the LPC2100 Series

Hey friends,

No reply as yet !!! what's the matter ? no one who
has worked on LPC series I2c ?

Shailesh
--- shailesh lomate wrote:

>
> Hi experts & users,
>
> I am using the LPC2210 arm controller I2c interface
> for interacting with AT24c512 eeprom. My write
> operation seems succed with the status codes
> generated
> in sequence (0x08-> 0x18 -> 0x28).
> As users may be aware, in order to read from the
> AT24C512 eeprom first i require to make a dummy
> write
> and then generate a repeat start and then do the
> reading in order to get the data from eeprom.
> In this case, i am unable to generate the repeat
> start condition.
> In order to make a dummy write i am setting the
> STA bit for generating the Start condition, then i
> get
> the Interrupt with status code 0x08, then the slave
> address is transmitted along with write condition,
> then i get the status code as 0x18, then i send
> higher
> address and get the status code as 0x28 and then
> send
> the lower address and get the status code as 0x28.
> After which i am not generating the stop condition,
> instead i am generating the start condition again ,
> but i am getting the status code as 0x08 ( which
> should have been 0x10). and then the read proceeds
> with status codes as 0x40 & 0x50.
> I would like to know what must be going wrong in
> my sequence and the exact registers to be
> manipulated
> in order to generate the repeat start condition.
> I would highly appreatiate any ready made code
> bein g developed for AT24C512 with LPC controller.
> Thanking you and waiting for a valuable
> reply...
>
> Shailesh
>
>
>
>
____________________________________________________________________________________
> Need a quick answer? Get one in minutes from people
> who know.
> Ask your question on www.Answers.yahoo.com
>

____________________________________________________________________________________
Want to start your own business?
Learn how on Yahoo! Small Business.
http://smallbusiness.yahoo.com/r-index
--- In l..., shailesh lomate wrote:
>
> Hey friends,
>
> No reply as yet !!! what's the matter ? no one who
> has worked on LPC series I2c ?

Hm, you could wait a bit more than just 15 hours before complaining
[;)]
Apparently there is nobody with an AT24c512 around just now.
I have no knowledge on that chip either but I did do some applications
that use the restart.
The I2C code I am using is not my own code and I did not check the
actual status codes. But the I2C restart function checks on both 0x08
(START condition transmitted) and 0x10 (Repeated START condition
transmitted).

But looking at your description you are receiving data correctly

> > After which i am not generating the stop condition,
> > instead i am generating the start condition again ,
> > but i am getting the status code as 0x08 ( which
> > should have been 0x10). and then the read proceeds
> > with status codes as 0x40 & 0x50.

After the restart first the device address (I2C slave address) is sent,
resulting in status 0x40 (SLA+R Transmitted, ACK received)
and then 0x50 (Databyte received, ACK transmitted) - the transmitted ACK
tells me you want to read more bytes (sequential read)
I peeked in the AT42C512 datasheet and the order seems to be correct.

Is the data you read correct? Have you tried writing data and reading
that data back?
Connect either a logic analyzer or a digital storage oscilloscope to the
I2C lines and check what's happening at hardware level.
Good luck,
Rob
Hi,
> Is the data you read correct? Have you tried writing
> data and reading
> that data back?
> Connect either a logic analyzer or a digital storage
> oscilloscope to the
> I2C lines and check what's happening at hardware
> level.

No the data read is not correct. I have tried
writing the data is returns success for it. But for
reading data from eeprom i need to generate the
restart condition after sending the address from which
i need to read. Can anyone tell me I2EN flag if
disabled inbetween any transaction then the I2C engine
would get reset or it would retain its last state ?

Shailesh
--- ligfietser2003 wrote:

>
> --- In l..., shailesh lomate
> wrote:
> >
> > Hey friends,
> >
> > No reply as yet !!! what's the matter ? no one
> who
> > has worked on LPC series I2c ?
>
> Hm, you could wait a bit more than just 15 hours
> before complaining
> [;)]
> Apparently there is nobody with an AT24c512 around
> just now.
> I have no knowledge on that chip either but I did do
> some applications
> that use the restart.
> The I2C code I am using is not my own code and I did
> not check the
> actual status codes. But the I2C restart function
> checks on both 0x08
> (START condition transmitted) and 0x10 (Repeated
> START condition
> transmitted).
>
> But looking at your description you are receiving
> data correctly
>
> > > After which i am not generating the stop
> condition,
> > > instead i am generating the start condition
> again ,
> > > but i am getting the status code as 0x08 ( which
> > > should have been 0x10). and then the read
> proceeds
> > > with status codes as 0x40 & 0x50.
>
> After the restart first the device address (I2C
> slave address) is sent,
> resulting in status 0x40 (SLA+R Transmitted, ACK
> received)
> and then 0x50 (Databyte received, ACK transmitted) -
> the transmitted ACK
> tells me you want to read more bytes (sequential
> read)
> I peeked in the AT42C512 datasheet and the order
> seems to be correct.
>
> Is the data you read correct? Have you tried writing
> data and reading
> that data back?
> Connect either a logic analyzer or a digital storage
> oscilloscope to the
> I2C lines and check what's happening at hardware
> level.
> Good luck,
> Rob
>
> [Non-text portions of this message have been
> removed]

____________________________________________________________________________________
Have a burning question?
Go to www.Answers.yahoo.com and get answers from real people who know.
Hi Shailesh

I use these routine to comunicate with 24c04. I hope this will help you.

U8 read_24c04(U8 device, U16 address)
{
U8 tmp = (address >> 7 | device) & 0xfe; //

I2C0CONSET = STA; //
while(I2C0STAT != 0x08); // wait for : START transmitted
I2C0DAT = tmp; //
I2C0CONCLR = SI | STA; //
while(I2C0STAT != 0x18); // wait for : SLA+W transmitted; ACK
received
I2C0DAT = address; //
I2C0CONCLR = SI; //
while(I2C0STAT != 0x28); // wait for : Data byte in I2DAT
transmitted; ACK received
I2C0CONSET = STA; //
I2C0CONCLR = SI; //
while(I2C0STAT != 0x10); // wait for : Repeated START transmitted
I2C0DAT = tmp | 0x01; //
I2C0CONCLR = SI | STA; //
while(I2C0STAT != 0x40); // wait for : SLA+R transmitted; ACK
received
I2C0CONCLR = SI | AA; //
while(I2C0STAT != 0x58); // wair for : Data byte received; NAK
returned
tmp = I2C0DAT; //
I2C0CONSET = STO; //
I2C0CONCLR = SI; //
while(I2C0STAT != 0xf8); // wait for completion
return tmp;
}
void write_24c04(U8 device, U16 address, U8 data)
{
U8 tmp = (address >> 7 | device) & 0xfe;
I2C0CONSET = STA; //
while(I2C0STAT != 0x08); // wait for : START transmitted
I2C0DAT = tmp; //
I2C0CONCLR = SI | STA; //
while(I2C0STAT != 0x18); // wait for : SLA+W transmitted; ACK
received
I2C0DAT = address; //
I2C0CONCLR = SI | STA; //
while(I2C0STAT != 0x28); // wait for : SLA+W transmitted; ACK
received
I2C0DAT = data; //
I2C0CONCLR = SI; //
while(I2C0STAT != 0x28); // wait for : Data byte in I2DAT
transmitted; ACK received
I2C0CONSET = STO; //
I2C0CONCLR = SI; //
while(I2C0STAT != 0xf8); // wait for : Data byte in I2DAT
transmitted; ACK received
do
{
I2C0CONSET = STA; //
if(I2C0STAT == 0x20) I2C0CONCLR = SI; //
while(I2C0STAT != 0x08 && I2C0STAT != 0x10); // wait for : START
transmitted
I2C0DAT = tmp; //
I2C0CONCLR = SI | STA; //
while(I2C0STAT != 0x18 && I2C0STAT != 0x20); // wait for : ACK or
NAK receved
} while (I2C0STAT != 0x18); // wait for : ACK
I2C0CONSET = STO; //
I2C0CONCLR = SI; //
}
Hi friends,
These are the briefs of my code. Can anyone analyse
them and let me what could the problem be ?

InitRoutine()
{
HAL_READ_UINT32(pin_base +
CYGARC_HAL_LPC2XXX_REG_PINSEL0, reg);
HAL_WRITE_UINT32(pin_base +
CYGARC_HAL_LPC2XXX_REG_PINSEL0, reg|0x00000050);
HAL_READ_UINT32(pin_base +
CYGARC_HAL_LPC2XXX_REG_PINSEL0, reg);

//Determine the clock frequency using I2SCLH &
I2SCLL reg

//Assuming pclk0MHz and I2C peripheral
working on 100KHz.
HAL_WRITE_UINT16(base +
CYGARC_HAL_LPC2XXX_REG_I2SCLH, 0x015E);
HAL_WRITE_UINT16(base +
CYGARC_HAL_LPC2XXX_REG_I2SCLL, 0x015E);

//Enable master mode & interrupt //Set I2EN
Bit
HAL_WRITE_UINT8(base +
CYGARC_HAL_LPC2XXX_REG_I2CONSET, 0x40);
Enable_Interrupt();

}

send_start()
{
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONSET,0x40);//Sl061205
HAL_READ_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONSET, sr);

sr1=sr;
sr=sr & 0x04;//Check if AA bit is set-if
set,device is in slave mode
// and hence cannot generate
start cond,hence return
if(sr!=0)
return 0;
else //If AA bit is not set, set the STA bit
to generate start cond.
sr1=sr1 | 0x20;
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONSET, sr1);
HAL_WRITE_UINT8(base +
CYGARC_HAL_LPC2XXX_REG_I2DAT, address);

}

isr()
{
//Read status register and clear the interrupt
bit.
HAL_READ_UINT8( base +
CYGARC_HAL_LPC2XXX_REG_I2STAT, sr);

//Read data register.
HAL_READ_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2DAT,set);

if(sr==0x08 || sr=){ /* start condition has
been transmitted */
//write slave address & r/w bit to
i2dat
HAL_READ_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2DAT,set);
// Clear STA & SI bit
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONCLR, 0x28);
}
elseif(sr==0x18){ /* Slave addr, write
direction has been transmitted,
ACK received */
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2DAT,*tx_data);
tx_data += 1;
count--;
// Clear SI bit
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONCLR, 0x08);
}
else if(sr==0x20){ /* Slave addr, write
direction has been transmitted,
NOT ACK received */
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONSET, 0x50);
/*Master Mode & set STO bit*/
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONCLR, 0x08);
/*Clear SI bit*/
result=1;
}
else if(sr==0x28){ /* Data byte transmitted,
ACK received */
if(i2c_count-- > 0){
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2DAT,*tx_data);
tx_data += 1;
//Clear SI bit
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONCLR, 0x08);
}
else{
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONCLR, 0x48);
//Clear SI bit nw add
result=1;

}
}
else if(sr==0x30){ /* Data byte transmitted,
NOT ACK received */
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONSET, 0x50);
/* Stop condition issued */
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONCLR, 0x08);
/* Clear SI bit */
result=1;
}
else if(sr==0x40){ /* Slave addr, read
direction has been transmitted, ACK received */
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONSET, 0x04);

HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONCLR, 0x08);
/* Clear SI bit */
}
else if(sr==0x50||sr==0x58){ /* Data byte
received, ACK returned */
if(i2c_count-- > 0){

HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONSET,
0x04);
HAL_READ_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2DAT,*(rx_data));
rx_data += 1;
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONCLR, 0x08); /* Clear
SI bit */
}
else{
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONSET, 0x50);
/*Stop condition*/
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONCLR, 0x08); /*
Clear SI bit */
result=1;
}
}
else if(sr==0x38){ /* Arbitration lost in NOT
ACK bit */
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONSET, 0x60);
/* Issue start condition */
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONCLR, 0x08);
/* Clear SI bit */
}
else if(sr==0x48){ /* slave addr + r has been
transmitted NAK received*/

HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONSET, 0x50); /* Stop
followed by a start transmitted */
HAL_WRITE_UINT8(base
+CYGARC_HAL_LPC2XXX_REG_I2CONCLR, 0x08);
/* Clear SI bit */
result=1;
}
if(result == 1){
i2c_completed = 1;
}
interrupt_unmask(vec); /* Unmask I2C
interrupt */
}

stop_it()
{
HAL_WRITE_UINT8(I2C_BASE(extra) +
CYGARC_HAL_LPC2XXX_REG_I2CONSET,0x50);

}

tx(bool send_stop_flag)
{
send_start();
if(send_stop_flag)
send_stop();
}

rx(bool
send_stop_flag)
{
send_start();
if(send_stop_flag)
send_stop();

}

main()
{
InitRoutine();
tx(FALSE);
rx(TRUE);
}

Shailesh

--- shailesh lomate wrote:

> Hi,
> > Is the data you read correct? Have you tried
> writing
> > data and reading
> > that data back?
> > Connect either a logic analyzer or a digital
> storage
> > oscilloscope to the
> > I2C lines and check what's happening at hardware
> > level.
>
> No the data read is not correct. I have tried
> writing the data is returns success for it. But for
> reading data from eeprom i need to generate the
> restart condition after sending the address from
> which
> i need to read. Can anyone tell me I2EN flag if
> disabled inbetween any transaction then the I2C
> engine
> would get reset or it would retain its last state ?
>
> Shailesh
> --- ligfietser2003 wrote:
>
> >
> > --- In l..., shailesh lomate
> > wrote:
> > >
> > > Hey friends,
> > >
> > > No reply as yet !!! what's the matter ? no
> one
> > who
> > > has worked on LPC series I2c ?
> >
> > Hm, you could wait a bit more than just 15 hours
> > before complaining
> > [;)]
> > Apparently there is nobody with an AT24c512 around
> > just now.
> > I have no knowledge on that chip either but I did
> do
> > some applications
> > that use the restart.
> > The I2C code I am using is not my own code and I
> did
> > not check the
> > actual status codes. But the I2C restart function
> > checks on both 0x08
> > (START condition transmitted) and 0x10 (Repeated
> > START condition
> > transmitted).
> >
> > But looking at your description you are receiving
> > data correctly
> >
> > > > After which i am not generating the stop
> > condition,
> > > > instead i am generating the start condition
> > again ,
> > > > but i am getting the status code as 0x08 (
> which
> > > > should have been 0x10). and then the read
> > proceeds
> > > > with status codes as 0x40 & 0x50.
> >
> > After the restart first the device address (I2C
> > slave address) is sent,
> > resulting in status 0x40 (SLA+R Transmitted, ACK
> > received)
> > and then 0x50 (Databyte received, ACK transmitted)
> -
> > the transmitted ACK
> > tells me you want to read more bytes (sequential
> > read)
> > I peeked in the AT42C512 datasheet and the order
> > seems to be correct.
> >
> > Is the data you read correct? Have you tried
> writing
> > data and reading
> > that data back?
> > Connect either a logic analyzer or a digital
> storage
> > oscilloscope to the
> > I2C lines and check what's happening at hardware
> > level.
> >
> >
> > Good luck,
> > Rob
> >
> >
> >
> > [Non-text portions of this message have been
> > removed]
> >
> >
>
____________________________________________________________________________________
> Have a burning question?
> Go to www.Answers.yahoo.com and get answers from
> real people who know.
>

____________________________________________________________________________________
Yahoo! Music Unlimited
Access over 1 million songs.
http://music.yahoo.com/unlimited
Hi Shailesh,

just returned today and found some time to comment on your code.
I'm not sure if you still have the problem but I found some things in
your code that I'll comment below.

In send_start() you start with setting the I2EN bit but this is not
needed. You set this bit in the InitRoutine() and it should not be
cleared before you are finished with all of your I2C stuff. Second thing
you do is read the I2CONSET register and you use this data to set the
STA bit at the end of the routine but it is better to perform the
read/write actions just behind each other. The content of the register
may be changed (by e.g. an ISR routine) in between the few lines of code
in your function - maybe not in this specific case but better safe than
sorry.

In the isr(), as soon as you detect that a start condition has been
sent, you read the I2DAT register and after detecting a start/restart
condition you again read that same register - is this really what you
meant to do ???
You already sent the address in send_start() - in the code I have this
is only done after the status register identifies that the start
condition has been sent.

Then, in the if(sr == 0x18) section you use count-- to keep track of
the number of bytes to send but in the (sr == 0x28) this suddenly is
i2c_count--
I gues this should be the same counter.

The (sr == 0x50 || sr == 0x58) section is a bit strange.
Here you set the AA bit after receiving (and acknowledging ?) a
databyte, but the AA bit should be set before the receive is done - in
that way you will acknowledge the data received. Only before the last
byte that you receive you should clear the AA flag such that the last
byte will be received and not acknowledged. In that way the slave knows
this is the last byte. Just stopping the transaction (by sending the
stop condition) is a crude way of ending a nice conversation [;)]

Furthermore, when entering isr() you do not check for the SI flag and
you only clear the SI flag in the different sections of the else if()
blocks.
It is better to check the SI flag on entering (and exit when not set,
just in case of a spurious interrupt) and clear the flag on exit - this
cleans up the code a bit and makes sure that you never end up with a
deadlock situation where communication does not proceed - which is
perfectly possible since you do not handle all possible situations.
Converting the if / else if statements into a switch with a 'default:'
will further make it more readable.

Readability and understanding of code is the first thing to look at when
you find the code does not do what it should.

I hope this helps a bit, I did not have any time to write/check some I2C
code - I am still to occupied with the user interface for my on-board
computer and meanwhile my boss also wants me to do some things [:">]

Regards,
Rob

Memfault Beyond the Launch