Hello !
A new strange behavior with a Nano.
My goal is to reach 1 micro second with the Timer1.
That works, but if i try to read millis(), it returns 0 !
Is someone can help me to understand this ?
//===============================================================================================================
// ARDUINO
//===============================================================================================================
#include <wiring.c>
//---------------------------------------------------------------------------------------------------------------
void initTimer() {
sei();
#if defined(TCCR0A) && defined(WGM01)
sbi(TCCR0A, WGM01);
sbi(TCCR0A, WGM00);
#endif
// set timer 0 prescale factor to 64
#if defined(TCCR0B) && defined(CS01) && defined(CS00)
// this combination is for the standard 168/328/1280/2560
sbi(TCCR0B, CS01);
sbi(TCCR0B, CS00);
#else
#error Timer 0 prescale factor 64 not set correctly
#endif
// enable timer 0 overflow interrupt
#if defined(TIMSK) && defined(TOIE0)
sbi(TIMSK, TOIE0);
#elif defined(TIMSK0) && defined(TOIE0)
sbi(TIMSK0, TOIE0);
#else
#error Timer 0 overflow interrupt not set correctly
#endif
}
//---------------------------------------------------------------------------------------------------------------
//#define TIMER1_COUNTER 49536 // = 65536-16MHz/ 1/ 1kHz --> 16000 / 1000µs // works
//#define TIMER1_COUNTER 63936 // = 65536-16MHz/ 1/ 10kHz --> 1600 / 100µs // works
//#define TIMER1_COUNTER 65376 // = 65536-16MHz/ 1/ 100kHz --> 160 / 10µs // works
//#define TIMER1_COUNTER 65456 // = 65536-16MHz/ 1/ 200kHz --> 80 / 5µs // works
//#define TIMER1_COUNTER 65472 // = 65536-16MHz/ 1/ 250kHz --> 64 / 4µs // works
//#define TIMER1_COUNTER 65504 // = 65536-16MHz/ 1/ 500kHz --> 32 / 2µs // works
//#define TIMER1_COUNTER 65510 // = 65536-16MHz/ 1/ 615Hz --> 26 / 1.625µs // works
//#define TIMER1_COUNTER 65515 // = 65536-16MHz/ 1/ 762kHz --> 21 /1.3125µs // works
//#define TIMER1_COUNTER 65516 // = 65536-16MHz/ 1/ 800kHz --> 20 / 1.25µs // works
#define TIMER1_COUNTER 65517 // = 65536-16MHz/ 1/ 842kHz --> 19 /1.1875µs // ISSUE !!!
//#define TIMER1_COUNTER 65518 // = 65536-16MHz/ 1/ 889kHz --> 18 /1.1250µs // ISSUE !!!
//#define TIMER1_COUNTER 65519 // = 65536-16MHz/ 1/ 941kHz --> 17 /1.0625µs // ISSUE !!!
//#define TIMER1_COUNTER 65520 // = 65536-16MHz/ 1/ 1MHz --> 16 / 1µs // ISSUE !!! --> My target
volatile uint32_t tickms = 0;
//---------------------------------------------------------------------------------------------------------------
void myIRQTimer() {
noInterrupts(); // disable all interrupts
TCCR1A = 0; // initialize timer1
TCCR1B = (1 << CS10); // 1 prescaler
TCNT1 = TIMER1_COUNTER; // preload timer
TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt
interrupts(); // enable all interrupts
}
//---------------------------------------------------------------------------------------------------------------
ISR(TIMER1_OVF_vect) { // interrupt service routine
tickms++;
TCNT1 = TIMER1_COUNTER; // preload timer
}
//---------------------------------------------------------------------------------------------------------------
int main () {
initTimer(); // Start only with Timer0
myIRQTimer(); // Configure Timer1
Serial.begin(115200);
Serial.print(F("Timer1 Bug ?\n"));
for (;;) { Serial.println(millis()); }
}
//---------------------------------------------------------------------------------------------------------------
Thanks for your help.
Patrick
That's because you are using a main() function. This not only bypasses loop() and setup(), but also ANY initialization. Aka, also any initialization of Timer0 for millis().
PS, don't forget to disable interrupts when reading tickms or you might be in for some random surprises 
Hello septillion,
No no i've already check with setup() and loop() functions instead of main() and still the same behavior, exactly the same.
void setup() {
myIRQTimer(); // Configure Timer1
Serial.begin(115200);
Serial.print(F("Timer1 Bug ?\n"));
}
void loop() {
Serial.println(millis());
}
Another idea ?
Please post complete programs only. Not only is it you with a question (so why give use, the volunteers, the job of copy-pasting), it also reduces the change of error because we end up with slightly different code.
Hi, as requested :
So, when i compile with timer1 from 65517 to 65520 (and more i guess), millis() return 0.
Below, it works correctly.
Is anyone can help me to understand this behavior ?
Patrick
//===============================================================================================================
// ARDUINO
//===============================================================================================================
//#define TIMER1_COUNTER 49536 // = 65536-16MHz/ 1/ 1kHz --> 16000 / 1000µs // works
//#define TIMER1_COUNTER 63936 // = 65536-16MHz/ 1/ 10kHz --> 1600 / 100µs // works
//#define TIMER1_COUNTER 65376 // = 65536-16MHz/ 1/ 100kHz --> 160 / 10µs // works
//#define TIMER1_COUNTER 65456 // = 65536-16MHz/ 1/ 200kHz --> 80 / 5µs // works
//#define TIMER1_COUNTER 65472 // = 65536-16MHz/ 1/ 250kHz --> 64 / 4µs // works
//#define TIMER1_COUNTER 65504 // = 65536-16MHz/ 1/ 500kHz --> 32 / 2µs // works
//#define TIMER1_COUNTER 65510 // = 65536-16MHz/ 1/ 615Hz --> 26 / 1.625µs // works
//#define TIMER1_COUNTER 65515 // = 65536-16MHz/ 1/ 762kHz --> 21 /1.3125µs // works
//#define TIMER1_COUNTER 65516 // = 65536-16MHz/ 1/ 800kHz --> 20 / 1.25µs // works
#define TIMER1_COUNTER 65517 // = 65536-16MHz/ 1/ 842kHz --> 19 /1.1875µs // ISSUE !!!
//#define TIMER1_COUNTER 65518 // = 65536-16MHz/ 1/ 889kHz --> 18 /1.1250µs // ISSUE !!!
//#define TIMER1_COUNTER 65519 // = 65536-16MHz/ 1/ 941kHz --> 17 /1.0625µs // ISSUE !!!
//#define TIMER1_COUNTER 65520 // = 65536-16MHz/ 1/ 1MHz --> 16 / 1µs // ISSUE !!! --> My target
volatile uint32_t tickms = 0;
//---------------------------------------------------------------------------------------------------------------
void myIRQTimer() {
noInterrupts(); // disable all interrupts
TCCR1A = 0; // initialize timer1
TCCR1B = (1 << CS10); // 1 prescaler
TCNT1 = TIMER1_COUNTER; // preload timer
TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt
interrupts(); // enable all interrupts
}
//---------------------------------------------------------------------------------------------------------------
ISR(TIMER1_OVF_vect) { // interrupt service routine
tickms++;
TCNT1 = TIMER1_COUNTER; // preload timer
}
//---------------------------------------------------------------------------------------------------------------
void setup() {
myIRQTimer(); // Configure Timer1
Serial.begin(115200);
Serial.print(F("Timer1 Bug ?\n"));
}
void loop() {
Serial.println(millis());
}
//---------------------------------------------------------------------------------------------------------------
I think that the high frequency Timer1 interrupts are blocking the Timer0 interrupt to advance the millis(). I don't fully understand the interrupt latency, and why the Serial print is actually working as well, but if you make the Timer1 OVF ISR slightly shorter, by typing tickms uint16_t, millis() is running. If you comment the tickms++ out of the ISR the code also works at full speed.
//===============================================================================================================
// ARDUINO
//===============================================================================================================
//#define TIMER1_COUNTER 49536 // = 65536-16MHz/ 1/ 1kHz --> 16000 / 1000µs // works
//#define TIMER1_COUNTER 63936 // = 65536-16MHz/ 1/ 10kHz --> 1600 / 100µs // works
//#define TIMER1_COUNTER 65376 // = 65536-16MHz/ 1/ 100kHz --> 160 / 10µs // works
//#define TIMER1_COUNTER 65456 // = 65536-16MHz/ 1/ 200kHz --> 80 / 5µs // works
//#define TIMER1_COUNTER 65472 // = 65536-16MHz/ 1/ 250kHz --> 64 / 4µs // works
//#define TIMER1_COUNTER 65504 // = 65536-16MHz/ 1/ 500kHz --> 32 / 2µs // works
//#define TIMER1_COUNTER 65510 // = 65536-16MHz/ 1/ 615Hz --> 26 / 1.625µs // works
//#define TIMER1_COUNTER 65515 // = 65536-16MHz/ 1/ 762kHz --> 21 /1.3125µs // works
//#define TIMER1_COUNTER 65516 // = 65536-16MHz/ 1/ 800kHz --> 20 / 1.25µs // works
//#define TIMER1_COUNTER 65517 // = 65536-16MHz/ 1/ 842kHz --> 19 /1.1875µs // ISSUE !!!
//#define TIMER1_COUNTER 65518 // = 65536-16MHz/ 1/ 889kHz --> 18 /1.1250µs // ISSUE !!!
//#define TIMER1_COUNTER 65519 // = 65536-16MHz/ 1/ 941kHz --> 17 /1.0625µs // ISSUE !!!
#define TIMER1_COUNTER 65520 // = 65536-16MHz/ 1/ 1MHz --> 16 / 1µs // ISSUE !!! --> My target
//volatile uint32_t tickms = 0;
volatile uint16_t tickms = 0;
//---------------------------------------------------------------------------------------------------------------
void myIRQTimer() {
noInterrupts(); // disable all interrupts
TCCR1A = 0; // initialize timer1
TCCR1B = (1 << CS10); // 1 prescaler
TCNT1 = TIMER1_COUNTER; // preload timer
TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt
interrupts(); // enable all interrupts
}
//---------------------------------------------------------------------------------------------------------------
ISR(TIMER1_OVF_vect) { // interrupt service routine
tickms++;//ifthis is commented it also runs at top speed
TCNT1 = TIMER1_COUNTER; // preload timer
}
//---------------------------------------------------------------------------------------------------------------
void setup() {
myIRQTimer(); // Configure Timer1
Serial.begin(115200);
Serial.print(F("Timer1 Bug ?\n"));
}
void loop() {
Serial.println(millis());
}
//---------------------------------------------------------------------------------------------------------------
Hi Cattledog,
Thanks to spend a few your time to test really my code and for your workaround.
So, for my software, i'll remove tickms completly and will use millis() - or micros() - and that should be great.
Again a big thanks for your help.
Patrick
BRIOT_Patrick:
Hello !
A new strange behavior with a Nano.
My goal is to reach 1 micro second with the Timer1.
That works, but if i try to read millis(), it returns 0 !
I know this has already been solved, but I am curious, if you have achieved a perfect microsecond that does not drift and is interrupt driven, why have a second timer dedicated to essentially the same function? Why not set up a millis()-esque function that is not interrupt-driven, but also does not drift and is based on your new micros function?
Perehama:
I know this has already been solved, but I am curious, if you have achieved a perfect microsecond that does not drift and is interrupt driven, why have a second timer dedicated to essentially the same function? Why not set up a millis()-esque function that is not interrupt-driven, but also does not drift and is based on your new micros function?
Hello,
It's because in my final software a program run continiously to emulate another old 8bits processor and i need to sampling sound to a loud speaker with a custom analog output.
Hello all !
This morning i was a little frustrated and so i've searched deeper to find a solution.
And i found one !
I don't understand why i need to re-activate the interrupt explicitly, but that is the solution.
If someone can explain it would be perfect.
However, the corrected code below :
//===============================================================================================================
// ARDUINO
//===============================================================================================================
#include <wiring.c>
//---------------------------------------------------------------------------------------------------------------
void initTimer() {
sei();
#if defined(TCCR0A) && defined(WGM01)
sbi(TCCR0A, WGM01);
sbi(TCCR0A, WGM00);
#endif
// set timer 0 prescale factor to 64
#if defined(TCCR0B) && defined(CS01) && defined(CS00)
// this combination is for the standard 168/328/1280/2560
sbi(TCCR0B, CS01);
sbi(TCCR0B, CS00);
#else
#error Timer 0 prescale factor 64 not set correctly
#endif
// enable timer 0 overflow interrupt
#if defined(TIMSK) && defined(TOIE0)
sbi(TIMSK, TOIE0);
#elif defined(TIMSK0) && defined(TOIE0)
sbi(TIMSK0, TOIE0);
#else
#error Timer 0 overflow interrupt not set correctly
#endif
}
//---------------------------------------------------------------------------------------------------------------
//#define TIMER1_COUNTER 49536 // = 65536-16MHz/ 1/ 1kHz --> 16000 / 1000µs // works
//#define TIMER1_COUNTER 63936 // = 65536-16MHz/ 1/ 10kHz --> 1600 / 100µs // works
//#define TIMER1_COUNTER 65376 // = 65536-16MHz/ 1/ 100kHz --> 160 / 10µs // works
//#define TIMER1_COUNTER 65456 // = 65536-16MHz/ 1/ 200kHz --> 80 / 5µs // works
//#define TIMER1_COUNTER 65472 // = 65536-16MHz/ 1/ 250kHz --> 64 / 4µs // works
//#define TIMER1_COUNTER 65504 // = 65536-16MHz/ 1/ 500kHz --> 32 / 2µs // works
//#define TIMER1_COUNTER 65510 // = 65536-16MHz/ 1/ 615Hz --> 26 / 1.625µs // works
//#define TIMER1_COUNTER 65515 // = 65536-16MHz/ 1/ 762kHz --> 21 /1.3125µs // works
//#define TIMER1_COUNTER 65516 // = 65536-16MHz/ 1/ 800kHz --> 20 / 1.25µs // works
//#define TIMER1_COUNTER 65517 // = 65536-16MHz/ 1/ 842kHz --> 19 /1.1875µs // ISSUE !!!
//#define TIMER1_COUNTER 65518 // = 65536-16MHz/ 1/ 889kHz --> 18 /1.1250µs // ISSUE !!!
//#define TIMER1_COUNTER 65519 // = 65536-16MHz/ 1/ 941kHz --> 17 /1.0625µs // ISSUE !!!
#define TIMER1_COUNTER 65520 // = 65536-16MHz/ 1/ 1MHz --> 16 / 1µs // ISSUE !!! --> My target
volatile uint32_t tickms = 0;
//---------------------------------------------------------------------------------------------------------------
void myIRQTimer() {
TCCR1A = 0; // initialize timer1
TCCR1B = 0; // stop the timer1
TIFR1 |= (1 << TOV1); // clear the overflow interrupt flag by writing 1 to it
TCNT1 = TIMER1_COUNTER; // preload timer
TCCR1B |= (1 << CS10); // 1 prescaler
TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt
}
//---------------------------------------------------------------------------------------------------------------
ISR(TIMER1_OVF_vect) { // interrupt service routine
tickms++;
TCNT1 = TIMER1_COUNTER; // preload timer
sei(); // <=== THIS has solved the issue !!!!!
}
//---------------------------------------------------------------------------------------------------------------
int main () {
initTimer(); // Start only with Timer0
myIRQTimer(); // Configure Timer1
Serial.begin(115200);
Serial.print(F("Timer1 Bug ?\n"));
for (;;) {
Serial.println(millis());
}
}
//---------------------------------------------------------------------------------------------------------------
And by the way, that works too with setup() and loop() ! 
I don't understand why i need to re-activate the interrupt explicitly, but that is the solution.
If someone can explain it would be perfect.
I think you are fooling yourself, and the fact that millis() values prints does not mean that they are accurate, that Timer0 overflow interrupts are properly executed, and that the microsecond tickms count is accurate.
The time taken to enter and exit an interrupt is on the order of 2.625 microseconds. See the discussion of interrupt latency in Nick Gammon's tutorial on interrupts.
https://gammon.com.au/interrupts
If you just focus on the entry latency of 1.4375 us you will see that by the time you set the TCNT1 value up near the top for the next microsecond tick, the microsecond has already passed.
If you reenable the interrupts within the ISR you may be reducing some of the exit latency, but overall, the interrupt entry and execution are longer than the next microsecond.
The AT328 is just not fast enough to have a Timer interrupt based 1 us tick.
Clearly, i was wrong.
Thank you Cattledog for these clarifications and the interesting link to read.
Now i need to find a solution to work on my emulation to sampling sound maybe with 2us.
I need to do some tests.
Patrick
BRIOT_Patrick:
Hello,
It's because in my final software a program run continiously to emulate another old 8bits processor and i need to sampling sound to a loud speaker with a custom analog output.
You should elaborate more on this, because so far this whole thread has been solving solving for Y instead of X. Cattledog has already posted that it takes longer than a microsecond to enter the interrupt. If you go for 2 microseconds, all you will be able to do is enter and exit the interrupt, maybe. micros() is already quite accurate to a resolution of 4 microseconds. The older 8-bit chip would likely also not be faster or more efficient in code than the ATmega328P. So, what are you really wanting to do?