Pages: [1] 2   Go Down
Author Topic: Timer interrupt not working?  (Read 1781 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 25
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't have much hair left!!!  Please put me out of my misery.  Why won't this interrupt timer work?

// Define Global Variables
volatile byte ExecutionFlag = 0;
//*****************************************************
void setup() {             
     // Conf an interrupt on Timer 1 to fire an ISR every second
  TCCR1B |= (1 << WGM12);  // Configure for CTC mode
  TCCR1B |= ((1 << CS10) | (1 << CS12)); // Prescaler @ 1024
  TIMSK1 |= (1 << OCIE1A); // Enable interrupt
  OCR1A = 15624;         // compare value = 1 sec (16MHz AVR)
  sei();     // Enable global interrupts
 
  Serial.begin(9600);
}
//*****************************************************
void loop() {
  if (ExecutionFlag){                      //  Every second ...
    digitalWrite(13, !(digitalRead(13)));  // toggle LED on Pin 13
    ExecutionFlag = 0;
  }
}
//**********************************************
ISR(TIMER1_COMPA_vect)  {
  ExecutionFlag = 1;
}



Thanks!!!
Logged

nr Bundaberg, Australia
Online Online
Tesla Member
***
Karma: 129
Posts: 8601
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I think you're setting up A then enabling B's interrupt.

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

0
Offline Offline
Newbie
*
Karma: 0
Posts: 25
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Tried that.  It is my understanding that there is only one timer 1 with two compare values/registers (please correct me if I am wrong). 
When I put a Serial.println(TCNT1) in the loop, the timer does not appear to be incrementing ...
I'm stumped.
Logged

Left Coast, USA
Offline Offline
Sr. Member
****
Karma: 7
Posts: 499
Sometimes I just can't help myself.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

...hair...
Yeah, we all have bad hair days from to time.  (Well, most of us...)

Here's the deal: You need to be taking over Timer 1.  Totally.  See Footnote.

Try the following, to make sure that that the Timer 1 registers don't have anything left over from the Arduino initialization stuff:
Code:
void setup()
{
  pinMode(13, OUTPUT);
      
  cli();                   //Disable interrupts while setting registers      
  TCCR1A = 0;              // Make sure it is zero
  TCCR1B = (1 << WGM12);   // Configure for CTC mode (Set it; don't OR stuff into it)
  TCCR1B |= ((1 << CS10) | (1 << CS12)); // Prescaler @ 1024
  TIMSK1 = (1 << OCIE1A);  // Enable interrupt
  OCR1A = 15624;           // compare value = 1 sec (16MHz AVR)
  sei();                   // Enable global interrupts
  
  Serial.begin(9600);
}

Regards,

Dave

Footnote:
The Arduino init() function is always called before your setup() function. That's the way that Arduino builds the application around your sketch.

The Arduino init() function initializes Timer 1 to be ready for PWM output operation as follows:

  • Sets bit WGM10 in TCCR1A
  • Sets bits CS11 and CS10 in TCCR1B

Bottom line:  You are taking over the timer.  You need to initialize the registers for your mode of operation.  By leaving those Timer 1 register bits set and ORing your bits into TCCR1B, the timer is definitely not operating the way you want it to.
« Last Edit: February 08, 2011, 09:17:40 am by davekw7x » Logged

Glasgow, scotland
Offline Offline
Newbie
*
Karma: 5
Posts: 42
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm kind of a nub and want to set up a timer0 interrupt every 1ms, what needs setting?

or rather, where can I read about what bits and bobs to set? 

thanks :]
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17303
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you are willing to use timer2 instead, there is already a well developed general purpose timer library avalible. I've used it to generate 2 millsec interrupts in a 5x5x5 led cube I built. Recall the arduino core functions already utilize timer0 for predefined functions like millis(), etc.

Either way you should be able to read the source code for MsTimer2 to see how they built it.

http://www.arduino.cc/playground/Main/MsTimer2

Lefty
« Last Edit: February 07, 2011, 01:36:06 pm by retrolefty » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 25
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thankyou Davekw7x!!!  You have saved what few hairs I have left.
I had to clear the cs11 bit as well but then all works great!

Does this mean that I cannot do any PWM now?  Or does this timer only control PWM on some pins?
Logged

Left Coast, USA
Offline Offline
Sr. Member
****
Karma: 7
Posts: 499
Sometimes I just can't help myself.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

...Or does this timer only control PWM on some pins?

