Garbled I2C transmission

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Garbled I2C transmission

Jump to solution
1,171 Views
scottm
Senior Contributor II

I'm using interrupt-based I2C block transfers with the Processor Expert drivers for the MK22FN1M0AVLH12.  I've got a periodic I2C query that starts by sending a register number to a particular address.  Other code handles a subsequent block read command to get data from the register.

The problem is that the register byte, immediately after the slave address, is getting garbled.  It should be 0x02 but it frequently comes out 0xff, 0x88, or other values.  It shows up this way on my logic analyzer, and the oscilloscope confirms that's what's actually on the SDA line.  Nothing looks amiss on the analog side - levels are correct, no ringing or overshoot to speak of.  It's just wrong.

If I step through the code - specifically if I have any delay between the transmission of the slave address and the 0x02 byte, it works perfectly.  It does not work, however, if I insert a delay loop in the I2C ISR.  The garbled byte just gets moved out a few milliseconds.  The driver looks like it's behaving properly and I'm not seeing any spurious I2C interrupts.  I've tried baud rates all the way down to 15 kHz and it behaves exactly the same.

The behavior is the same if the register byte is set to 0x00 or 0xff.  Everything else looks OK on the logic analyzer - it just doesn't send the right data.

Any ideas?  This looks like it *should* be very straightforward but it's driving me nuts.

Thanks,

Scott

Labels (1)
Tags (1)
0 Kudos
Reply
1 Solution
934 Views
scottm
Senior Contributor II

I figured it out.  User error.  I was cleaning up the ColdFire version, moving some code out of the ISR that didn't need to be there, and noticed that the problem got worse.

I forgot that the Processor Expert I2C driver doesn't have its own output buffer.  I was only sending a single byte - the register number to be read - but the byte was in a local variable.  If the function finished its other work and returned before the I2C driver got a chance to send the byte, the value was being overwritten on the stack.  It's working perfectly now.

Thanks,

Scott

View solution in original post

0 Kudos
Reply
5 Replies
934 Views
mjbcswitzerland
Specialist V

Scott

Comparing the MK22FN1M0AVLH12 and MK22FN1M0VLL12 data sheets (A is revison after main) I see that the recommended software flow diagram has been modified a little to match the recommended flow in the parts with double-buffered I2C - although I don't think that any of the K22s have double-buffered operation since it is otherwise not noted anywhere.

I have used the I2C on many different Kinetis parts, including some newer ones with the double-buffered modification, but never had difficulties with the byte after the slave address when starting from an idle bus. I can confirm that the double-buffered parts do have diffciulties with the byte after the slave address when doing a repeat-start although, in this case, they tend to transmit the slave address twice if not handed specially.

Again, I don't think that the I2C design have been changed to double-buffered design in the K22 A parts but can't exclude that there is somethig else that has been (slightly) modified. Can you compare the same code on different parts to see whether it is restricted to your chip?

I have attached development notes concerning interrupt behavior of single and double buffered Kinetis I2C parts in master and save modes as reference.

Regards

Mark

0 Kudos
Reply
934 Views
scottm
Senior Contributor II

I have the same code running on a ColdFire version of the hardware - specifically on an MCF51JM128.  Mind you, they're both using Processor Expert drivers so I don't know how different the underlying code is.  It does seem to be exhibiting similar behavior but to a lesser degree.  I also seem to be able to influence it with other application activity, so I'm going to look for other possible causes.

This wasn't a problem before I switched to non-blocking I2C.  And previously on the ColdFire version I was using my own I2C code, which never seemed to behave quite like datasheets would suggest but I did have it working reliably.  If NXP would publish timing diagrams that showed the relationships between the external signals and the internal ones (completion interrupts, movement to and from the shift register, etc) I would be very happy.

Scott

0 Kudos
Reply
934 Views
mjbcswitzerland
Specialist V

Scott

I was thinking more of whether the exact code that you are using works on other K22 parts (pre-0 marking), or similar Kinetis parts? If the exact code works on them it would indicate a difference due to the silicon revision. (A reference board as comparison is useful. Eg. can you make a binary that runs on a similar reference board that demonstrates the behavior?)

In the past I analysed various problems with PE generated I2C code but sometimes the difficulty is more how the user's code interacts with it (eg. sometimes it requires user callbacks to do things and, without them added, it won't operate correctly). It is however a bit of a lucky-dip as to what you get and what it does so you may need to be prepared to anayse it, repair it or shape it to a certain requirement.

Regards

Mark

0 Kudos
Reply
935 Views
scottm
Senior Contributor II

I figured it out.  User error.  I was cleaning up the ColdFire version, moving some code out of the ISR that didn't need to be there, and noticed that the problem got worse.

I forgot that the Processor Expert I2C driver doesn't have its own output buffer.  I was only sending a single byte - the register number to be read - but the byte was in a local variable.  If the function finished its other work and returned before the I2C driver got a chance to send the byte, the value was being overwritten on the stack.  It's working perfectly now.

Thanks,

Scott

0 Kudos
Reply
934 Views
scottm
Senior Contributor II

Now you've done it - you made me clean my workstation.  I've got three devel boards here that all have mask set 1N41K, which I think is the A version.  I think I built the first with a pre-A part but I know I replaced it at some point and I can't find the original part.  Any pre-production prototype boards are probably the same and I don't want to take them apart to find out.

Anyway, since the behavior changes with what's going on in the application code I'm going to look elsewhere for causes and see if I can narrow down the possibilities a bit.  Perhaps it's related to interrupt latency?  In polled mode the timing would have been very consistent.  In interrupt mode it could vary quite a bit more depending on what's going on. I would think that that shouldn't affect what's going out, other than an inter-character delay.  If I can find a pre-A part I'll try that out.

Thanks,

Scott

0 Kudos
Reply