Trouble with counter

I need a counter for an initialization sequence. I’m using Timer0, so millis() isn’t available to me. Here’s what I have right now:

unsigned long init_counter = 0;

// Inside a Timer/Counter1's ISR:
// Interrupt service routine called to generate PWM compare values
ISR(TIMER1_COMPA_vect) {
  if (init_counter < 50000)
    init_counter++;
}

void setup() {
  Serial.begin(9600);

// To debug:
void loop() {
  Serial.println(init_counter);
}

And here’s typical output:

5570660
5570659
5636195
5636195
5636195
5636195
5636195
5636195
5636195
5636194
5570658
5570658
5570658
5570658
5570658
5570658
5570658
5570658
5570651
5570651
5570651
5570651
5570651
5570651
5570651
5570651
5570653
5832797
...

Any idea why my counter is counting up? Reversing the direction (--init_counter) makes no difference.

Thanks,
Brennon

brennon:
I need a counter for an initialization sequence. I’m using Timer0, so millis() isn’t available to me. Here’s what I have right now:

unsigned long init_counter = 0;

// Inside a Timer/Counter1’s ISR:
// Interrupt service routine called to generate PWM compare values
ISR(TIMER1_COMPA_vect) {
 if (init_counter < 50000)
   init_counter++;
}

void setup() {
 Serial.begin(9600);

// To debug:
void loop() {
 Serial.println(init_counter);
}

Results:

sketch_feb05e.cpp: In function 'void setup()':
sketch_feb05e:13: error: a function-definition is not allowed here before '{' token
sketch_feb05e:15: error: expected `}' at end of input

Once I add the missing brace, my output is:

0
0
0
0
0
0
0
0
0
0
0
0

So, sorry, can’t reproduce that. Maybe copy and paste the actual code?

And don't forget to declare init_counter to be 'volatile'.

johnwasser:
And don't forget to declare init_counter to be 'volatile'.

Already tried this...doesn't change anything.

Well, I have to excerpt things–I’m not allowed to post the entirety of the program. Let me try again:

#include <stdint.h> 
#include <avr/interrupt.h> 
#include <avr/io.h> 

volatile static unsigned long init_counter = 0;

void setup() {
  
  // Disable global interrupts
  cli();
  
  // Setup Timer/Counter1 Control Registers (TCCR1) with the following options:
  //    Timer/Counter Mode of Operation  |  CTC
  //                                TOP  |  OCR1A
  //                 Update of OCR1x at  |  Immediate
  //                   TOV1 Flag Set on  |  MAX
  TCCR1A &= ~(_BV(WGM11) | _BV(WGM10)); // Clear bits WGM11 and WGM10 in TCCR1A
  TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12); // Clear bit WGM13 and set bit WGM12 in TCCR1B
  
  // Setup clock prescaler for TCCR1 as clk_IO/8
  TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS10))) | _BV(CS11);
  
  // Set compare value (OCR1A) to value equivalent to:
  //    F_CPU  = Core clock frequency
  //    PS     = This counter's prescaler value
  //    B      = Base frequency of generated waveform
  //    L      = Wavetable length
  //    C      = Timer compare value
  //    C = F_CPU / (PS * B * L)
  unsigned long ocr1a_divisor = (unsigned long) 8 * 100 * 100;
  OCR1A = F_CPU / ocr1a_divisor; // Clock Speed / Target Interrupt Frequency (4kHz)
  
  // Enable Timer/Counter1 Output Compare A Match Interrupt
  TIMSK1 |= _BV(OCIE1A);
  
  // The PWM compare-set ISR fires at 8MHz / 8 (prescaler) / OCR1A, or 25.641kHz
  // To have our init settings in place for 5 seconds, we want:
  // init_counter = (F_CPU / 8 / OCR1A) * 1;

  // Re-enable global interrupts
  sei();
  
  Serial.begin(9600);  
}

void loop() {
  while(true) {
    Serial.println(init_counter);
  }
}

// Interrupt service routine called to generate PWM compare values
ISR(TIMER1_COMPA_vect) {

  unsigned long sine_0, sine_1;
  if (init_counter < 50000)
    init_counter++;
}

Moderator edit: CODE TAGS

Very strange. I put in a 500 millisecond delay and the outputs only come out every 5 seconds. WTF?

At what rate did you want the interrupts? 4 KHz?

I notice you clear some bits in TCCR1A but leave the other bits unchanged. How do you assure that the other bits are already set as you desire?

brennon:
Well, I have to excerpt things--I'm not allowed to post the entirety of the program. Let me try again:

Cut down the sketch to a minimum sketch that demonstrates the actual problem, and post that.

PeterH:

brennon:
Well, I have to excerpt things--I'm not allowed to post the entirety of the program. Let me try again:

Cut down the sketch to a minimum sketch that demonstrates the actual problem, and post that.

Did you read the rest of that message? That's what I did...

johnwasser:
Very strange. I put in a 500 millisecond delay and the outputs only come out every 5 seconds. WTF?

At what rate did you want the interrupts? 4 KHz?

I notice you clear some bits in TCCR1A but leave the other bits unchanged. How do you assure that the other bits are already set as you desire?

Sorry about that–that comment and a couple of others were relics of old code that I missed when trimming. The other bits in those registered are initialized to zero, according to the Atmel docs, so in actuality, I don’t need to manually clear anything at all. Here’s an update:

#include <stdint.h> 
#include <avr/interrupt.h> 
#include <avr/io.h> 

volatile static unsigned long init_counter = 0;

void setup() {
  
  // Disable global interrupts
  cli();
  
  // Setup Timer/Counter1 Control Registers (TCCR1) with the following options:
  //    Timer/Counter Mode of Operation  |  CTC
  //                                TOP  |  OCR1A
  //                 Update of OCR1x at  |  Immediate
  //                   TOV1 Flag Set on  |  MAX
  TCCR1B |= _BV(WGM12); // Clear bit WGM13 and set bit WGM12 in TCCR1B
    
  TCCR1B |= _BV(CS11);  // Setup clock prescaler for TCCR1 as clk_IO/8
  
  unsigned long ocr1a_divisor = (unsigned long) 8 * 100 * 100;
  OCR1A = F_CPU / ocr1a_divisor;
  
  // Enable Timer/Counter1 Output Compare A Match Interrupt
  TIMSK1 |= _BV(OCIE1A);

  // Re-enable global interrupts
  sei();
  
  Serial.begin(9600);  
}

void loop() {
  while(true) {
    Serial.println(init_counter);
  }
}

ISR(TIMER1_COMPA_vect) {
  if (init_counter < 50000)
    init_counter++;
}

With the I/O clock running at 16MHz, OCR1A is set to 200. So, that ISR should be firing at 10kHz. (Please feel free to correct my calculation if it’s wrong.) Where were you putting the delay?

With the amended code it appears to work for me:

48265
48337
48410
48482
48555
48627
48700
48772
48844
48917
48989
49062
49134
49207
49279
49352
49424
49496
49569
49641
49714
49786
49859
49931
50000
50000
50000
50000
50000
50000
50000
50000
50000
50000
50000
50000
50000
50000
50000

That's what you are expecting, right? What board/processor are you using?

And does the amended code, posted above, behave differently for you?

I just tried the amended code and it seems to work correctly now for me, too.

Perhaps a comparison between the two would point to the problem.