Interrupts causing problems..

Hi,

I’m using an MPU6050 to get IMU data using the following code:

void GetIMUData(){   // Gets IMU data from MPU6050
nowtime = micros();

  Wire.beginTransmission(MPU_addr);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr,14,true);  // request a total of 14 registers
  AcX = Wire.read()<<8;
  AcX |= Wire.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)     
  AcY = Wire.read()<<8;
  AcY |= Wire.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ = Wire.read()<<8;
  AcZ |= Wire.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  Tmp = Wire.read()<<8;
  Tmp |= Wire.read();  // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  GyX = Wire.read()<<8;
  GyX |= Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY = Wire.read()<<8;
  GyY |= Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ = Wire.read()<<8;
  GyZ |= Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
  
  timetaken = micros() - nowtime;
  
  accelangleY = atan2(AcX, AcZ)*4068/71.00;
  accelangleX = atan2(AcY, AcZ)*4068/71.00;
  
  gyroX = (GyX-3)/65.50; //turn value into deg/s
  gyroY = (GyY)/-65.50; //turn value into deg/s
  gyroZ = (GyZ)/-65.50; // into deg/s
}

and i am also using an RC receiver to detect 4 PWM inputs using interrupts for the 4 input channels, however I have noticed that the acceleration values seem to be a bit more noisy than what I would expect. I ran the code again but with the interrupts all switched off and the noise was a lot better.

Upon further inspection it seems that every now and then the accel values change quite dramatically. Now I think it is because an interrupt routine is being called while the second byte of information from the IMU is being called and it is missing it.

The length of time the code above takes to run in 1.74mS. I am hesitant to add a “no interrupts()” line over the IMU data because surely that will mess up the PWM inputs?

I have 4 separate inputs each cycling at 50Hz, so to turn off interrupts for 1.74mS will cause more problems than before no?

Thanks in advance.

so you say you are being interrupted 200x per second for your PWM. how long does these interrupt last?

The 2-wire Serial Interface has priority 25 out of 26 in an Atmega328. So clearly your communication with the MPU through the wire interface has less priority than your PWM ones.

If I remember correctly the default speed for the wire library is 100kHz. you might want to do a Wire.setclock(400000UL); set it to 400kHz (param is a uint32_t)that will get your wire library 4 times faster and still OK with your MPU capabilities.

(Wire.setClock() must be called after Wire.begin(). Wire.begin() initializes the bitrate to 100kHz)

The registers between 0x3B and 0x48 indeed store Accelerometer Measurements, Temperature Measurement and Gyroscope Measurements but they are user-facing read register. They duplicate an internal working register and those measurements are written to the user-facing read register at the Sample Rate as defined in Sample Rate Divider Register 0x25 (but The accelerometer output rate is 1kHz)

from the doc:

The data within the accelerometer sensors’ internal register set is always updated at the Sample Rate. Meanwhile, the user-facing read register set duplicates the internal register set’s data values [u]whenever the serial interface is idle[/u]. This guarantees that a burst read of sensor registers will read measurements from the same sampling instant. Note that if burst reads are not used, the user is responsible for ensuring a set of single byte reads correspond to a single sampling instant by checking the Data Ready interrupt.

so as you are request all the bytes in one go, even if you are interrupted while reading, the user-facing read register should not be updated behind your back.

The four interrupt routines look like this:

void calcElev()
{
  if(digitalRead(ELEV_IN_PIN) == HIGH) { 
    ulElevStart = micros();
  }
  else {
    unElevInShared = (uint16_t)(micros() - ulElevStart);
  }
}

I tried to keep them simple to avoid any issues.

And it's 400 interrupts per second as it interrupts on the rising and falling edge of the 50Hz square wave.

"Class twoWire has no member named setClock"

Any ideas?

jaddion82052: "Class twoWire has no member named setClock"

Any ideas?

No capital --> setclock()

In your ISR I would use the PORT and a mask to read the pin state which will be much faster than digitalRead (and check LOW instead of HIGH because usually faster in assembly, so invert the if blocks)