Wire library versus TimerOne interrupt on Teensy 2

Status
Not open for further replies.

klaasdc

Member
I'm trying to read data from a ST L3G4200D gyro, which is connected via 2-wire I2C to a Teensy2, on pins D0 and D1. I'm using the L3G library from https://github.com/pololu/l3g-arduino for convenience.

Everything works fine as long as the call to the library's gyro.read() function is in the main loop. If I put this call inside an interrupt using a TimerOne instance every 100ms, the Teensy virtual serial port fails to come up after programming and in Windows I get a popup saying "The USB device is not recognized". Reprogramming is still possible by pressing the button on the Teensy2 though.

I'm running out of ideas to try... Maybe anyone has a suggestion on where to look?


A minimal "nonworking" example of what I'm doing:

Code:
#include <Wire.h>
#include <L3G.h>
#include <math.h>
#include <TimerOne.h>

L3G gyro;

void setup() {
  Wire.begin();

  /* Enable gyro, default 250 deg/sec, ODR 100Hz, cutoff 12.5 Hz */
  if (!gyro.init()){
    Serial.println("Failed to autodetect gyro type!");
    while (1);
  }
  gyro.enableDefault();
  
  /* Setup interrupt */
  Timer1.initialize(100000);
  Timer1.attachInterrupt(interruptCode);

  Serial.begin(115200);
}

void loop() {
}

void interruptCode(){
   gyro.read();
  //Serial.print(gyro.g.y);
}
 
The Wire library, which is used by the L3G library, definitely will NOT work within interrupts on Teensy 2.0. The Wire library needs to use an interrupt itself, but while running inside another interrupt, new interrupts are disabled.

Likewise, Serial.print() is risky inside interrupts.

Here's a few possible solutions...

#1: Write to a global variable inside interruptCode(), and read it in loop() and run the code when you see that variable is set.

#2: Instead of interrupts with Timer1, use elapsedMillis or the Metro library, or course with code in loop().

#3: (risky) turn interrupts back on within interruptCode(), using sei() or interrupts(). If you don't complete the work before the timer creates another interrupt, your interrupt code will recursively interrupt itself, leading to bad results (probably overwriting all RAM).

#4: Use a Teensy 3.1. On the ARM processor, there's 16 levels of interrupt priority. You could set the timer at a medium priority level (the default anyway), and set Wire and USB at a higher priority, so they interrupt the timer, but the timer can't recursively interrupt itself. The Wire library on Teensy 3.1 also doesn't need interrupts for the simplest cases, which are probably what L3G is using.
 
Okay, I peeked in Wire.cpp and see what you mean. I'm a bit surprised why it would need interrupts at all, since the Wire read/write methods are supposed to be blocking anyway?

I'll solve it with a global flag and read it in the main loop, as you suggested.
Thanks for the help!
 
Status
Not open for further replies.
Back
Top