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 (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;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");
}