FIXED: http://arduino.cc/forum/index.php/topic,160938.msg1204942.html#msg1204942
(OSEPP Mega 2560 R3 board)
I'm new to Arduino, so please excuse my ignorance... but, I need a bit of help or understanding on this one. I'm well versed in PIC micro controllers, though not so much in AVR's or higher-level languages. Most of my work has been in assembly, so I hope my code style doesn't offend anyone. .
I have a need to capture and manipulate an R/C servo signal (just one channel) at a stable 1us resolution. The pulseIn() is not close enough. So, being experienced in PICs, I thought I'd give the interrupts and a 16-bit timer a go...
/*
*********************************************************************
* 4/15/13 NoRoHS *
* For Mega 2560 R3 (OSEPP) - 5,950 bytes used *
* R/C signal applied to pin 21 (int.2), timer5 used *
* Results: tmr_val ='s PWM in 1us resolution (1000us to 2000us) *
*********************************************************************
*/
word tmr_val; // Captured PWM in 1us
volatile word first_tmr_val; // First timer5 read
volatile word second_tmr_val; // Second timer5 read
void setup(){
attachInterrupt(2, cap_pwm_start, RISING); // Prime interrupt looking for first PWM
pinMode(21, INPUT); // Redundant - automatically an input
TCCR5A = 0x00; // Force normal counting mode (needed... why????)
TCCR5B = 0x01; // Turn Timer5 ON (no prescaling)
Serial.begin(9600); // Start debug
}
void loop(){
while (digitalRead(21)); // Wait while incoming PWM is high
tmr_val = second_tmr_val - first_tmr_val; // Calculate captured PWM time
tmr_val = map(tmr_val,16095,31945,1005,1995); // Map PWM to 1000us-2000us (YTV Servo Cycler proofed)
Serial.println(tmr_val); // Print captured PWM value
while (!digitalRead(21)); // Wait while incoming PWM is low
}
void cap_pwm_start(){ // ISR - PWM RISING
first_tmr_val = TCNT5; // First read of timer5 (on-the-fly)
attachInterrupt(2, cap_pwm_end, FALLING); // Start looking for end of PWM
}
void cap_pwm_end(){ // ISR - PWM FALLING
second_tmr_val = TCNT5; // Second read of timer5 (on-the-fly)
attachInterrupt(2, cap_pwm_start, RISING); // Start looking for next PWM
}
I'm getting what I consider to be 99% accurate and usable data, but completely at random, I'm getting odd data values. These can be large enough to ruin the 1us accuracy I'm looking for.
I've written several interrupt driven programs trying to find a resolution and they all are showing the same problem. The code here is only one of them. I've tried (what seems like) 20 variations and countless "under the hood" debugs, like eliminating the Serial function and replacing it with an LED to indicate anomalies, I've tried battery driven to eliminate the USB, different interrupt ports, a single attachInterrupt() using the CHANGE type, using different timers, stopping the timer to read/write/clear timer data, using an R/C transmitter/receiver instead of the servo driver (Spektrum DX6i & AR6115e) and I even used my oscilloscope's calibration pulse... they all respond the same way and at the same scale - random jitter in the data. BTW, the oscilloscope's best resolution to look at the jitter from the servo driver shows no movement at all with a 5us per division setting. I believe it to be rock-steady.
This occurs on average once per second, but entirely at a random rate. They may only be a few cycles apart, or as long as several seconds apart. The following are cut/paste snippets captured from the serial monitor. The data is updated at the frame rate of every 20ms. I can get 30 to 100 (or even 200) updates clean and stable, then something like this just shows up:
Results as the program is written:
...
1534
1534
1534
1534
1534
1530 <<< Problem
1534
1534
1534
1534
1534
1534
...
Results without any mapping: (raw Timer5 data)
...
24572
24575
24574
24575
24574
24573
24573
24482 <<< Problem
24574
24575
24575
24575
24574
24577
24572
...
My best guess (if it's "under the hood") is some unknown interrupt overhead that's happening between the interrupt detection and executing the "TCNT5" reads. This I could understand, but the randomness has my head scratching.
I might just be spoiled by the rock-steady interrupts on the PIC. Should I be expecting this random error or should I do something different to steady the data?
Thanks in advance for taking the time to read all this.