Go Down

Topic: timer0 prescale factor and timing functions adjustments (Read 984 times) previous topic - next topic

y100921

Hi all,

I'm trying to modify prescale factor for timer0 on Arduino UNO, I'm modifiing wiring.c to keep the delay(), millis()... functions working. If I select lower prescale factor than the default 64 it appears to be working, but I have trouble getting it to work for higher factors. What am I missing?

My sketch is below, I expect serial output each second. Per http://playground.arduino.cc/Main/TimerPWMCheatsheet I'm changing this line in wiring.c:
#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(PRESCALE_FACTOR * 256))

For the code below I use PRESCALE_FACTOR = 256 but nothing shows up on serial monitor.

Code: [Select]
unsigned long prev_millis;

void setup() {
  Serial.begin(9600);
  //TCCR0B = _BV(CS01);  //factor 8
  //TCCR0B = _BV(CS01) | _BV(CS00);  //factor 64
  TCCR0B = _BV(CS02);  //factor 256
  prev_millis = millis();
}

void loop() {
  if (millis() - prev_millis > 999) {
    Serial.println(millis());
    prev_millis = millis();
  }
}

cattledog

Code: [Select]
#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(256 * 256))

The constants are treated as integers, and the expression is overflowing.  Instead use

Code: [Select]
#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(256UL * 256))

y100921

Thank you, I was expecting something like that...

Interesting thing, though. When I use (256UL * 256) the serial output is not whole thousands as expected but rather 1003, 2007, 3010, 4014, 5017, 6017, 7020, ... When I use (250UL * 256) it fixes this issue but the ticks are then shorter than one second.

cattledog

Things look more precise if you simply scale the value of millis() in the sketch rather than change the library. I think that when you change the library for a prescaler of 256, there are issues with size of the fractional millis() and the fact that the minimum millis() precision is four. I have not fully worked through the section of wiring.h which generates the millis() from the overflow interrupt on Timer 0 to see if it can be modified to give the even count.

Code: [Select]
unsigned long prev_millis;

void setup() {
  Serial.begin(9600);
  //TCCR0B = _BV(CS01);  //factor 8
  //TCCR0B = _BV(CS01) | _BV(CS00);  //factor 64
  TCCR0B = _BV(CS02);  //factor 256
  prev_millis = 4*millis();
}

void loop() {
  if (4*millis() - prev_millis > 999) {
    Serial.println(4*millis());
    prev_millis = 4*millis();
  }
}

Go Up