[U-Boot-Users] I2C Initialization, important Update!!

Joakim Tjernlund
2003-03-14T13:38:50Z

> > For I2C Reset it is adviseable to cause at least a sequence of eight STOP
> > one START and another STOP condition. Some Manufacturers (Microchip when I
> > remember correctly) require that because in violation of the I2C Spec they
> > do not recognize a STOP condition while expecting the Bits of a Byte.

So does the DS1337 also, but I don't think this is a bug. When you are
reading FROM a I2C device, it owns the SDA signal and all you can do is
set the master SDA to high and generate clocks util the slave wants ACK/NACK.
When the slave sees the masters high SDA during the ACK/NACK cycle it will
look for a START or STOP condition. If the slave sees a STOP, it will go
into "passive"(release the bus) mode and listen for a new transmision.

> > Otherwise you might end up writing an arbitrary value the last addressed
> > location in your I2C memory if the previous transfer has been interrupted in
> > an unfortunate state... (see also I2C Edge Conditions, which addresses a
> > part of the Problem).
>
> Hi
>
> I have a DS1337 RTC which hangs if you press the reset button while doing
> hwclock. To "unhang" the DS1337 I have to remove the battery :-(.
> I figured the above I2C reset trick would help, but so far nothing helps.

[SNIP]

I managed to fix my problem, by coping the latest soft I2C code u-boot,
but I had to do some some changes to make it work reliably. I think this
is something all 8xx(possibly 82xx too) suffer from.

On my boards(862, B0 rev.) I2C_ACTIVE will pull SDA low initially whatever
I do(verified with a scope)!!
This messes up the DS1337 so it wont recover(sometimes), no matter how
many times I run the loop. By modifying the code to avoid activate, see #if 1
below, SDA is kept high until I do stop(as it should).

I think the I2C_ACTIVE behaviour is a CPU bug, possibly in other 8xx PUs as well.
Can anybody confirm this?

This is what I run now:

void myi2c_reset(void)
{
volatile immap_t *immr = (immap_t *)CFG_IMMR;
int j;

immr->im_cpm.cp_pbpar &= ~(PB_SCL | PB_SDA); /* GPIO */
immr->im_cpm.cp_pbodr |= PB_SDA; /* Open Drain Output */

if(getenv("noi2cres")){
printf("No I2C reset!\n");
return;
}
if 1
I2C_SCL(1);
I2C_SDA(1);
I2C_INIT;
I2C_TRISTATE;
#else
I2C_SCL(1);
I2C_SDA(1);
I2C_INIT;
I2C_ACTIVE; /* Buggy, will pull SDA low! */
#endif
for(j = 0; j < 9; j++) {
I2C_SCL(0);
I2C_DELAY;
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_DELAY;
}
send_stop();
}