For PWM output using Arduino analogWrite() function calls, Timer 1 is used to control ATmega pins OC1A and OC1B.  For Arduino Duemilanove, Uno, and other Arduino non-Mega boards, these are Arduino Pins 10 and 11.  Of course, you can still use Pins 10 and 11 for other things; you just can't expect to call analogWrite()s for those pins if you modify Timer 1 to operate in CTC mode.   (The other analogWrite() pins are not affected by Timer 1 settings.)


Regards,

Dave
« Last Edit: February 08, 2011, 12:58:50 pm by davekw7x » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 25
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks again Dave!
To clarify my understanding of the timer ...  timer1 is just one timer but has two compare registers/values (A & B).  Can these compare registers/values each have a different value and be used to trigger their own separate ISR in the way I have just done?

Bryan
Logged

Left Coast, USA
Offline Offline
Sr. Member
****
Karma: 7
Posts: 499
Sometimes I just can't help myself.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

...timer1 is just one timer but has two compare registers/values (A & B)

Yes.

Here are the interrupt vectors for Timer 1:
  • TIMER1_CAPT_vect           /* Timer/Counter1 Capture Event */
  • TIMER1_COMPA_vect        /* Timer/Counter1 Compare Match A */
  • TIMER1_COMPB_vect        /* Timer/Counter1 Compare Match B */
  • TIMER1_OVF_vect            /* Timer/Counter1 Overflow */


Quote from: bryanb334
in the way I have just done?
The complete reference can be found here: http://www.atmel.com/dyn/resources/prod_documents/doc8271.pdf  Chapters 15 and 16 contain EYAWTKAT1 (Everything You Always Wanted To Know About Timer 1).


Regards,

Dave
« Last Edit: February 09, 2011, 09:53:36 am by davekw7x » Logged

Glasgow, scotland
Offline Offline
Newbie
*
Karma: 5
Posts: 42
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've been fiddling around with TIMER1 , and I can't get interrupt A AND B to work at the same time.

I'm in CTC mode, timer resets when it gets to OCR1A so i set OCR1B lower of course, but still it seems to be either or.  Also tried using ICR1 (input capture) and OCR1B to no avail.

It doesn't affect me since I don't want both interrupts, I just use interrupt A and in my loop check for the OCF1B flag.

Just thought i'd mention it :]
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 25
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes, I have been having the same problem.  Can only get one interrupt to work at a time.  My thoughts are that it is in CTC (Clear on Timer Compare) mode.  So which one does the clearing?  It would seem that the lowest compare value would clear the timer so the higher value would never be reached, but it doesn't appear to be doing that.
Can anybody set me straight?
Thanks!
Logged

Glasgow, scotland
Offline Offline
Newbie
*
Karma: 5
Posts: 42
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

it's the OCR1A  that does the clearing, not B.

there IS another CTC mode that uses ICR1 as the max, but I tried that too and couldn't get two interrupts on one timer.
Logged

Global Moderator
Dallas
Online Online
Shannon Member
*****
Karma: 210
Posts: 13036
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

My thoughts are that it is in CTC (Clear on Timer Compare) mode.

Are you using the code in the first post?  Or something similar?

If "yes", then you will need to change your code to set the values of bit WGM13 and bit CS11.
Logged

Left Coast, USA
Offline Offline
Sr. Member
****
Karma: 7
Posts: 499
Sometimes I just can't help myself.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here's a way to use ICR1 to determine the count period and use OCR1A and OCR1B interrupts for times somewhere within each count cycle.

Code:
//
// Illustration of use of OCR1A and OCR1B interrupts
// with Timer 1.
// A "real" application might do something more meaningful
// than simply recording the times that the interrupts
// occur, but, this can form a framework for bigger and
// better things.
//
// Maybe.
//
// davekw7x
//
#include <avr/io.h>
#include <avr/interrupt.h>


const int LEDPIN = 13;

// I want the count period to be 1 second.  This is how long
// (in seconds) it takes the counter to reset.
const float countinterval = 1.0;

// For Arduino Uno and Duemilanove and Mega boards F_CPU = 16 MHz
const unsigned long CPU = F_CPU;

// I'll pick a large prescale divisor to allow long intervals
const unsigned long prescale = 1024;

// Round the floating point value to an integer
const unsigned count1 = (CPU * countinterval / prescale) + 0.5 - 1;

