In the thread above about RS485 driver enable, always originated by me, some new and interesting (for me) techniques has been descripted to use a "wide" (32- or 64-bits) hardware up/down counter to read effectively without disabling interrupts, as I usually have done in the past.
If the processor supports native hardware 32-bits counter, the problem doesn't exist: most probably it can be read atomically. Most probably there are some 8-bits architectures where it's possible to read atomically a 32-bits counter, but they are exceptions.
Suppose to have a poor 8-bits micro with only 8-bits counters. I want to extend it to 32-bits, starting from the suggestions by Wouter van Ooijen/Don Y:
h1 = read_high(); >l1 = read_low(); >h2 = read_high(); >if h1 == h2 return ( h1, l1 ) else return ( h2, 0 )
and David Brown:
On an 8-bit system with 64-bit counters, the "read_high" >should read the upper 56 bits, and the "read_low" reads the low >8-bit (or use a 48-bit/16-bit split if you can do an atomic 16-bit >read of the counter hardware, which IIRC is possible on an AVR).
When the 8-bits counter wraps-around, the relative ISR is called and the upper 24-bits are incremented:
volatile uint32_t counter_high = 0; Timer/Counter ISR: counter_high += 0x10;
To read the 32-bits value, without disabling interrupts, I can use (I'm assuming the compiler have a native support of uint32_t):
uint32_t read_counter(void) { uint32_t h1 = counter_high; uint8_t l = COUNTER_REGISTER; /* Atomic operation */ uint32_t h2 = counter_high; return h1 == h2 ? h1 + l : h2; }
Now a generic "software" timer can be set and checked in the following way:
typedef uint32_t Timer; void TimerSet(Timer *tmr, uint32_t delay) { *tmr = read_counter() + delay; } bool_t TimerExpired(Timer *tmr) { return (read_counter() - *tmr) *tmr; }