MCU on Eclipse


Home | Pages | Archives


KL25Z and I2C: Missing Repeated Start Condition

December 5, 2012 11:27

I really hate this kind of stuff: I know it should work, but it does not. I’m loosing a lot of time (hours, days, even weeks) to track it down to the root cause. Yes, I create my own bugs. Yes, there are bugs in tools, sources, libraries and components. But what many might not believe: there are bugs in silicon too :-(. If you do not believe, here is one: there is a hardware I2C problem on the KL25Z used on the Freedom board. It worked in one project, but not in another.

❗ The silicon bug described here is present on many Kinetis devices, not only the KL25Z!

Logic Analyzer attached to the FRDM-KL25Z board

Logic Analyzer attached to the FRDM-KL25Z board

So if you are facing a problem where you read 0xFF or wrong values from the I2C bus with the KL25Z, here is probably why (and how to workaround it). The problem showed up with a modified version of the Freedom Accelerometer tutorial….

Start or not Start, that’s the question

In my application I need to read through I2C from a device. It is using the I2C1_MasterSendBlock() followed by a I2C1_MasterReceiveBlock() (see as well this post).

byte I2C2_ReadAddress(byte i2cAddr, byte *memAddr, byte memAddrSize, byte *data, word dataSize)
{
  byte res = ERR_OK;
  TMOUT1_CounterHandle timeout;
  bool isTimeout;

  if (I2C2_SelectSlave(i2cAddr)!=ERR_OK) {
    return ERR_FAILED;
  }
  for(;;) { /* breaks */
    /* send device address and memory address */
    I2C2_deviceData.dataTransmittedFlg = FALSE;
    res = I2C1_MasterSendBlock(I2C2_deviceData.handle, memAddr, memAddrSize, LDD_I2C_NO_SEND_STOP);
    if (res!=ERR_OK) {
      break; /* break for(;;) */
    }
    timeout = TMOUT1_GetCounter(I2C2_TIMEOUT_MS/TMOUT1_TICK_PERIOD_MS); /* set up timeout counter */
    if (timeout==TMOUT1_OUT_OF_HANDLE) {
      res = ERR_FAILED;
      break; /* break for(;;) */
    }
    do { /* Wait until data is sent */
      isTimeout = TMOUT1_CounterExpired(timeout);
      if (isTimeout) {
        break; /* break while() */
      }
    } while (!I2C2_deviceData.dataTransmittedFlg);
    TMOUT1_LeaveCounter(timeout);
    if (isTimeout) {
      res = ERR_FAILED;
      break; /* break for(;;) */
    }
    /* receive data */
    I2C2_deviceData.dataReceivedFlg = FALSE;
    res = I2C1_MasterReceiveBlock(I2C2_deviceData.handle, data, dataSize, LDD_I2C_SEND_STOP);
    if (res!=ERR_OK) {
      break; /* break for(;;) */
    }
    timeout = TMOUT1_GetCounter(I2C2_TIMEOUT_MS/TMOUT1_TICK_PERIOD_MS); /* set up timeout counter */
    if (timeout==TMOUT1_OUT_OF_HANDLE) {
      res = ERR_FAILED;
      break; /* break for(;;) */
    }
    do { /* Wait until data is received */
      isTimeout = TMOUT1_CounterExpired(timeout);
      if (isTimeout) {
        break; /* break while() */
      }
    } while (!I2C2_deviceData.dataReceivedFlg);
    TMOUT1_LeaveCounter(timeout);
    if (isTimeout) {
      res = ERR_FAILED;
      break; /* break for(;;) */
    }
    break; /* break for(;;) */
  } /* for(;;) */
  if (I2C2_UnselectSlave()!=ERR_OK) {
    return ERR_FAILED;
  }
  return res;
}

There is nothing wrong with that code, as it worked for other devices very well.

Below is a logic analyzer output from that code sequence, which reads from the device a value:

Working I2C Bus Communication

Working I2C Bus Communication

It sends a start condition (first green dot on the SDA line), followed by the I2C device address (0x68), then the memory address (0x00), followed by a ‘repeated start’ condition (the second green dot), then again the I2C device address (0x68), and then reads the data from the device (0x26). So this one is working.

Now here is the same thing on the KL25Z, same code, but this time things are screwed up:

Does not work: Start Condition is missing

Does not work: Start Condition is missing

The problem is: somehow the start condition is not sent, screwing up the communication, and the software just reads back 0xff (wrong!) :-(.

It took me a while to find out what is the difference between the ‘working’ and ‘non-working’ version: it is the pre-scaler setting for the I2C peripheral on the KL25Z. It works if the prescaler to the I2C bus is set to 1!

Workaround

To verify the settings, I inspect the ‘Internal Frequency’ Settings of the I2C_LDD component:

Internal Frequency Settings

Internal Frequency Settings

Here I have a dialog with which has a ‘Clock path’ tab which shows the clock used for the peripheral:

💡 The ‘Clock path’ is a really, really nice feature of Processor Expert!

Internal Frequency Settings with prescaler of 1

Internal Frequency Settings with prescaler of 1

If that bottom prescaler setting is set to one, I’m fine.

But if that setting is set to anything other than one, the bus communication does not work reliably, as shown above:

I2C prescaler not 1, will not work

I2C prescaler not 1, will not work!

Looks like the silicon has a real issue with the internal clock distribution :-(.
So the workaround is to make sure that a prescaler of 1 is used. This means to select the maximum clock frequency as offered in the above dialog. And to achieve the desired I2C bus clock frequency, to use the frequency divider bits e.g. to reach a desired I2C clock frequency:

Frequency Divider to achieve 109 kHz I2C clock

Frequency Divider to make a 109 kHz I2C clock

Summary

  1. Always have a working example (that’s why tutorials or example projects are great!)
  2. It is possible that my code has bugs (yep! I admit.)
  3. Libraries or sources from somebody else has bugs too (yep! they are not better than I am ;-).)
  4. It is not unlikely that silicon has bugs too, especially if the silicon is brand new (absolutely! that’s why companies wait until Rev 2.0 of the silicon comes out)
  5. The debugger combined with a logic analyzer is my best friend (yes, indeed! and makes a prefect Christmas present.)

Thinking that only software can be flawed is simply wrong: silicon has bugs too, and this is obvious with reading the silicon erratas. The current KL25Z erratas are available here (but does not list above issue (yet?)).

Happy Starting 🙂

PS: My Saleae Logic16 was my ‘self-wished-and-purchased’ Christmas gift for 2011. Still thinking what I should wish (and buy) for 2012 :-). Suggestions and donations are welcome. 🙂

Posted by Erich Styger

Categories: Boards, Debugging, Embedded, Embedded Components, I2C, Kinetis, KL25Z Freedom Board, Tips & Tricks

Tags: , , ,

53 Responses to “KL25Z and I2C: Missing Repeated Start Condition”

  1. Thank you for making all this very clear !
    I can’t wait to retry the ‘Accelerating …’ tutorial with various different frequencies as shown (have you already tried it ?).

    Also, you might want to add a link to this topic in your ‘Accelerating …’ tutorial.

    Like

    By Royce on December 5, 2012 at 15:09

    1. Good suggestion about the link (added now). And yes, I have used the I2C bus with different clock speeds, from below 100 kHz up to 1 MHz.

      Like

      By Erich Styger on December 5, 2012 at 15:28

  2. […] is an issue with the KL25Z silicon. Please see this post for further […]

    Like

    By Tutorial: Accelerating the KL25Z Freedom Board | MCU on Eclipse on December 5, 2012 at 15:27

  3. I2C is a very hard system to troubleshoot when it goes wrong. That is great that you found the error. One suggestion for Christmas… the Google Nexus 7 pad. I use it to keep my schematics, doc sets, for projects, source code, email …everything. The disadvantage is you can’t escape having your work with you at all times. I have the Saleae analzyer as well; I wish they would add the conditional software triggers… it has been over a year they have been promising… that would be a good Christmas gift.

    Like

    By Robert Lewis on December 5, 2012 at 21:00

    1. Hi Robert, yes, I miss the conditional triggers on the Saleae analyzer as well. And good suggestion with the Google Nexus 7 pad: I’m already using an iPad for this :-). The challenge with it is that the whole family wants to use it too 😉

      Like

      By Erich Styger on December 6, 2012 at 05:46

      1. And what type of cable adapter do you guys use to connect to the iPad or Nexus 7? Also, the Saleae website doesn’t mention that they have software for iOS or Android.

        Like

        By Gil dePaula on August 23, 2014 at 23:21

        1. There is no adapter. The Salea software runs on a host, not on a tablet or phone. But if you really want to have it on a tablet, then use a remote UI connection software, but I have not done that.

          Like

          By Erich Styger on August 24, 2014 at 07:44

      2. I had misunderstood the comments. I thought you guys were running the Saleae on the iPad and Nexus. Got it now! Thanks.

        Like

        By Gil dePaula on August 24, 2014 at 09:35

  4. […] ← Previous […]

    Like

    By Processor Expert Maxim I2C RTC Driver the Arduino Data Logger Shield | MCU on Eclipse on December 6, 2012 at 03:59

  5. Again (I hope this doesn’t get old) thanks! One update here. Mask Set Errata for Mask 2N97F lists it as Errata ID 6070, but it actually suggests that a value of zero is the safe bet: “I2C: Repeat start cannot be generated if the I2Cx_F[MULT] field is set to a non-zero value” . Ref: http://cache.freescale.com/files/microcontrollers/doc/errata/KINETIS_L_2N97F.pdf?fpsp=1

    Like

    By vicatcu on March 10, 2013 at 17:48

    1. ah, finally that errata has been published. Thanks for the link, as sometimes it is really hard to find such a important information.

      Like

      By Erich Styger on March 10, 2013 at 18:08

  6. I’ve been trying to get a Sensirion SHT21 humidity sensor to work on the KL15, wasn’t working and this is why.

    I don’t know whether to drink, or go on a monkey sh*t throwing rampage, or both.

    Like

    By Gibbon1 on October 4, 2013 at 23:42

    1. Hi Gibbon1,
      intersting, I thought that issue only exists for the KL25Z. Thanks for the heads up, as I want to switch one of my projects to the KL15.

      Like

      By Erich Styger on October 5, 2013 at 08:25

  7. I had the same problem with a KL05. Thanks. That would have been a nightmare.

    Like

    By Dusty on November 2, 2013 at 02:23

    1. Yes, Freescale is using the same IP blocks/silicon for multiple devices. So silicon bugs get easily propagated :-(. The good thing is that the most recent Processor Expert has a built in warning (at least for some known cases).

      Like

      By Erich Styger on November 2, 2013 at 07:23

  8. […] for myself, I have faced bugs in the hardware too (see “KL25Z and I2C: Missing Repeated Start Condition“). I was to solve my problem with the information from the errata and using special clock […]

    Like

    By Bit-Banging I2C with ResetBus() Functionality | MCU on Eclipse on December 8, 2013 at 18:38

  9. Hi Erich.
    I’m running “very low power” mode in KL25Z-FRDM.
    Core Clock: 2 MHz, bus Clock 0.666667 MHz. And Maximum I2C bus clock I can set is 33.33 KHz.
    I’m using I2C to write config and read data on Accelerometer MMA8451.
    Sometimes MMA8451 work correctly, but sometimes when rebooting, MMA8451 can not write config (initialize) –> Accelerometer can not work (hang if I put unlimited while loop at I2C return).
    This case, though I do many reset (simple software reset), it still can not work again. I must cut down power (re-solder battery) then it can work again.

    How can solve this problem? 33.33 KHz is not fine for MMA8451? (recommended in spec is 100 KHz –> 400 KHz)

    Like

    By Thach Ngo on January 3, 2014 at 08:39

    1. Hi Thach,
      this is a problem of the MMA8451 accerometer: it can hang, and you need reset the accelerometer (e.g. with a power-on reset). This is a known problem, and for this sometimes I put in a FET in my designs so I can unpower/repower I2C devices. Unfortunately the Freescale I2C hardware has no way to reset through the bus a hanging device. But you could do this with bit banging (see https://mcuoneclipse.com/2013/12/08/bit-banging-i2c-with-resetbus-functionality/).
      I hope this helps.

      Like

      By Erich Styger on January 3, 2014 at 08:54

      1. One thing I’ve had issues with over the years is, devices with I2C and SPI buses, don’t have reset lines, and after a watchdog timeout or jtag reset get left in the middle of a bus operation. For that reason when initializing the bus I bit bang the I2C or SPI Clock 8-10 times.

        Like

        By Gibbon1 on March 5, 2014 at 21:53

        1. Yes, this is indeed a problem. Unfortunately most I2C implementations do not support this in the hardware.
          What I do is bitbanging instead: https://mcuoneclipse.com/2013/12/08/bit-banging-i2c-with-resetbus-functionality/

          Like

          By Erich Styger on March 6, 2014 at 06:17

  10. Hi Erich,
    I saw that you own a Saleae Logic16. I’m thinking in buy one Logic Analizer, and I saw this and a gwinstek GLA-1016, did you have the oportunity to test this one ? Do you know if one is much better than the other ?

    Best Regards,
    Christian

    Like

    By Christian on March 5, 2014 at 20:59

    1. Hi Christian,
      I don’t know this GLA-1016. To me the software made the difference, and the Saleae one is really nice. To me it is exactly what I needed.

      Like

      By Erich Styger on March 5, 2014 at 21:22

  11. Thaks a lot Erich.. i’m begining to make me crazy…
    Yes, with the kl15 succes the same.
    Sometimes sending the restart and sometimes not.
    It has been to put the preescaler value to 1 and work it correctly

    Thanks !!

    Like

    By Carlos Burgos. on May 7, 2014 at 12:27

    1. Hi Carlos,
      yes, I know how this feels to find out that the silicon is buggy 😦

      Like

      By Erich Styger on May 7, 2014 at 12:55

  12. Hey yet again, Erich!
    Do you have experience working with SHT21?

    Like

    By Piotr Słupski on May 7, 2014 at 20:06

    1. Hi Piotr,
      no, I have not used the SHT21.

      Erich

      Like

      By Erich Styger on May 8, 2014 at 06:22

  13. Outstanding! I just came across the same issue on the K22 and was pounding my head against the wall trying to figure it out. Showing the clock path screen is the key. I tried manually setting mult to 0 but that did not work. When I did exactly as you said and made sure I2C0 prescale value was set to 1 (it was 2 in my design) everything started working!

    Like

    By Larry on March 26, 2015 at 14:29

    1. good to hear that I was able to help out :-)!

      Like

      By Erich Styger on March 26, 2015 at 14:31

  14. Hey Erich,

    First of all, thank you for all the helpful notes on Kinetis. It really helped!

    I have been getting what appears to be the exact same problem as the I2C LDD component works sometimes but not always (sometimes the SDA line is always pulled low for no reason).

    I am working with a KL46Z board and I tried following your tutorial to solve the bug, but I’ve encountered the following condition:

    My OUTDIV2PRESC = 1 but my OUTDIV4PRESC = 2. Do you know where we could change this value?

    Thank you!

    Thomas

    Like

    By Thomas on July 15, 2015 at 16:44

    1. Hi Thomas, what tools/toolchain are you using? Processor Expert with Kinetis Design Studio? With or without Kinetis SDK?
      You can manually change the clock prescaler values in Processor Expert.

      Like

      By Erich Styger on July 15, 2015 at 17:18

      1. Hey Erich,

        I am using Processor Expert with KDS but not SDK.
        I still can’t change the OUTDIV4PRESC even with Advanced option on.

        Interestingly, I enabled auto-initialization for all components of the project and it seems to have solved the problem. But I’m pretty sure it’ll fail again, given how it has failed before with Auto-initialization.

        Thanks.
        Thomas

        Like

        By Thomas on July 15, 2015 at 17:45

        1. Hi Thomas,
          if you use auto-initialization, then all what it does is to call the Init() function (and driver handle generation) during PE_low_level_init(). Could it be that you are somehow missing to call the Init() from your application, or using a duplicate device handle?
          It should not affect the prescaler settings in my view anyway, so I’m really wondering what the problem could be.

          Like

          By Erich Styger on July 15, 2015 at 20:43

  15. Hi Erich,
    Thank you for the prompt replies!

    I made sure that the Init function was called and I didn’t have a duplicate DeviceData handle (I had this error once but the compiler pointed it out).

    What is really interesting is that the Sensor Fusion project that uses the exact same configurations always works, but my project only works some of the time.

    Like

    By Thomas on July 15, 2015 at 20:49

    1. ‘Some of the time’ means same source/code/binary works sometimes, but not always. Or do you have a state/configuration/source file set where it does not always work? Would be interesting to know the difference between ‘working’ and ‘non-working’. Or are you saying that one time the clock prescalers are set correctly, one time not?

      Like

      By Erich Styger on July 15, 2015 at 21:29

      1. Hey Erich,

        working = I2C is getting reading from Accelerometer, SDA line is not always low;
        not-working = SDA line always low, I2C not reading anything.

        The clock prescalar OUTDIV4PRESC is still at 2 though, however. I wish I could find some documentation on OUTDIV4PRESC but Google turned up nothing.

        Anyway, after doing the following, the code is miraculously working:

        1. following the work-around in this tutorial and use the highest value for I2C source clock.
        2. Use 010 for both divider to get 375kHz (even though it gives a warning of exceeding the 100kHz limit.
        3. set all flag variables to volatile, which solved another problem of the ADC component of the same project only working with breakpoint present.

        Like

        By Thomas on July 15, 2015 at 21:54

        1. Hi Thomas,
          about point 2): you can ignore that warning. The original specs of I2C is for 100 kHz, but this warning does not make any sense to me if the device (like the one you are using) allows a higher speed).
          About 3): if you have to set things to volatile, either the compiler is doing things in a wrong way, or indeed there is a reentrancy problem. Marking the variable volatile prevents compiler optimizations, and will affect timing. So it might be because of optimizations, or because of timing that things work or do not work. Have you optimizations turned off?

          Like

          By Erich Styger on July 15, 2015 at 22:00

  16. Hi Erich,

    Pardon me if this question is too simple, but how do you see optimization levels?

    I followed a link you replied to on Freescale forum and check the Debug settings and the Other compiler flags blank is blank. Should I manually type in -0 to turn that off? Or maybe I don’t need volatile variable at all, even if they correspond to flags that are being set in events.c?

    Also, in the Tool Settings section under properties of the project, I am seeing ARM GNU Assembler, ARM C compiler, ARM C++ Compiler and ARM C++ Linker. Is this what I am supposed to be seeing?

    Apologies in advance for not know what appears to be basics of C.

    Thanks again for all the help.
    Thomas

    Like

    By Thomas on July 15, 2015 at 22:11

    1. Hi Thomas,
      you find the compiler optimization settings under Project > Properties > C/C++ Build > Settings > Optimization. The Optimization level should be ‘None -O0’ to disable optimizations. And yes, you should not need to use ‘volatile’, as this would not be a proper solution for a problem.

      Erich

      Like

      By Erich Styger on July 16, 2015 at 10:08

  17. Is there any example of use kl25 or kl26 as I2C Slave? I try use I2C_LLD with MASTER-SLAVE mode, but when I try detect address with i2cdetect on my Linux I don’t have any results 😦

    Like

    By misiek81 on September 26, 2015 at 16:49

    1. I have used the KL25Z as I2C slave, but have not published that project on GitHub because it was done for a research partner, and he did not want that project published. Have you checked the I2C signals with a logic analyzer if they make sense?

      Like

      By Erich Styger on September 26, 2015 at 18:04

      1. Now I have result of i2cdetect with correct address, OnRX and OnTX event in CI2C component when I put i2cset and i2cget command, but I don’t known how to get bytes from i2cset command, and send response for i2cget command. What is the order of events and methods of CI2C komponent to get and send bytes? I can’t find any example of internet 😦
        Thanks for any help.

        Michal

        Like

        By misiek81 on September 29, 2015 at 01:35

        1. I don’t know i2cdetec. I have an example with the KL25Z as master here: https://mcuoneclipse.com/2012/09/21/tutorial-accelerating-the-kl25z-freedom-board/
          I would need to dig out another example (was with CodeWarrior and using the S08), or to create a new example with the KL25Z as I2C slave first.
          As for not finding anything on the internet: have you checked the I2C_LDD help (see https://mcuoneclipse.com/2012/11/12/getting-help-on-processor-expert-components/) as it describes as well the slave use case?

          Like

          By Erich Styger on October 1, 2015 at 21:10

  18. I’m getting this exact lack of repeat start condition on an MKL16, but setting the I2Cx_F[MULT] to 0 or 1 does nothing to resolve it 😦 I suppose will continue to modify the clock path until I find a solution

    Like

    By jacobjennings on February 24, 2016 at 22:32

    1. Are you using Processor Expert? You should be able to verify that clock setting in there.

      Like

      By Erich Styger on February 25, 2016 at 05:54

  19. Hi Erich!

    I had a trouble very similar with the KL03Z, my problem is when i send the repeated start, the bus sends the last byte that i sent instead of the byte that i want to send. But the trouble it’s only when i run the application, but when i debug step by step it works! I’m not using Processor Expert.

    Like

    By Saul on July 1, 2016 at 19:21

    1. Hi Saul,
      there is yet another hardware bug with Kinetis around the double buffer implementation, see https://community.nxp.com/thread/377611
      Erich

      Like

      By Erich Styger on July 1, 2016 at 19:49

      1. Hi Erich,
        I have seen that post, but it’s possible to solve that problem?

        Like

        By Saul on July 1, 2016 at 20:09

        1. Hi Saul,
          ah, I see you have posted that question there too. I believe there is really no solution. I saw that several users switched to bit banging (I have the GenericSWI2C component doing this). That double buffering thing seems to be only in the newer Kinetis devices which have double buffering.

          Like

          By Erich Styger on July 1, 2016 at 20:24

  20. Hi Erich,
    Thanks for the post.
    I want to read two bytes from I2C slave device (using KL03 as master). If I try for reading only one byte it is working fine, but reading of two bytes is showing “1 FF” data. Is it because of repeated start conditions?
    and how to change I2C prescalar to 1 in KDS 3.0.0 ?
    I dont find “Internal clock frequency” in I2C component inspector.

    Like

    By Syed on August 17, 2016 at 12:19

    1. I am using PE and fsl_I2C component

      Like

      By Syed on August 17, 2016 at 12:23

      1. Hi Syed,
        I have not used that fsl_i2c component in my projects. Is it not possible to use the one I have used because there I can set the clock divider?
        Otherwise, you need to step through th fsl_i2c component code to see where the clock is configured.
        I recommend that you check with a logic analyzer the signals on the i2c bus so you see that is going on: without such a tool, your are more or less blind and don’t know what is going on 😦

        Erich

        Like

        By Erich Styger on August 17, 2016 at 18:09

  21. Hello Erich,

    Can this problem happen in the mke02z family?
    In my case it does not go into the OnMasterBlockSent event and does not return errors.

    Like

    By Assis on January 5, 2018 at 22:51

    1. I don’t have any KE02Z at hand. I have seen that silicon bug present on all Kinetis I have used so far, but the KE series uses very different peripherals. The only way to find out is to hook up a logic analyzer/scope and see if the repeated start condition is sent or not. If you don’t have a scope, try an I2C clock settings with no divider and check if the problem goes away.
      I hope this helps,
      Erich

      Like

      By Erich Styger on January 6, 2018 at 09:21

Leave a Reply



Mobile Site | Full Site


Get a free blog at WordPress.com Theme: WordPress Mobile Edition by Alex King.