Go Down

Topic: Reading from Wire inside an ISR (Read 606 times) previous topic - next topic

desh

I am trying to read data from a Wire (connected to a gyroscope) from inside a function called from an interrupt service routine. I am using the FlexiTimer2 library from http://playground.arduino.cc/Main/FlexiTimer2.

The problem I am having is that whenever this function (my function I'm attaching to the interrupt) is called, the code locks up. I beleive this is due to my Wire.something() function calls, since removing them and just using some Serial.print()s allows it to work properly.

My code:

Code: [Select]
void timerTask() {
  Serial.print("Gyro X: ");
 
  int buff[10];
  Wire.beginTransmission(ADDRESS_GYRO); //start transmission to ACC
  Wire.write(0x1B);        //sends address to read from
  Wire.endTransmission(); //end transmission
 
  Wire.beginTransmission(ADDRESS_GYRO); //start transmission to ACC
  Wire.requestFrom(ADDRESS_GYRO, G_TO_READ);    // request 6 bytes from ACC
 
  int i = 0;
  while(Wire.available())    //ACC may send less than requested (abnormal)
  {
    buff[i] = Wire.read(); // receive a byte
    i++;
  }
  Wire.endTransmission(); //end transmission
   
   
  Serial.print(buff[0]);
  Serial.print("\r\n");
}


And I assign my fuction to the interrupt handler here:

Code: [Select]
FlexiTimer2::set(500, timerTask);
    FlexiTimer2::start();


Is there a way for me to use Wire functions from within an interrupt, or is this not possible?

My ultimate goal is to query the gyro every so many milliseconds to get an accurate picture of how far I've rotated since I started.

Thanks for taking the time to read this...

Nick Gammon

Code: [Select]

Wire.beginTransmission(ADDRESS_GYRO); //start transmission to ACC
  Wire.requestFrom(ADDRESS_GYRO, G_TO_READ);    // request 6 bytes from ACC
 
  int i = 0;
  while(Wire.available())    //ACC may send less than requested (abnormal)
  {
    buff[i] = Wire.read(); // receive a byte
    i++;
  }
  Wire.endTransmission(); //end transmission


You don't need  Wire.beginTransmission and Wire.endTransmission around Wire.requestFrom.

Wire.requestFrom returns the number of bytes read.

You shouldn't be doing Serial.print inside an ISR, and the Wire library uses interrupts which is why it doesn't work.

Better is to set a flag, check that flag in the loop function, and do your stuff there.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

desh

I see... I was starting to suspect the Wire lib using interrupts was the problem.

Thanks!

MarkT

Rather than guess about how the Wire library works remember you have the source code for it - just have a look
at it's description and comments and code!

Actually for the Wire library you'd need to look at <install>/libraries/Wire/utility/twi.c to discover the use of interrupts,
so perhaps not the most straightforward example.

Built in libraries are either at <install>/libraries/... or a few (including HardwareSerial) are at <install>/hardware/arduino/cores/arduino/...

Even if the code means nothing the big comments at the top of a library file can be very informative.
[ I won't respond to messages, use the forum please ]

dhenry

Quote
or is this not possible?


It is generally not possible / advisable.

The issue is with re-entrancy: you have no way of knowing that before an isr is fired, if that very (wire) function is being called.

There are solutions around it but they fundamentally don't alter the picture:

1) don't call a function from within the isr;
2) if you have to, make sure that that function isn't called anywhere else.

desh

Yes, I didn't think to look at the included source for the libs...

I have an alternative solution that involves not using the interrupt to handle my Wire calls (keeping track of time in my main loop with if/else and doing what I need to there)..

Thanks for the responses.

Go Up