Issue with Timer interupt resolution

Hi,

Quick question,

I'm trying to emulate the resolution of a 16 bit timer using timer 0 or 2 on Arduino Nano, as I am already using timer 1 for something else.

This is actually part of a bigger project where I am electrically gearing two stepper motors, and using timer 1 with changing interrupt delays to accelerate one stepper motor up to max speed, and another timer to "follow" the first stepper motor as at accelerates and reaches top speed using a constant frequency ratio between the two steppers.

The code below illustrates what I'm trying to do with one of the 8 bit timers.
an array of values is set in the main loop, and the timer interrupts use these to determine when to set pin 5 high and then low again by accumulating multiple interrupts before changing the pin state and the overflow limit.

Similar code with timer 1 works fine, but because it's 16bit, the maximum overflow is always higher than the TOP value I'm setting for the interrupt.

The code below gives a 60Hz output, but should be giving more than 4Khz when it reaches highest frequency.

Can anyone shed any light on this? is it an issue with the number of clock cycles being used to set the variables in the interupt?

volatile long TriggerAry [3] = {0, 0, 0};
long valcount = 19999;//800hz
long mincount = 3635; //4.396khz

bool TriggarTimer = false;

int loopcounter = 0;
// using pin 5

void setup() {
  pinMode(5, OUTPUT);


  TriggerAry[0] = valcount / 256;
  TriggerAry[1] = 255;
  TriggerAry[2] = valcount - (TriggerAry[0] * 256) - 1L;

  TCCR0A = 0;
  TCCR0B = 0;
  TCNT0 = 0;
  OCR0A = TriggerAry[1];
  OCR0B = 31;
  TCCR0B  |= (1 << WGM01);
  TCCR0B  |= (0 << CS02) | (0 << CS01) | (1 << CS00); // x1 prescaler
  TIMSK0 |= (1 << OCIE0A);
  TIMSK0 |= (1 << OCIE0B);
  sei();
}

void loop() {

  if (valcount > mincount) {
    valcount = valcount - 10;
  }

  TriggerAry[0] = valcount / 256;

  TriggerAry[1] = 255;

  // TriggerAry[2] = (valcount % 256)-1L     - appears slower than....
  TriggerAry[2] = valcount - (TriggerAry[0] * 256) - 1L;
}


ISR(TIMER0_COMPA_vect) {

  if (TriggarTimer == true)

  {
    PORTD |= 0x20;
    TriggarTimer = false;
  }
}


ISR(TIMER0_COMPB_vect) {

  if (loopcounter >  TriggerAry[0])

  { PORTD &= 0xDF; //off
    OCR0A = TriggerAry[2];
    loopcounter = 0;
    TriggarTimer = true;
  }
  else
  { OCR0A = TriggerAry[1];
    loopcounter++;
  }
}

Just to add,

I don't want to loose resolution by changing the pre-scaler, but out of curiosity did try altering the prescaler but this only gave a marginal increase in pulse frequency.

If you want to use any Arduino time features, like millis(), micros(), or delay(), you should not mess with Timer0.

You can extend the count of an 8-bit timer by counting overflow interrupts.

If you are emulating 16 bit timers, you don't need long variables, uint8_t will do.
I think the issue is that you keep setting OCR0A inside your COMPB ISR. Imagine you have counted up to the last phase when you set OCR0A to your remainder (TriggerAry[2]) but that value is higher than OCR0B so your COMPB ISR fires again before you even get to COMPA. At that point, you reset OCRA back to 255 so....

  TCCR0B  |= (1 << WGM01);
  TCCR0B  |= (0 << CS02) | (0 << CS01) | (1 << CS00); // x1 prescaler

Wrong register. WGM01 is in TCCR0A. It's only WGM02 that is in TCCR0B. You are setting CS01 which, along with CS00, is setting a prescale of 64. No, ORing with (0 << CS01) won't turn the bit off.

johnwasser:

  TCCR0B  |= (1 << WGM01);

TCCR0B  |= (0 << CS02) | (0 << CS01) | (1 << CS00); // x1 prescaler



Wrong register. WGM01 is in TCCR0A. It's only WGM02 that is in TCCR0B. You are setting CS01 which, along with CS00, is setting a prescale of 64. No, ORing with (0 << CS01) won't turn the bit off.

This is true, but the line right before this clears the entire register so that bit is already zero. Even though it does nothing, it does help document the intent.

WGM01 is in TCCR0A

It doesn't really matter what register it is on as WGM01 is defined in the core as number which is passed to your bit shift. John is correct in that you are setting CS01(bit1) in TCCR0B

C:\Program Files (x86)\Arduino\hardware\tools\avr\avr\include\avr\iom328p.h

#define WGM01 1
TCCR0B  |= (1 << WGM01);
TCCR0B  |= (1 << 1);

Thanks All - I must have read the data-sheet 5 or 6 times, but still missed it.

Now getting 4.28 kHz.

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