--- In l..., Mike Harrison wrote:
>
> (LPC2103 and 2136, but I think I2C is the same on most parts)
>
> I only want to use I2C to access an EEPROM, and to keep it simple
I'm using the I2C hardware in
> polled mode instead of under interrupts - I always
know what the
EEPROM will do next so this should
> simplify things a lot.
>
> However there's an issue I can't quite get my head round - I've
read
the UM several times & still
> can't figure out the answer...
>
> When doing an eeprom read, after sending the last byte of the
address, I need to do a repeated start
> condition, but am having a hard time figuring out how
this can work
reliably when the code might get
> interrupted. (all eeprom datasheets show using a
repeated start not
a stop+start)
>
> If I set STA, clear SI, then wait for SI to check when the start
condition has happened, and an
> interrupt occurs between setting STA and clearing SI,
the clear of
SI could be delayed until after
> the start condition has completed (due to the time
taken for the
interrupt service), and it could
> then loop forever waiting for the start condition to
finish.
>
> I can't clear SI before setting STA, as if an interrupt occurs
between these operations, the cleared
> SI could cause another byte to be written as the II2C
hardware is
still in master write mode.
>
> As I need to clear one bit & set another, it can't be done as an
atomic operation on I2CCON.
> OK I could disable ints but this feels like a messy
solution....
>
> I also can't see why this issue wouldn't also affect interrupt-
driven I2C, e.g. if a FIQ interrupts
> the I2C IRQ service between STA getting set and SI
being cleared,
unless the FIQ service time was
> always short enough to never be longer then the time
between STA
being set and SI going high.
> Or maybe there is there some internal latching that
prevents this?
>
> If setting STA also clears SI, then this shouldn't be a problem, but
as far as far as I can tell it
> doesn't.
>
> Below is the current code - any comments welcome!
>
> void sendiic(char d)
> { I2C0DAT=d; I2C0CONCLR=8; while((I2C0CONSET & 0x08)==0) ; }
>
> char iistart(char adr) // returns true if no ack
> {
> I2C0CONSET=0x20; // startcond
> // an int here could cause enough delay that SI gets set
by the hardware
> I2C0CONCLR=8; // clear previous int from
ee address
write
> while((I2C0CONSET & 0x08)==0); // this loop could
hang if SI got
cleared after hardware set it
> I2C0DATr;
> I2C0CONCLR=0x28; // clear start+int
> while((I2C0CONSET & 0x08)==0); // ii address done
> return(I2C0STAT!=0x18);
> }
>
> void iistop(void)
> { I2C0CONSET=0x10; // stop
> I2C0CONCLR=0x08; // clear int
> while(I2C0CONSET & 0x10); // wait til stop done
> }
>
>
> void doreadeeprom(Int32U adr,Int32U nbytes,char *dest) // b27..4 i2c
address
> {
> while(iistart(((adr>>24) & 0x0e) | 0xa0)) I2C0CONCLR=8;
>
> sendiic(adr>>8);
> sendiic(adr);
>
> iistart(((adr>>24) & 0x0e) | 0xa1);// repeated start
> I2C0CONSET=4; // ACK
>
> do {
> I2C0CONCLR=--nbytes?0x08:0x0c; // clear AA on last
> while((I2C0CONSET & 0x08)==0); // wait 1st byte
> *dest++=I2C0DAT;
>
> } while (nbytes);
> iistop();
>
>
> }
>
The secret it that the LPC2103 holds the I2C clock low (thus holding
the bus in a wait state) while the SI bit is set. So, until you clear
SI the start bit (or whatever the next state you've commanded) will
not occur.
Somewhere in the user manual is a single sentence that states
something like "while SI is set..." the low period of the SCL line is
stretched... or something like that. Search for the string I put in
quotes as I'm pretty sure that is the wording they used.
TC