In my system, I am using I2C and I realize under heavy interrupt load (from other sources), I2C communication is easily disrupted. Is this expected behavior for I2C? I would have expected despite interrupt load, it would still be ok since I2C is not exactly a time critical interface, clock is provided with data.


The processor is STM32. The interrupts are due to ADC, I cannot disable interrupts during the read events therefore I must find a solution where I can make the i2c communication more stable. The STM32 is master and the slave is another device (accelerometer).


When I connect a logic analyzer to the clock with a small flying cable, the problem disappears. Interestingly, there is no interrupt load, read write works well, when there is interrupt load, they don't. However, if I attach the probe to the clock, read write works under interrupt load as well. I think, there is a capacitance issue somewhere.

  • 1
    \$\begingroup\$ Your question is very generic because it all depends on the design of your system. How I2C handles really depends on the devices on the bus. Can you ignore them and come to the later? In an FPGA, you could design logic to take care of a lot for you and avoid this. Again, we need more information about the microcontroller and what other things you have. Usually a good solution here is to use an RTOS and properly design the tasks. \$\endgroup\$ Commented Feb 21, 2013 at 2:12
  • \$\begingroup\$ Two things to look for, Voltage sag on the pullups or on the power to your i2c master and slave, or emi or capacitance issues. As for interrupt load, do you mean your master is stopping to handle a interrupt? Some chips won't allow infinite clock stretching. \$\endgroup\$
    – Passerby
    Commented Feb 21, 2013 at 2:14
  • \$\begingroup\$ @GustavoLitovsky you are right but 80% of CPU cycles are servicing ADC interrupt and there is not enough time to do a read cycle during the non ISR window. So the read will be interrupted no matter how well I design the OS system. \$\endgroup\$
    – Ktc
    Commented Feb 21, 2013 at 10:15
  • \$\begingroup\$ @Passerby you may be right. The problem disappeared when I attached the probe of logic analyzer to the clock line. \$\endgroup\$
    – Ktc
    Commented Feb 22, 2013 at 0:06
  • \$\begingroup\$ What's your current value for the pull-ups. Have you tried changing them to a different value? (Try 10k or 4k7 or 2k just for a first guess) \$\endgroup\$
    – Tom L.
    Commented May 5, 2014 at 5:57

4 Answers 4


