I'm using timer 1 to switch on a LED then trigger timer 2 to switch it off again after a certain elapsed period. In reality, it is much more complicated that that but I have reduced the core problem to this for demonstration purposes.
It appears to fail with at least 2 prescaler settings, that is /256 and /1024 of timer 2. With some lower prescaler settings, it functions OK. The failure case is that the timer 2 ISR is never entered with these higher prescaler values. Obviously, when the prescaler division value is increased, the compare output value (OCR2A) must be reduced correspondingly to maintain the same period and clearly the timer2 ISR must have completed before the next cycle of timer1.
So timer1 runs with a 4ms period and sets up timer2 for a 1ms period. This works if the prescaler is /128 and OCR2A is set to ~62 and the ISR is called correctly. I've chosen 1ms to be well within the 4ms period of timer1 so there is no clash. If, however, I select a prescaler of /256 and an OCR2A value of 31 then it fails in that the ISR is never entered although the elapsed time period should be the same.
I'm probably missing something very basic. Here is the code sample. For anyone who wishes to try it, simply swap the comments on the three marked lines in the timer 1 ISR.
const uint8_t led = 13 ; // was 13
volatile uint32_t isrEntered = 0 ;
ISR(TIMER2_COMPA_vect) {
// switches led off and terminates itself.
TCCR2B = 0 ; // stop timer 2
digitalWrite( led , LOW ) ;
isrEntered++ ;
}
ISR(TIMER1_COMPA_vect) {
// runs every 4 ms
// set up timer2 to trigger its ISR after a defined period
TCCR2A = WGM21 ; // CTC
/* this fails */
/*
OCR2A = 31 ; // 62 = ~1ms with ps = /256
TCNT2 = 0 ;
TCCR2B = (1 << CS21) | (1 << CS22) ; // prescaler /256
*/
/* this works */
OCR2A = 62 ; // 62 = ~1ms with ps = /256
TCNT2 = 0 ;
TCCR2B = (1 << CS20) | (1 << CS22) ; // prescaler /128
digitalWrite( led , HIGH ) ;
}
void setup() {
Serial.begin( 115200 ) ;
pinMode( led, OUTPUT ) ;
//deep clean timer 2
TCCR2A = 0 ;
TCCR2B = 0 ;
TCNT2 = 0;
// timer2 set up - but started by timer1
TCCR2A = WGM21 ; // CTC
OCR2A = 255 ;
TIMSK2 = (1 << OCIE2A); // enable interrupts
//deep clean timer 1
TCCR1A = 0 ;
TCCR1B = 0 ;
TCNT1 = 0;
// timer1 setup CTC, 4ms Period, interrupts
TCCR1B = (1 << WGM12) | (1 << CS12) ; // CTC ps= /256
OCR1A = 250 ; // 4ms with ps= /256
TIMSK1 = (1 << OCIE1A); // enable interrupts
}
void loop() {
static uint32_t lastRunAtMs = 0 ;
if ( millis() - lastRunAtMs > 1000 ) { // 1 seconds
noInterrupts() ;
uint32_t isrEnteredCopy = isrEntered ;
isrEntered = 0 ;
interrupts() ;
Serial.print( "Timer 2 ISR entered in this timeslice = " ) ;
Serial.println( isrEnteredCopy ) ;
lastRunAtMs = millis() ;
}
}
I observe few anomalies in your codes (the codes does not agree with description) which I wish to pinpoint based on the answers of the following queries: (When I run your corrected sketch with TCCR2A = 1 << WGM21, I see no activity (ON/OFF) of L; however, there is this message: "Timer 2 ISR entered in this timeslice = 250" on the Serial Monitor.)
1. You want to run TC1 at 250 Hz (4 ms period) CTC Mode-4. Correct? 2. When Compared Match occurs for TC1, you want to turn on L (built-in LED of Arduino). Correct?
3. When Compared Match occurs for TC1, you want to turn on TC2 at 1000 Hz (1 ms period) CTC Mode-4 (Fig-1). Correct?
Figure-1:
4. Once TC2 has started, then how long you want to wait before turning off L?
Once TC2 has started by TC1, after that TC1 and TC2 are not synchronized. They are totally free-running square wave oscillators.
Let TC1 allow to turn on L at it first compare match interrupt and also to turn on TC2. Let allow TC2 to be running for 1-sec and then allow TC2 to turn off L during its last clock cycle.
The OP says that the LED will go off after certain amount of time; but, the LED is not going OFF. Therefore, I can always bring this incident to the kind attention of the OP. It is up to him to care it or not!
There is RONG calculation in the above for OCR1A: 1. For 4 ms period, the frequency is: 250 Hz (1000/4). 2. Therefore, the value of OCR1A is 124 and not 250 with prescaler 256!
The above calculation is also RONG!
For exactly 1 ms period of the CTC wave, the value of prescaler (N ) and OCR2A should
64 and 124 respectively and not 128 and 62?
With N = 128 and OCR2A = 62, we get the following fractional frequency which is no good!
f = 992.06 Hz
Note: There is a good chance for two waves to remain in synchronism and locked if one is multiples of the other.
Thanks once again to all for for looking into this. @GolamMostafa
OK. Thanks for the additional detailed analysis and discussion of the code sample provided in the OP. Obviously it was a basic error resulting in a timer overrun because the wave mode erroneously selected did not respect the selected match value in OCR2A. However, that code was lifted out of a much larger development and then prepared as a minimal example which demonstrates the main problem and ,hence, some of the comments may not have been well maintained to reflect later changes in the code. I'm sorry if these were a distraction.
It will be used to adjust the brightness of a vacuum fluorescent display which is multiplexed at ~4ms (that is approximately). Some time into the ~4ms period, depending on the output of an LDR, the display will be blanked and that is the purpose of starting a second timer. It is not a high precision application.
There may also be other ways of achieving the same thing, even with just one timer, but this ( now ) appears to work as intended.
@DrDiettrich
I guess the data sheets are rather prone to such copy paste type errors probably because when these are updated, say to reflect new corporate identity standards such as new layouts, fonts, colours etc., the work is done not by engineers but by office assistants.
Not visible. To make it visible, the timing and frequency of the signals needs to be adjusted. If I could know how much later the LED will go OFF, I would try to adjust the codes to make the LED's activity visible.