I need a timer interrupt to set my system clock (1 ms tick). I try any of 3 timers available - and every time some another function is damaged. My guess is that the timers are used in Serial.x() functions and in delayMicroseconds(). The former are used to communicate with my PC, the latter - with DS18B20.
Where can I find the formal description of Atmega's hardware usage in standard Arduino libraries?
Additionally, are the libraries open? Can I see a source codes?
As I can see now, Timer0 is used in millis() and micros(), but not in delayMicroseconds().
SoftwareSerial functions use delayMicroseconds().
So, my USB communications as well as DS18B20 functions are independent of the Timer0 usage. And they are not linked to Timer1 and Timer2.
It leaves my initial question: why my program goes mad when I try to use timers?
You see, I created the sketch and it works well. Now I decided to re-organize the program and added a timer interrupt subroutine. Just to try. But, any timer used, I have one or two of such effects:
Serial communication stops
DS18B20 gives wrong tesults
Program timer based on interrupts (1 ms tick) is not correct
Hmm. That looks right to me. Any improvements of you do a cli() before messing with the timer settings, and also ensure every value you write is a byte ( i.e. b00000010 instead of 0x02, TIMSK2 = (byte)(1 << OCIE2A) ?
ISR(TIMER2_OVF_vect) {
static int Millis2 = 1000;
static byte blink = 0;
TCNT2=0x06; // No way without this stupid operation!
if (--Millis2 == 0) {
Millis2 = 1000; ++Sec2; }
blink ^= 1;
digitalWrite( 13, blink);
}
and this:
// TIMSK2 = (1 << OCIE2A);
TIMSK2 = (1 << TOIE2);
Now the timing is right. But why the CTC interrupt doesn't work? Still unknown...
It's not the pure perfectionism.
When I reload Timer in my ISR - the timing is not exact. You see, the timer overflow occurs, then some time passes till CPU enters ISR and the program reload is performed. So. next overflow will happen not exactly in 1000 us after the previous.
On the contrary, hardware reload does not enlarge the time interval.
Timer1 - the same situation. Now I can formulate the main problem:
Timer0 is a sacred cow, don't use it. Now we speak only about Timer1 and Timer2.
Both Timers can be programmed to cause Interrupts:
a) Overflow Ints
b) CTC Ints.
And: Both kinds of Ints are invoked in my experiments. I make ISR with appropriate vectors, program TIMSK1 register with TOIE1 or OCIE1A bits - and I see the result (oscillogram at BLINK port and increasing of Sec counter).
But: Timers are not reseted by hardware in CTC mode! In both kinds of Ints I have to set TCNT to relevant values (~16000 or ~250 in OVF Ints or ZERO in CTC Ints).
Tried the CTC version without resetting TCNT2 in the ISR.
It is interesing that T, the millis()-value printed is the same on every line. At 9600 bps, it ought to take 1 millisecond for every character printed, so why doesn't millis advance between printed lines?
Does the timer2-interrupt come so often that the timer0-interrupts that would advance millis can't get a word in edgeways?
Tried the CTC version without resetting TCNT2 in the ISR.
And? Have you noticed the effect I'm speaking about? Without resetting TCNT2 in the ISR the interrupts are very frequent. With resetting - the value of OCR2A does not matter...
Yes, I noted the strange effect. In CTC mode, it shouldn't matter whether you reset TCNT2 or not. I suspect all the serial printing might disturb things, so I'll test by storing the timings in an array first and defer all the printing until after the timing checks are completed.
(I'm currently developing a sketch that depends on CTC working as advertised, hence my interest in this bug)
I increased prescaler to feel free inside ISR. With the frequency of counting 15625 Hz the overflow of 8-bit counter must happen once in 16.4 ms. So it is! No COMPARE and CLEAR. I have 2 proves to it:
Port 13 is toggled once in 16.4 ms
Printed 20 codes of TCNT2 show all values from 0 to 255
Besides, OCR2A = 50; does nor change anything
And when I eliminate resetting of TCNT2 in ISR - interrupts become very frequent.
I have now tried everything else I could think of:
defining a value for OCR2B as well to ensure that it will not cause any disturbing timer compare matches
writing to ASSR so we are not using external clocks
clearing out old interruptflags from TIFR2
Not doing anything to Serial, not even Serial.begin(), until all tests are finished, in case serial communication might disturb the timers.
Verifying that main() does absolutely nothing between the calls to setup() and loop()
None of those precautions helped though.
To recapitulate:
The code posted below tries to setup timer2 in CTC mode at 1000Hz and will print 21 lines with two numbers each.
The first number is millis since startup (counted by hopefully undisturbed timer0 interrupts).
The other number is the number of seconds passed, as counted by the supposedly 1000Hz timer2 interrupt.
The expected output is that the first column increases by roughly 1000 between lines, and the second column by one.
Since CTC mode means TCNT2 should auto-reset to zero on every OCR2A match/TIMER2_COMPA interrupt - why is the TCNT2 = 0 line required in the ISR for the output to look sane? Any forum gurus listening? :
#include <avr/interrupt.h>
#include <avr/io.h>
volatile int Sec2 = 0;
ISR(TIMER2_COMPA_vect) {
static int Millis2 = 1000;
static byte blink = 0;
// TCNT2 = B00000000; // Why does this matter?
if (--Millis2 == 0) {
Millis2 = 1000; ++Sec2; }
blink ^= 1;
digitalWrite( 13, blink);
}
void setup()
{
pinMode( 13, OUTPUT);
cli();
ASSR = B00000000; // make sure we use internal clocks
TCNT2 = B00000000;
OCR2A = B11111010; // 250, for 16e6 / 64 / 250 = 1000Hz interrupts
OCR2B = B11111111; // 255, so there will be no disturbing OCR2B timer compare matches
TIFR2 = B00000000; // clear flags for previous interrupts
TCCR2A= B00000010; // CTC mode, supposed to autoreset TCNT2 to 0 when it reaches OCR2A
TCCR2B= B00000100; // prescaler = 64
TIMSK2= B00000010; // Enable interrupt when Timer reaches OCR2A
sei();
}
int s2, old2 = 0;
void loop()
{
long Tarr[25];
int s2arr[25];
int stopCounter = 21;
do
{
long T = (long)millis();
s2 = Sec2; // Fix Sec2 (photo shot)
if( s2 != old2) // New second
{
old2 = s2;
--stopCounter;
Tarr[stopCounter] = T;
s2arr[stopCounter] = s2;
}
} while( stopCounter > 0);
// not using serial until now so that it couldn't possibly disturb the timers.
Serial.begin(9600);
Serial.print( "\nThe study of Interrupts\n");
Serial.print( "Timers and Ints are ready\n");
for (int i=20; i>=0; i--) {
Serial.print(Tarr[i]); Serial.print(" ");
Serial.print(s2arr[i]); Serial.print( " \n");
}
while(1) ; // Endless loop
}
You see, the Timer is set in CTC mode and it freely runs without any interrupts.
Sometimes I fetch TCNT2 and print it.
The result depends on the insane operation:
without it we see ONLY ZEROES exept the very first time. (if we make Timer to run faster, PRESCALER = 64, we will not see NOZERO even the first time).
So, the Timer starts, comes to zero and stops forever
When we put that TCNT2 = 0 on the stage - we do see several NOZEROES. Timer runs now!
By the way, prescaler matters, So try with the slowest possible frequency of Timer - prescaler 1024.
I fixed the problem with PWM phase correct mode. But it would be great to understand my mistakes with the CTC...
You say
Any forum gurus listening?
My love Deep Purple (Pictures Of Home):
Only my own words return
Nobody's up there
It's a deception
When will I ever learn?
There are more funny things in the datasheet.
E.g. 13.4.4 (page 92) says that all the bits of PINB are read-only, but 13.2.2 (page 77) says you can write to PINB to toggle outputs...
Read it again. Yes you can toggle the pins of port B BUT not through the PINB register. that register is only for reading the port pins. PORTB section 13.4.2 shows you the register to use for reading and writing.