Writing to I2C from an interrupt fails

When I try to write to the I2C bus by a timer triggered interrupt, it doesn't do anything. I even tried the slowest timer division(1024), still nothing. On the other hand when writing to I2C from a loop the actual data transmission takes about 300microseconds, that's much less than the interrupt repetition time, so maybe it's not a time time related issue.

#include <Wire.h>

byte inttime = 128; //second half of cycle

struct Threesamples {
  int smp1;
  int smp2;
  int smp3;
};

Threesamples threesamples;

void setup() {
  Wire.begin();
  Wire.setClock(400);

  //timer2
  TCCR2A = B10110011; //Timer Control Register 1, both Compare Match Outputs on non inverting mode, fast pwm mode

  TCCR2B = B00000100; //Timer Control Register 2, counter clock divided by 128 (1024us cycle)

  OCR2A = inttime; //set compare match value

  TIMSK2 = B00000010; //configure interrupt to happen at Compare Match A
  

}

void loop() {

}

ISR (TIMER2_COMPA_vect) { //start interrupt at second half of cycle

  threesamples.smp1 = random(0, 1024);
  threesamples.smp2 = 512;
  threesamples.smp3 = 8;

  Wire.beginTransmission(8);
  Wire.write ((byte *) &threesamples, sizeof threesamples); //send struct by i2c
  Wire.endTransmission();
}

That looks like a brutal construction, starting, running and finishing wire inside an ISR.
Set a flag in the ISR and do the transmission in loop.

When I try to write to the I2C bus by a timer triggered interrupt, it doesn't do anything. I even tried the slowest timer division(1024), still nothing. On the other hand when writing to I2C from a loop the actual data transmission takes about 300microseconds, that's much less than the interrupt repetition time, so maybe it's not a time time related issue.

I2C communications require interrupts, and interrupts are disabled inside the ISR.

cattledog:
I2C communications require interrupts, and interrupts are disabled inside the ISR.

Thanks for clearing that up.
I'm open to other ways of sending a data struct from an interrupt, can SPI or serial help?

Not from inside the ISR.

Railroader:
Not from inside the ISR.

For using serial only one way I don't think this really applies, because I have successfully sent a single value from the ISR at high enough serial baud rate. But I can't figure out a way how to send a struct by serial.

Sending from inside an ISR is bad practise. How you managed that is a mystery. Set a flag and pick up that flag in loop code.

ISRs should be as short and fast as possible and should never do serial I/O of any sort.

That is not what interrupts are for!

As a beginner, it is incredibly unlikely that interrupts will be useful to you.

A common "newbie" misunderstanding is that an interrupt is a mechanism for altering the flow of a program - to execute an alternate function. Nothing could be further from the truth! :astonished:

An interrupt is a mechanism for performing an action which can be executed in "no time at all" with an urgency that it must be performed immediately or else data - information - will be lost or some harm will occur. It then returns to the main task without disturbing that task in any way though the main task may well check at the appropriate point for a "flag" set by the interrupt.

Now these criteria are in a microprocessor time scale - microseconds. This must not be confused with a human time scale of tens or hundreds of milliseconds or indeed, a couple of seconds. A switch operation is in this latter category and even a mechanical operation perhaps several milliseconds; the period of a 6000 RPM shaft rotation is ten milliseconds. Sending messages to a video terminal is clearly in no way urgent,

Unless it is a very complex procedure, you would expect the loop() to cycle many times per millisecond. If it does not, there is most likely an error in code planning; while the delay() function is provided for testing purposes, its action goes strictly against effective programming methods. The loop() will be successively testing a number of contingencies as to whether each requires action, only one of which may be whether a particular timing criteria has expired. Unless an action must be executed in the order of microseconds, it will be handled in the loop().

So what sort of actions do require such immediate attention? Well, generally those which result from the computer hardware itself, such as high speed transfer of data in UARTs(, USARTs) or disk controllers.

An alternate use of interrupts, for context switching in RTOSs, is rarely relevant to this category of microprocessors as it is more efficient to write cooperative code as described above.

I have found that @defavlttt is super resistant to advice. I wouldn't bother.

As always, part of the rationale for providing detailed advice (and as you know, I was using a "stock" reply saved for each time this situation arises) is not merely to educate the OP, but anyone whose search lands on this sad thread! :grinning:

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.