I have a periodic timer ISR that once in a while increments an error counter (up to 10 increments per ISR invocation). This is the only interrupt in my program, I disabled everything else to reduce interrupt jitter. There are at least 200 16Mhz clock cycles interval between successive interrupts. I would like to read this counter from the main program without disabling interrupts (again, to reduce interrupt jitter).
uint16_t reads are not atomic, right? If so, what is a reasonable way to do so without disabling interrupts? For example, is this safe and reasonable?
The price will be that reasoning on the correctness of the program will be more difficult and error pone. The spec of the read_count() function for example will say 'may or may not return the correct value' and this uncertainty will propagate to the rest of the program, adding complexity which I want to avoid.
These are the accesses to the counter:
Reset during initialization in setup(). I can wrap this one with interrupts off. No interrupt jitter issues during initialization.
Timer 2 ISR may increment this a few times at most. The ISR is triggered at about 20Khz.
Main program (that is, from loop()) reads the counter, not more than once per loop() iteration. This is the access I want to have with interrupts enabled. It will compute diff from previous reading so should handle counter overflow with no problem.
No matter how you try and do it, an atomic read cannot be done in less clock cycles than a normal read, since the ATmegas are only 8-bit processors. That means that, for a short period of time, access to the variable must be disabled so that only one thing can change it at once. This means that there is a period of time where the interrupt cannot access the variable, and must be disabled. This will cause interrupt jitter, and is unavoidable.
What are your trying to do that is so jitter-sensitive?
[quote author=Coding Badly link=topic=208149.msg1530731#msg1530731 date=1388714295] @zapta, what price do you pay if read_counter fails to return the correct value of counter?
The price will be that reasoning on the correctness of the program will be more difficult and error pone. The spec of the read_count() function for example will say 'may or may not return the correct value' and this uncertainty will propagate to the rest of the program, adding complexity which I want to avoid.[/quote]
Right. And when that uncertainty propagates to the rest of the program what happens? Wrong value displayed on an LCD? Thermonuclear reaction?
Does this counter really need to have more than 8 bits?
If this counter increases by no more than 10 each time through loop(), then why not just have the counter be 8 bits, and have loop() check for overflow?
odometer:
Does this counter really need to have more than 8 bits?
If this counter increases by no more than 10 each time through loop(), then why not just have the counter be 8 bits, and have loop() check for overflow?
I am trying to relax the timing requirements loop() max iteration time.
Twice I have tried to get you to answer a very basic question about your application. Twice you have answered, instead, about your state of mind. If you won't provide a reasonable answer then I have no choice but to give up. You will have to take PaulS's advice and disable interrupts or odometer's advice and use a byte-sized datatype.
Badly, with all the respect, you are avoiding answering my original question, how to transfer correctly a counter value from the ISR to main, without disabling interrupts. I even posted a proposed code snippet and asked for critique.
Instead you keep asking me to analyze what will happen in any future program that will use the library I am writing if this API function will return incorrect values, That's a different topic. My question is about how to have correct code.
Any comment on the code snippet I posted? Is there any hole I am missing?
Or if you really need atomic 16-bit support, go up to an ARM processor like the Teensy 3.0/3.1, Arduino Due, DigiX, etc. The AVR chips only process data 8-bits at a time.
Um... wrong. You need to cast high before shifting it so far left.
Actually the code works as is. Most processors are not internally 8 bit and compilers will, by default, upcast to the native word size for speed reasons. But to be pedantic then yes we should cast first, or we could define high and low as uint16 and handle casting in the comparison operators.
zapta:
Badly, with all the respect, you are avoiding answering my original question...
Bullshit...
uint16_t reads are not atomic, right?
PaulS gave you the correct direct answer. There is nothing more I can offer.
If so, what is a reasonable way to do so without disabling interrupts?
"Reasonable" is a subjective term. What is reasonable to PaulS may be different than what is reasonable to me which may be different than what is reasonable to you. The only way to answer that question is for you to define "reasonable". Something I was trying to help you do.