This is a software issue, you are spending too much time servicing interrupts & your I2C routine is not able to handle it (so that's two things which are not right). I have been through several similar situations.

First: You need to do as little as possible in the interrupts, only read & store the data, don't do any processing that you could do outside the ISR, maths can take a LOT of CPU cycles and the CPU cannot do anything else while in that interrupt.

Second: Investigate DMA to automate things, so your interrupts become almost a background automated process.

Third: If I2C is important, put THAT in an interrupt too, but make sure you work out the priorities!

Fourth: Work out why your I2C routine is failing, I2C itself can stand up to very intermittent timings, pauses & waits etc. so your routine may need modifying to allow this.

Fifth: See if you can "chain" interrupts, you may find you can service the ADC reads more efficiently, or put the ADC in a different mode where it does more work for you before interrupting (EG wait for all readings to be available, then read all in one hit, rather than 8 separate interrupts for 8 separate ADC channel reads).

Sixth: Use an oscilloscope or logic analyser, and spare IO pins on the board, to trace how much time you're spending in each bit of code, to see if you can speed it up. (Set pin high when you enter a function/ISR, set it low again on exit).

Seventh: Decide if you really need to read the ADC so much, will going slower make things worse? It's counter-intuitive but sometimes running slower actually gives nicer results, doing the work of averaging the signal for you and cutting down on spikes/transients which could cause problems or require extra processing to remove. We improved a motor control PID routine by simply running it 1/4 the speed, freeing up a load of CPU time in the process.

  • \$\begingroup\$ Thanks for suggestions. The problem somehow points to hardware. \$\endgroup\$
    – Ktc
    Commented Feb 22, 2013 at 0:03

A bus slave that's busy with other things has the ability to clock stretch to buy time until it's able to carry on its end of the communication. It does this by not immediately sending the ACK / NACK clock pulse, keeping the communication in an intermediate state until it's ready to answer.

Clock stretching is the appropriate way to deal with this sort of situation. A device that doesn't stretch and does other bad things (bus hang / restart, NACKs a valid address or command, etc.) can be problematic, and puts extra burden on the master to keep things sorted out (it has to repeat commands, keep track of NACKs, etc.)

  • \$\begingroup\$ You are right but the problem is the host. The host is busy with other things, not slave. So not so sure I can do a clock stretch. \$\endgroup\$
    – Ktc
    Commented Feb 21, 2013 at 10:16
  • \$\begingroup\$ Are you using onboard I2C hardware or bit-banging the protocol out of GPIO lines? There's no specific I2C timeout interval defined in the standard, so slaves should wait indefinitely for the master to finish a packet. \$\endgroup\$ Commented Feb 21, 2013 at 13:28
  • \$\begingroup\$ I use the STM32 IC2 APIs. Please see the update, it looks like capacitance issue. \$\endgroup\$
    – Ktc
    Commented Feb 22, 2013 at 0:01

Depending on the capabilities of the STM32 (I have never used one), you could try one of the following approaches. If you can provide more detail about what you are trying to do, and have a convincing argument about why each interrupt is necessary in the form you have it now, then a more specific answer may be thought of. Specifically in your case, though, I2C is slow enough for this to not be a problem with well written interrupt routines.

  • Interrupts for anything can usually be disabled. There are at most one or two Non-Maskable Interrupts in any usual controller, one of which is reset. If you don't need interrupt driven control of something (ADC or I2C, in your case), then turn that peripheral code into one that doesn't use interrupts, and then disable interrupts.

  • Interrupt handlers should not be long. Try to do as little as possible from the interrupt vector itself. The extreme minimalistic approach to interrupts is to simply set a flag from within the interrupt handler routine and have, say, the main loop do all the heavy lifting from there on in. What your specific application and firmware architecture requires may not be as simple as that, but it really is worthwhile to put in the effort to see how much really has to be done from within the interrupts.

  • If you have peripheral DMA, use that instead of interrupting at each byte. Typically, it would be easier to put the ADC on DMA as opposed to I2C, but different chips have different implementations. I would not be surprised if there was a clean way to hive off an I2C exchange to the DMA as well. DMA allows you to reduce the number of interrupts and leaves your processor core free from having to deal with every single block of data.

  • Try to identify the specific instances where you're seeing data corruption, and the mechanism by which the data corruption is happening. This is much harder to do, but with creative use of a modern oscilloscope / logic analyzer you may be able to see some of the problems. Specifically, make sure the problem has to do with timing and not memory (which is a possibility with a combination of terrible code and a liberal compiler)

EDIT : Some specific notes regarding this instance of the problem, from your comments on the question :

  • Having 80% CPU used to read the ADC is usually not a worthwhile thing to do. Gathering data is useless if you can't act on it or even save the data.
  • Even if you are somehow gathering (usefully) a huge amount of data, ADC interrupts should not be so long as to completely suppress the I2C peripheral for a time long enough to make it lose data. I2C runs at, at most, 100/400KHz. You'd need a really, really long interrupt to interrupt for long enough to make it look like something more serious than clock jitter on I2C.
  • \$\begingroup\$ Thanks. Our system requires this type of complex and long ISR, it is a long story. You are right though, I2C must sustain even under this interrupt load and it can't. I am suspecting the issue is in the hardware, see the update. \$\endgroup\$
    – Ktc
    Commented Feb 22, 2013 at 0:05
  • \$\begingroup\$ For what its worth, in my experience, most use cases which seem to mandate an insanely long ISR are actually those which deserve an RTOS. And yes, per your latest edit it does seem like a hardware problem. Try putting in a small capacitor on the line where your logic analyzer was and you'll probably be fine. Why that is necessary, though, is somewhat harder to answer. I'd check the I2C pullup resistors (may be too low for your bus capacitance), and check the datasheets of any I2C buffers/repeaters you may be using. \$\endgroup\$ Commented Feb 22, 2013 at 13:01

In a given system, there could be noise entering the clock and data buses. The fact that your logic anlayser removes the problem shows this. For practical and quickest implementation, just follow the cue given by your observation. On an i2c bus with 400kbits/sec implementation, based on similar observation, I connected 2M paralleled with 12pf to ground from clock and data points and found that the problem is solved. This removes/filters noise outside the band of interest required for the specific i2c communication. Please try and advise.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.