Adding I2C controlled MPU to Shield-EKG-EMG's demo sketch

Started by abhinav, March 22, 2015, 08:02:44 AM

Previous topic - Next topic

abhinav

Hi, I am working on recording EKG data along with tracking accelerometer readings (on an MPU-6050) through I2C. I really like how this demo sketch uses FlexiTimer2 to generate interrupts for sampling the EKG data, and I want to read the I2C bus whenever these interrupts come along (alongwith sampling the EKG data)
(https://www.olimex.com/Products/Duino/Shields/SHIELD-EKG-EMG/resources/ShieldEkgEmgDemo.zip)

I am now modifying the demo sketch to also collect readings on an MPU-6050, and so far, I can read the MPU-6050 (using Wire.h) in the main loop() of the program, but if I try to add it to the function called by FlexiTimer's interrupt, all serial communication fails. Any thoughts on why this might be happening, and how I could fix it?


/////////////////////////////////////////////
// Team UMAR-VARS                          //
// Arduino code for grabbing               //
// - ECG/EMG data (A0, A1)                 //
// - PPG data     (A2)                     //
// - acc data     (A5, A6) - I2C - raw     //
////////////////////////////////////////////////////////////////////////////////////////////
// Links/Credits:
// - User manual
// https://www.olimex.com/Products/Duino/Shields/SHIELD-EKG-EMG/resources/SHIELD-EKG-EMG.pdf
// - ECG code from Stan12's code (which is adapted from Olimex's sample code)
// https://www.olimex.com/forum/index.php?topic=572.0
// - MPU-6050 code from JohnChi's example sketch
////////////////////////////////////////////*BEGIN*/////////////////////////////////////////

  #include<FlexiTimer2.h>;  //http://playground.arduino.cc/Main/FlexiTimer2 for interrupts (timing)
  //#include<compat/deprecated.h>; //seems to be outdated
  #include<Wire.h>;                 //for I2C

  // MPU-6050:
      const int MPU=0x68;  // I2C address of the MPU-6050
      int i=0;
      //int16_t AcX,AcY,AcZ; //,Tmp,GyX,GyY,GyZ; 
  // ECG shield:
      volatile unsigned char CurrentCh = 0;       // Current channel being sampled.
      volatile unsigned int  ADC_Value = 0;   // ADC current value, 2 byte value (16 bits total)
      volatile unsigned char TXBuf[1+1+2*3+2*3];  // sync + packetNum + heartData + accData
      volatile unsigned char TXIndex;             // Next byte to write in the transmission packet.

  void setup() {
  // MPU-6050:   
      //do NOT place noInterrupts() here. Seems to affect I2C?
      Wire.begin();
      Wire.beginTransmission(MPU);
      Wire.write(0x6B);  // PWR_MGMT_1 register
      Wire.write(0);     // set to zero (wakes up the MPU-6050)
      Wire.endTransmission(true);
       
  // ECG shield:
      noInterrupts();  // Disable all interrupts before initialization
   
      //Packet | units?
      TXBuf[0] = 0xa5;    //Sync 0 -- could help with parsing -- unchanged for legacy
      TXBuf[1] = 0x0;     //Packet counter -- helps to see what we might miss
      TXBuf[2] = 0x02;    //ECG-1 | A0 High Byte
      TXBuf[3] = 0x00;    //ECG-1 | A0 Low Byte
      TXBuf[4] = 0x02;    //ECG-2 | A1 High Byte
      TXBuf[5] = 0x00;    //ECG-2 | A1 Low Byte
      TXBuf[6] = 0x02;    //PPG   | A2 High Byte
      TXBuf[7] = 0x00;    //PPG   | A2 Low Byte
      TXBuf[8] = 0x02;    //AccX  | I2C High Byte
      TXBuf[9] = 0x00;    //AccX  | I2C Low Byte
      TXBuf[10] = 0x02;   //AccY  | I2C High Byte
      TXBuf[11] = 0x00;   //AccY  | I2C Low Byte
      TXBuf[12] = 0x02;   //AccZ  | I2C High Byte
      TXBuf[13] = 0x00;   //AccZ  | I2C Low Byte
       
      FlexiTimer2::set(4, 1.0/1000, Timer2_Overflow_ISR); //4 units of 1 ms resolution => sampling at FS
      // FlexiTimer2::set(unsigned long units, double resolution, void (*f)())
      // E.g. units=1, resolution = 1.0/3000 will call f 3000 times per second,
      // whereas it would be called only 1500 times per second when units=2.

      //serial prints seem to freeze for certain rates. Data might still be coming through.

      FlexiTimer2::start();
      //enables the interrupt.
 
      // Serial Port
      Serial.begin(57600);       //why this baud rate? too slow vs too many errors

      interrupts();              // Enable all interrupts after initialization has been completed
  }

  void Timer2_Overflow_ISR() {
    // Serial.println("Hey!");   //use for experimenting with interrupt frequency
   
  // ECG/PPG:
    //Read the ADC channels (ECG-1, ECG-2, PPG)
    for(CurrentCh=0; CurrentCh<3; CurrentCh++) {
      ADC_Value = analogRead(CurrentCh); //first two channels reserved for I2C
      TXBuf[2*CurrentCh + 2] = ((unsigned char)((ADC_Value & 0xFF00) >> 8));// Write High Byte
      TXBuf[2*CurrentCh + 3] = ((unsigned char) (ADC_Value & 0x00FF));      // Write Low Byte
    }
    // http://arduino.cc/en/Reference/analogRead
    // 10-bit ADC, mapping input voltages 0-5V -> 0-1023 => resolution = 4.9 mV
    // The input range and resolution can be changed using analogReference().
    // It takes about (0.0001s to read an analog input =&amp;amp;amp;gt; max rate is about 10,000 Hz.
 
  // MPU-6050 (I2C routine):
    //couldn't get it to work here. Moved to void loop().
     
    //Serial.print(TXBuf[1], HEX);
    // Send Packet
    for(TXIndex=0;TXIndex<13;TXIndex++){
      Serial.write(TXBuf[TXIndex]);
    }
    Serial.println("");


    //Serial.println(TXBuf[1], HEX);
    TXBuf[1]++;                          // Increment the packet counter

  }

  void loop() {
    Wire.beginTransmission(MPU);
    Wire.write(0x3B);                    // starting with register 0x3B (ACCEL_XOUT_H)
    Wire.endTransmission(false);
    Wire.requestFrom(MPU,6,true);        // request 6 (consecutive?) registers
     
    i = 0;
    noInterrupts();                      // not sure if this is actually helping
    while(Wire.available() && i<6) {     // Reads the following 6 registers:
      TXBuf[8+i]=Wire.read();            // 0x3B (ACCEL_XOUT_H), 0x3C (ACCEL_XOUT_L)
      i++;                               // 0x3D (ACCEL_YOUT_H), 0x3E (ACCEL_YOUT_L)
    }                                    // 0x3F (ACCEL_ZOUT_H), 0x40 (ACCEL_ZOUT_L)
    interrupts();
    //delay(2);                          // occasionally helps with serial.print()

    //__asm__ __volatile__ ("sleep");
  }