//
// For countinterval = 1 sec, the LED goes high for one second
// and low for a second.
//
// For countinterval equal to 1.0 and F_CPU equal to 16000000,
// we will get count1 = 15624
//
// That is, the result fits in a 16-bit unsigned int, as it must.
// With this scheme you can get count intervals of slightly over
// four seconds.
//
// If you want a shorter interval you can decrease,
// the prescale value to get better granularity,
// but you must always keep the size so that count1
// fits into a 16-bit integer. A more sophisticated program
// might select the optimum prescale factor based on the value
// of countinterval.
//

void setup()
{
    pinMode(LEDPIN, OUTPUT);
    digitalWrite(LEDPIN, HIGH);

    // Disable interrupts while setting registers  
    cli();

    // Make sure all is normal in TCCR1A
    TCCR1A = 0;

    // Configure timer 1 for CTC mode with TOP = ICR1A, prescale = 1024
    // For finer granularity with shorter intervals, you could use a lower
    // prescale factor
    //
    // Top is ICR1
    TCCR1B = (1<< WGM13) | (1 << WGM12) | (1<< CS12) | (1 << CS10);


    // This determines output frequency: Timer will reset when it hits this value
    ICR1   = count1;
    
    OCR1A = count1 / 3; // Make it about 1/3 of the way through the count cycle
    
    // Arithmetic can overflow an int, so do the calculation
    // with long ints and truncate the result to an int
    OCR1B = 2L*count1 / 3; // Make it about 2/3 of the way through the count cycle
    
    // Enable CTC Interrupts for count match on comparator A
    // and also for comparator B
    TIMSK1 = (1 << OCIE1B) | (1 << OCIE1A);
    // Enable global interrupts
    sei();
    
    // As a sanity check, show the register values that were obtained by
    // calculations
    Serial.begin(9600);
    Serial.print("count1 = ");Serial.println(count1);
    Serial.print("OCR1A  = ");Serial.println(OCR1A);
    Serial.print("OCR1B  = ");Serial.println(OCR1B);
}

void loop()
{
    static unsigned long oldtime;
    unsigned long newtime = get_compb1time();
    if (newtime != oldtime) {
        oldtime = newtime;
        //Serial.print(millis());
        //Serial.print(":  ");
        Serial.print(get_compa1time(), DEC);
        Serial.print("  ");
        Serial.println(newtime, DEC);
    }
}

unsigned long compa1time, compb1time; // Millisecond values for OCR matches

// Fetching a 16-bit quantity is not atomic.  If it just
// happens that a timer0 (or other) interrupt occurs when
// trying to get compa1time, it just might return
// low byte from one count and high byte from the next
// count.  This can lead to occasional gross errors in
// the count value.
// To avoid this, don't try to read compa1time from the application,
// use this function:
unsigned long get_compa1time()
{
    unsigned long t;
    byte oldSREG = SREG;

    cli();
    t = compa1time;
    SREG = oldSREG;
    return t;
}
    
// See comment preceding get_compa1time()
unsigned long get_compb1time()
{
    unsigned long t;
    byte oldSREG = SREG;

    cli();
    t = compb1time;
    SREG = oldSREG;
    return t;
}
    
ISR(TIMER1_COMPA_vect)
{
    compa1time = millis();
  
    // Two methods for writing to the LED pin.
    // Comment out one of them and uncomment the other  
    
    // Direct manipulation of Arduino Pin 13 ia
    // faster than digitalWrite
    //PINB = (1 << 5); // Toggle the LED
    
    // On the other hand, digitalWrite makes it
    // easy to use a different LEDPIN without having
    // to look up the port and bit number.
    // Local variable keeps from having to read the LED pin each time
    static byte compa1;
    digitalWrite(LEDPIN, (++compa1)&1);

}  

ISR(TIMER1_COMPB_vect)
{
    compb1time = millis();
}

Output:

count1 = 15624
OCR1A  = 5208
OCR1B  = 10416
332  665
1332  1666
2332  2665
3332  3665
4332  4666
5332  5665
6332  6666
7332  7665
8332  8666
9332  9665
10332  10665
11332  11665
12333  12665
13332  13666
14332  14665
15332  15666
16332  16665
17332  17666
18332  18665
19332  19665
20332  20666
21332  21665
.
.
.



Regards,

Dave
« Last Edit: February 17, 2011, 11:35:00 am by davekw7x » Logged

Pages: [1] 2   Go Up
Jump to: