I2C: delay required between setting RSTA and write to D?

cancel
Showing results for 
Search instead for 
Did you mean: 

I2C: delay required between setting RSTA and write to D?

536 Views
Contributor V

Is there a required delay between setting a repeat start condition and writing to the D register?

The reason I'm asking is because I have code that is misbehaving. After a repeated start, the next address byte gets mangled unless I insert a delay loop before writing to the D register.

I'm additionally puzzled because this is code that I used successfully before. I am now running it on a KL03 and testing on a FRDM-KL03Z board.

Please see the attached scope screenshots. One shows a correct I2C sequence: W: 3A 0D, repeat start, R: 3B 1A. The other shows what happens if I remove the little delay: after a repeat start condition the next address byte gets transmitted as 0x0d (incidentally 0x0d is the previous byte that was transmitted before setting RSTA).

DS1054Z_DS1ZA171205497_2016-10-17_17.40.29.png

DS1054Z_DS1ZA171205497_2016-10-17_13.27.40 nodelay.png

This is the full code and the line where the delay needs to be inserted: https://github.com/jwr/kinetis_i2c/blob/master/i2c.c#L207 (e.g. just before line 207, the write to the D register).

I found experimentally that a loop like this:

for(delay_counter=0; delay_counter < 18; delay_counter++) {
__asm("NOP");
}

will fix the problem. Smaller number of iterations does not fix the problem.

I am running with the default clocks and mult=2, icr=0x17, in case it matters (to get about ~50kHz I2C), but different speeds don't seem to change much. Also, the workaround for issue 6070 (errata for mask 1N96F) doesn't help.

Labels (2)
Tags (2)
0 Kudos
3 Replies

53 Views
Senior Contributor II

Has you've discerned the 'Good old days' are gone.  Broken parts, poor documentation, no official acknowledgments of the double buffered I2C problems with an easy to find Erata (Been a year last week since the problem was reported!) etc.  You are just the most recent documented victim of Double Buffering Bug :-(

Now for something more productive:

for(delay_counter=0; delay_counter < 18; delay_counter++) {
__asm("NOP");
}

The nop needs to be marked  'volatile':

  __asm__ __volatile__ ("nop");

Otherwise the compiler optimizer may remove it as it has no side effects.

Turn off optimization is not the correct solution, as some have done.

Also depending on the exact ARM part a nop may not actually consume any time.

It could be removed from the pipeline before execution.

In reality it is the for loop itself consuming the time in some cases.

0 Kudos

53 Views
Contributor II

Hi Jan,

This sounds like the Double Buffered IIC issue which has been discussed on this forum at some length.

See

Double Buffered I2C Difficulties (eg. KL27)

Regards,

Martin.

0 Kudos

53 Views
Contributor V

Wow, I didn't even notice the I2C peripheral in the KL03 is different from the ones I've used before! I developed and used the code on KL05, KL25 and K20. This is so frustrating. I thought the whole point of sticking with stone-age peripherals that we see in the Kinetis line was that they are well known back from older 8-bit micros, are reliable, predictable and well-documented. And then we get this kind of thing.

I guess it's my fault for not carefully checking that the I2C isn't quite the same I2C anymore, but where do I look for things like that? I never expected that switching from KL05 to KL03 would mean my I2C code will stop working.

A quick look seems to indicate that I will have to implement a workaround so that repeated start works again. I wonder how to make the driver universal — will have to detect somehow the different I2C peripherals.

Many thanks for answering — I've spent far too much time on this already, now at least I know what the problem is.

0 Kudos