Measuring Duty Cycle of Mx2125 Accelerometer Output using Interrupts

Hello,

Attempting to measure the output of the Mx2125 Accelerometer using interrupts. The Mx2125 outputs a 100 Hz PWM output signal with duty cycle proportional to acceleration. (This fact can be used to test any sketch attempting to measure duty cycle of a square wave with interrupts)

I believe my issue stems from implementing the ISR incorrectly or passing data from the main sketch to and from the ISR incorrectly.

The idea is that the ISR triggers on CHANGE (Rising or Falling Edge), then the current and previous pin state is compared to determine the direction of the change and read millis() as appropriate.

Code and datasheet below. I am using a Teensy 3.1 Much thanks

http://www.robotshop.com/media/files/PDF/memsic-2125-datasheet-28017.pdf

const int Y_Tilt  = 11;

volatile unsigned long Y_Rising ;
volatile unsigned long Y_Falling ;

unsigned long Y_Time ;

unsigned long PrintThreshold = 3;
unsigned long PrevPrintTime = 0;

unsigned long AccelDataUpdateInterval = 2;

volatile boolean CurrentState;
volatile boolean PrevState;
volatile boolean StatePrint;

unsigned long Y_RiseCopy;
unsigned long Y_FallCopy;
unsigned long deltaY;
unsigned long PrevAccelTimeCheck;

unsigned long AccelTimeCheck;
unsigned long CurrentPrintTime;  
unsigned long AccelYTime;   



void setup() 
{
  Serial.begin(9600);
  Serial.println("Tilt Test:");
  pinMode(Y_Tilt,INPUT);

  attachInterrupt(Y_Tilt,ISR_Y,CHANGE);
    
}

void loop()
{    
  AccelTimeCheck     = millis();
  CurrentPrintTime   = millis();
  AccelYTime         = micros();
  
  //Read X and Y accel Data fron Interupt
  
  if ((AccelTimeCheck - PrevAccelTimeCheck )> AccelDataUpdateInterval){
  noInterrupts();
  Y_RiseCopy = Y_Rising;
  Y_FallCopy = Y_Falling;
  StatePrint = CurrentState;
  PrevAccelTimeCheck = AccelTimeCheck;
  interrupts();
  }
  
  deltaY = Y_RiseCopy - Y_FallCopy;
  
  if ((CurrentPrintTime - PrevPrintTime ) > PrintThreshold ){
  Serial.println(Y_RiseCopy);
  Serial.println(Y_FallCopy);
  Serial.println(CurrentState);
  Serial.println("test");
  PrevPrintTime = CurrentPrintTime;
  }
}

void ISR_Y() {

  CurrentState == digitalRead(Y_Tilt);
  
  if (CurrentState == HIGH and PrevState == LOW)
  {
    Y_Rising = AccelYTime;
    PrevState = CurrentState;
    
    }
  else if (CurrentState == LOW and PrevState == HIGH)
  {
    Y_Falling = AccelYTime;
    PrevState = CurrentState;
    }
  else 
  {
    PrevState = CurrentState;
    
    }
  }

Recording millis() on a 100Hz signal means you have a resolution of about 3bit.

To get a precise measurement you should use a hardware counter which gives you a much higher resolution. But as the Teensy platform is not really an Arduino platform I cannot tell you how to do that there.

Indeed, My intention is to use micros() to yield roughly 13 bit resolution on the 100 hz signal, satisfactory for this application.

I thought micros() was implemented on a hardware counter?

I have available a Due as well.

If I switch over to the Due, I would attempt to use attatchInterupt as well.

My question hinges on passing state changes (Pin high to low) and timer values in and out of the ISR.

I know millis() and micros() may not increment in the ISR, however I should be able to read then pass along their current value to the main loop in the ISR correct?

I thought micros() was implemented on a hardware counter?

Yes it is, but forget 13bit resolution, I'd guess 10 to 11 bit resolution might be possible if the sensor is able to produce a signal of that quality.

I have available a Due as well

I don't know how the Due behaves in this regard, I never checked the code there.

I know millis() and micros() may not increment in the ISR, however I should be able to read then pass along their current value to the main loop in the ISR correct?

Yes, this is correct. The credo for ISRs is "keep it a short as ever possible" anyway. So do in the ISR on what's really necessary, do the rest in the main loop.