High speed counting glitches

Hey all, I'm trying to prototype a capacitive touch array and my clock-interrupt cycle seems to get a bit confused at higher speeds.

My code basically consists of a loop between a hardware GPIO interrupt and a TIMER1 interrupt, which trigger each other over and over again. The problem is that when I shorten the time between the hardware interrupt and the clock interrupt (by lowering the OCR1A value) below about 2200 clock cycles, the clock interrupt begins occurring after only about 100 cycles, more than ten times less than it should be. Any idea what's causing this?

Note: my code saves the TCNT1 clock register value at every clock interrupt and dumps them all once it has saved 100 of them. I did this to make viewing the waveforms on my oscilloscope a bit easier.

#define period 1000

volatile int index = 0;
volatile int bank[100] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

void setup() {
  cli();

  Serial.begin(1000000);
  
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;

  TCCR1B |= (1<<CS10);
  //TCCR1B |= (1<<CS11);
  //TCCR1B |= (1<<CS12);
  
  //TCCR1B |= (1<<WGM12); //ctc

  TIMSK1 |= (1<<OCIE1A); //enables interupt
  OCR1A = period;

  DDRB |= (1<<0); //main touch IO pin OUTPUT
  DDRB |= (1<<1); //debug OUTPUT
  DDRB |= (1<<2); //debug OUTPUT
  PCICR |= (1<<PCIE0); //enable IO 8-13 interrupt
  PCMSK0 |= (1<<0); //enables interupt pin 8
  PORTB |= (1<<0); //initial touch pin high
  sei();
}

void dump() {
  Serial.println("New shipment, boss");
  Serial.println(OCR2A);
  for (int i = 0; i<100; i++) {
    Serial.println(bank[i]);
  }
  Serial.println("");
  index = 0;
  //PORTB |= (1<<1); //debug
}

ISR(TIMER1_COMPA_vect) {
  cli();
  if (index >= 100) {
    PORTB |= (1<<1);
    dump();
    PORTB &= ~(1<<1);
  }
  else {
    bank[index] = TCNT1;
    index++;
  }
  
  PORTB |= (1<<2); //debug
  DDRB &= ~(1<<0); //touch pin to input mode
  TIMSK1 &= ~(1<<OCIE1A); //diables interupt
  //TCCR1B &= ~(1<<WGM12); //ctc

  //turn off touch pin and start timer
  TCNT1 = 0;
  PORTB &= ~(1<<0);
  sei();
}

ISR(PCINT0_vect) {
  if(!(PINB & (1<<0))) {
    cli();
    
    PORTB &= ~(1<<2); //debug
    
    PORTB |= (1<<0); //touch pin off
    DDRB |= (1<<0); //output mode touch pin
    TIMSK1 |= (1<<OCIE1A); //enables clock interupt
    TCNT1 = 0;
    
    sei();
  }
}

void loop() {}

Excerpt from console log, this output is the same for every data dump cycle:

New shipment, boss
0
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98
98

You can remove the cli() and sei() calls from the interrupt handlers as the processor does this implicitly.

You must not call code depending on interrupts (as using the Serial object) inside an interrupt handler!
I'm extremely surprised that you get a complete output at all.

Your description sounds to me like CTC mode is activated (for example if WGM12 is HIGH). That's strange because your code does not activate such a mode.
How does it behave if you set the prescaler to another value than 1?

Consider using a counter/timer to do the work. No ISR and all of that stuff and it would be very fast.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.