Timer interrupts with I2C

I'm trying to make a head tracker module that will use a MPU9150 IMU to measure head position, and send PPM signals to my radio transmitter via the trainer port using a 3.3V Pro Mini. The PPM timing code that I found uses Timer1, but I have a feeling that the timer is used by my I2C communication. When I comment out the section that changes Timer1, the code runs fine but I cannot get the PPM signal to generate without using the timer interrupt. Can anyone suggest a way I can get the interrupt at 22mS to run as well as I2C?

Code Below:

// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#include "Wire.h"
//#include <Servo.h>

// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "MPU6050.h"

// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 accelgyro;


int outPinPPM = 9;

int Fixed_uS = 300;       // PPM frame fixed LOW phase
int pulseMin = 650;

int16_t ax, ay, az;
int16_t gx, gy, gz;
int16_t mx, my, mz;
    int ch1;
    int ch2;
    int ch3 = 700;
    int ch4 = 800;
    int ch5 = 900;
    int ch6 = 1000;
    int ch7 = 1100;
    int ch8 = 1200;
int timing = 22000;
int padding;
#define LED_PIN 13
bool blinkState = false;
unsigned long time;
unsigned long oldtime;

ISR(TIMER1_COMPA_vect) {
    ppmoutput(); // Jump to ppmoutput subroutine
}

void setup() {
    // join I2C bus (I2Cdev library doesn't do this automatically)
    Wire.begin();




    // initialize serial communication
    // (38400 chosen because it works as well at 8MHz as it does at 16MHz, but
    // it's really up to you depending on your project)
    Serial.begin(38400);
    // initialize device
    Serial.println("Initializing I2C devices...");
    accelgyro.initialize();

    // verify connection
    Serial.println("Testing device connections...");
    Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

    // configure Arduino LED for
    pinMode(LED_PIN, OUTPUT);
    
        pinMode(outPinPPM, OUTPUT);   // sets the digital pin as output
        oldtime = micros();
   // Setup timer
  TCCR1A = B00110001; // Compare register B used in mode '3'
  TCCR1B = B00010010; // WGM13 and CS11 set to 1
  TCCR1C = B00000000; // All set to 0
  TIMSK1 = B00000010; // Interrupt on compare B
  TIFR1  = B00000010; // Interrupt on compare B
  OCR1A = 22000; // 22mS PPM output refresh
  OCR1B = 1000;
}

void loop() {
    // read raw accel/gyro measurements from device
    accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
    // these methods (and a few others) are also available
    //accelgyro.getAcceleration(&ax, &ay, &az);
    //accelgyro.getRotation(&gx, &gy, &gz);
 


    // display tab-separated accel/gyro x/y/z values

    
    ch1 = (map(ay, -17000, 17000, 0,1000) * 1) + pulseMin;
    
    if(mx<=0){
      
    ch2 = (map(my, 0, 120, 0,500) * 1) + pulseMin;
    }else{
      
    ch2 = 1000 - (map(my, 0, 120, 0,500) * 1) + pulseMin;
    }
  
        Serial.print("a/g/m:\t");
    Serial.print(ch1); Serial.print("\t");
    Serial.print(ch2); Serial.print("\t");
    Serial.print(ax); Serial.print("\t");
    Serial.print(ay); Serial.print("\t");
    Serial.print(az); Serial.print("\t");
    Serial.print(mx); Serial.print("\t");
    Serial.print(my); Serial.print("\t");
    Serial.print(mz); Serial.print("\t");
    Serial.print(gx); Serial.print("\t");
    Serial.print(gy); Serial.print("\t");
    Serial.print(gz);Serial.print("\n");
    // blink LED to indicate activity
    blinkState = !blinkState;
    digitalWrite(LED_PIN, blinkState);

}


void ppmoutput() { // PPM output sub
  // Channel 1 - Aeleron
  digitalWrite(outPinPPM, LOW);
  delayMicroseconds(Fixed_uS);    // Hold
  digitalWrite(outPinPPM, HIGH);
  delayMicroseconds(ch1);  // Hold for Aeleron_uS microseconds      

 // Channel 2 - Elevator 
  digitalWrite(outPinPPM, LOW);
  delayMicroseconds(Fixed_uS);    // Hold
  digitalWrite(outPinPPM, HIGH);
  delayMicroseconds(ch2); // Hold for Elevator_uS microseconds      

 // Channel 3 - Throttle
  digitalWrite(outPinPPM, LOW);
  delayMicroseconds(Fixed_uS);    // Hold
  digitalWrite(outPinPPM, HIGH);
  delayMicroseconds(ch3); // Hold for Throttle_uS microseconds      

 // Channel 4 - Rudder
  digitalWrite(outPinPPM, LOW);
  delayMicroseconds(Fixed_uS);    // Hold
  digitalWrite(outPinPPM, HIGH);
  delayMicroseconds(ch4);   // Hold for Rudder_uS microseconds

 // Channel 5
  digitalWrite(outPinPPM, LOW);
  delayMicroseconds(Fixed_uS);    // Hold
  digitalWrite(outPinPPM, HIGH);
  delayMicroseconds(ch5);

 // Channel 6
  digitalWrite(outPinPPM, LOW);
  delayMicroseconds(Fixed_uS);    // Hold
  digitalWrite(outPinPPM, HIGH);
  delayMicroseconds(ch6);

 // Channel 7
  digitalWrite(outPinPPM, LOW);
  delayMicroseconds(Fixed_uS);    // Hold
  digitalWrite(outPinPPM, HIGH);
  delayMicroseconds(ch7);

 // Channel 8
  digitalWrite(outPinPPM, LOW);
  delayMicroseconds(Fixed_uS);    // Hold
  digitalWrite(outPinPPM, HIGH);
  delayMicroseconds(ch8);
  
  digitalWrite(outPinPPM, LOW);
  delayMicroseconds(Fixed_uS); 
  digitalWrite(outPinPPM, HIGH);



}

The part that I comment out to get it to work is:

  TCCR1A = B00110001; // Compare register B used in mode '3'
  TCCR1B = B00010010; // WGM13 and CS11 set to 1
  TCCR1C = B00000000; // All set to 0
  TIMSK1 = B00000010; // Interrupt on compare B
  TIFR1  = B00000010; // Interrupt on compare B
  OCR1A = 22000; // 22mS PPM output refresh
  OCR1B = 1000;

How long does that interrupt take to execute? How often are you calling it? How much time is left to do anything else?

Not sure how long it takes to execute, but I works fine when I'm not using I2C. The interrupt should execute every 22mS, and take a maximum of 16mS.

The interrupt should execute every 22mS, and take a maximum of 16mS.

That's 73% of the time processing just one interrupt, not counting the time it takes to call the interrupt handler. How do you expect that there will be time to do much else?

MWrock:
When I comment out the section that changes Timer1, the code runs fine but I cannot get the PPM signal to generate without using the timer interrupt. Can anyone suggest a way I can get the interrupt at 22mS to run as well as I2C?

Rule #1 - don't do delays in an ISR.

For one thing, delayMicroseconds will work in an ISR, however it becomes inaccurate after about 1 mS, because of the timer overflow.

So attempting to take 16 mS in an ISR will make delayMicroseconds give incorrect results. You have to rethink.