Comparator output mucking up "HIGH" byte in 16-bit timers in Input Capture Mode

This is a really bizarre problem I've been having. I have 3 16-bit timers setup in input capture mode. Whenever these are triggered via my comparator, the HIGH byte in the counts (TCNT1H, TCNT4H, and TCNT5H) becomes mucked up (erroneously un-synchronized with the other counters). What is odd is that the lower byte remains in sync so this probably is not a "noise" problem (I think). I will be attaching an O-Scope here soon to evaluate the output more.

My code for my timer setup (which generally follows AVR130) is listed in this post here: Should I outsource my counting to something external? Micros is too slow. - #56 by system - Project Guidance - Arduino Forum

Here is the code I've written that momentarily stops the timers so that I can read them and transmit their values (and then resyncs the timers) to the computer for troubleshooting:

...
			case 0xCC:		//204 checks timer synchronization
				//stop the timers to get a reading of their current value
				GTCCR = (1<<TSM)|(1<<PSRSYNC);
				Serial.write(TCNT1H);
				Serial.write(TCNT1L);
				Serial.write(TCNT4H);
				Serial.write(TCNT4L);
				Serial.write(TCNT5H);
				Serial.write(TCNT5L);
				GTCCR = 0;	//continue counting
...

Here is the circuit that drives my input capture pins. The LM224 is used as an active low-pass filter that converts my PWM input to a ~DC voltage for the comparator (LM393). I've added some headers that are used with SHUNTS to bypass the comparator stage and take my input signal right into the input capture pin.

There are three circuits that look just like this. The output "TIMERn_INPUT_CAPTURE" is tied to the corresponding input capture pins on the ATMega 2560.

I've tied all the CHn_SIGNAL pins to a stimulus pin so that I can examine my checkout code. In reality the CH1_SIGNAL comes from a different source (in my application its the emitter side of a PhotoTransistor component but I've eliminated that input as being the problem).

With J# set to bypass this comparator circuit, the counts stay perfectly inline and the input capture values are reasonable (sometimes a few clicks off from one another, but I suspect that much with them running at 16MHz with no noise rejection enabled). Here is an image of the output to my computer from the controller that shows that the counts are matching:

Now when I re-enable my comparator and run the same code, the HIGH bytes becomes un-syncronized. What is odd is that my LOW bytes stay perfectly in sync!

Here is an example of what I get when I enable my comparator circuit (in this one only TCNT4H is off, but I've seen TCNT5H off before as well, relative to TCNT1H):

One note (not sure how it is related): Yesterday afternoon when I was troubleshooting this circuit/software it was warmer (~78 deg F) and the HIGH values were very off. This morning when I came in and went back into troubleshooting it was a little cooler (~72 deg F) and I noticed that the problem still exists, but the amount that the HIGH byte was off was only by 1 or 2 and not by 100+. Not sure if is related...

Thanks for any of your input. I highly appreciate it.

-Nic

Here is the output from my 3 comparators using an O-Scope. The signal looks fine to me. I'm beginning to suspect that my PWM outputs have something to do with this. I specifically avoided the PWM outputs that were tied to TIMER1, 4 and 5 to avoid conflicts.

When I turned my PWM output to MAX, the problem seems to go away, however, simply adjusting the value seems to cause all the "H" registers to become out-of-sync. Lowering the PWM to a value <255 (lets say at 150) and I start getting weird "H" register problems. Whats especially odd about this is that the PWMs are running even when I change the shunt-jumper to bypass the comparators and I don't have any problems.

  • By-Pass the comparators, change the PWM values around = No problem what-so-ever. The timers all stay in-sync.
  • Use the comparators, change the PWM values all to 255, re-sync the timers. The timers all appear to stay in-sync.
  • Use the comparators, change the PWM values to <255, re-sync the timers. The HIGH byte of the timers becomes out-of-sync.

Here is my o-scope image of my comparator outputs:

I suspect it has something to do with the PWMs given this but I'm not sure how they are related exactly. If Bypassing the comparator and messing with the PWM values resulted in spurious counts in the HIGH byte then it would be more clear... but it is not.

Thanks again for any input you can provide.

I guess you're searching in the wrong corner. Have you read section 17.3 of the ATmega2560 datasheet?

For a 16-bit read, the low byte must be read before the high byte.

You're doing it the other way around and therefore it may return an old value for the high byte.

What pylon said plus... If you access the counts using the 16 bit register name (e.g. TCNT1), the compiler will order the reads for you.

Wow, I can't believe that worked but it has. I thought that the line:

GTCCR = (1<<TSM)|(1<<PSRSYNC);

effectively stopped the timers. I mean, how else would I be reading them individually 1-by-1 and have them all the same value unless the timers were effectively stopped. I understand why you would read the low byte first and the high byte second if the timers were still counting but the fact that the read order made a difference with them stopped is very puzzling to me.

I'm not 100% convinced yet, and will continue my checkouts but that solution seems to have worked. Thanks!

So far so good. Thanks guys. I guess I had a 50/50 shot at getting it right and I failed :(. Still not really sure I understand "WHY" reading the low byte first and the high byte second matters when the timers are not counting but apparently it does.

Still not really sure I understand "WHY" reading the low byte first and the high byte second matters when the timers are not counting but apparently it does.

Did you read the section in the datasheet I mentioned? It states that an internal temporary register is shared among all 16 bit registers and that you might get such strange results if you read the two bytes in the wrong order. If you use the low level stuff, get used to reading the datasheet in detail :).