Go Down

Topic: 32u4 timer prescaler (Read 152 times) previous topic - next topic

mattisalo

Hi,

Im trying to learn timers. But i just cannot understand what i'm doing wrong. trying to set prescaler to 8 to have 0.5us ticks.

the test code that i have is:
Code: [Select]
volatile int timeTicks;

void setup(){
  Serial.begin(115200); // start serial
  TCCR3A=0;   // Clear A control bits
  TCCR3B=0; // Clear B control bits
  TCCR3A = (0 << WGM33) | (1 << WGM32) | (0 << WGM31) | (0 << WGM30); / Set CTC Mode
  OCR3A = 2; // Set Compare to two ( 2x 0.5us  = 1us )
  TIMSK3 = (1 << OCIE3A); //Set timer mask 1
  TCNT3=0;  //Reset timer counter
  TCCR3B = (1 << CS31) ;  Select prescaler ( 16MHz with 8 prescaler is 0.5us pulse )
  //sei();
}

void loop() {     // print timer ticks in every one millisecond should be around 1000 because tick is every us)
Serial.println(timeTicks); 
delay(1); 
}

ISR (TIMER3_COMPA_vect) { //Add timertick on rollover an reset ticks every 60000 to have even numbers)
  //timeTicks++;
  if(++timeTicks < 60000)
  return;
  if (timeTicks = 60000) timeTicks = 0;
}


still i get output like this:
Code: [Select]

222
3222
3222
3222
3222
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3223
3224
3224
3224



the 1us i'm trying to aim is now about 27ms

something is cleatly wrong and i have gone several guides and processor specs thru dun i don't see the problem


DKWatson

TCCR3A = (0 << WGM33) | (1 << WGM32) | (0 << WGM31) | (0 << WGM30); / Set CTC Mode

Should be,
Code: [Select]
TCCR3B |= (1 << WGM32);

WGM31 and WGM30 are in TCCR3A, WGM33 and WGM32 are in TCCR3B. No need to propagate the zeros having just set the entire register to zero (can't do it with | anyhow).
Live as if you were to die tomorrow. Learn as if you were to live forever. - Mahatma Gandhi

johnwasser

Your 'timeTicks' variable is declares as a signed integer ('int').  You should not be comparing it with a value like 60000 that can't fit into a signed integer.  I recommend you make timeTicks 'unsigned int' instead of 'int'.

In this line you are assigning timeTicks the value 60000.  You probably meant '==' instead of '='.
Code: [Select]
  if (timeTicks = 60000) timeTicks = 0;
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

mattisalo

Thanks for the help. There were stupid rookie mistakes. Now I'm bit closer..

The code is now:
Code: [Select]
volatile unsigned int timeTicks;
int Round;
unsigned int values[10];

void setup(){
  Serial.begin(115200); // start serial
  delay(3000);
  Serial.println("Started....");
  TCCR3A=0;   // Clear A control bits
  TCCR3B=0; // Clear B control bits
 
  OCR3A = 2; // Set Compare to two ( 2x 0.5us  = 1us )
  TIMSK3 = (1 << OCIE3A); //Set timer mas 1
  TCNT3=0;  //Reset timer counter
  TCCR3B = (1 << CS31) | (1 << WGM32);  //Select prescaler ( 16MHz with 8 prescaler is 0.5us pulse ) And set CTC
  sei();
  Serial.println("Setup ready....");
 
}

void loop() {     // print timer ticks in every one millisecond should be around 1000 because tick is every us)
delay(10);
values[Round]=timeTicks;
if (Round < 9){
  Round++;
}
else{
for (int i=0; i <= 9; i++){
  Serial.print(values[i]);
  Serial.print(","); 
}
Serial.println("");
Round=0;
}

 
}

ISR (TIMER3_COMPA_vect) { //Ad timertick on rollover an reset ticks every 60000 to have even numbers)
  //timeTicks++;
  if(++timeTicks < 60000)
  return;
  if (timeTicks > 60000) timeTicks = 0;
}


I've done so i can be sure that i'm getting really 1us ticks out of the counter, but I'm not.
I created an array where to store the TimeTicks with 10ms delay so i should get pretty much 10000 difference between values. I print it to serial after 10 values so the serial print would not mess the testing with extra delay.

the output is:
Code: [Select]
30426,33113,36227,39340,42454,45568,48681,51794,54908,58021,
29659,32772,35886,39000,42155,45310,48423,51537,54651,57806,
29420,32533,35647,38802,41915,45029,48143,51256,54370,57484,
29117,32272,35385,38499,41613,44726,47840,50995,54109,57264,
28913,32027,35140,38296,41409,44523,47678,50791,53947,57060,
28734,31847,35002,38116,41229,44343,47457,50612,53726,56880,
28562,31675,34831,37944,40632,43745,46858,49972,53086,56199,
27885,31039,34195,37308,40422,43536,46649,49763,52876,55990,
27688,30802,33916,37029,40143,43257,46370,49525,52680,55794,


I'm now getting quite exactly 3113 or 3114 when i should get 10000.

I also changed the  delay(10) -> delayMicroseconds(10000), that should be quite the same, but the result was:

Code: [Select]
3074,22558,42042,1525,21002,40486,59970,19453,38938,58414,
45321,4805,24289,43764,3248,22732,42217,1700,21176,40660,
26985,46470,5944,25429,44913,4397,23872,43356,2840,22325,
8721,28196,47681,7165,26648,46124,5608,25092,44576,4060,
49875,9357,28842,48326,7802,27285,46770,6253,25738,45213,


Again i'm getting 19484 difference as it should be around 10000

I do not know what to believe...

johnwasser

From my experiments it appears that the Arduino can't reliably handle interrupts every microsecond (1 million per second).  It looks like 8 clocks (4 microseconds) works.  You also can't assume that the timer starts at 0 each time you start your delay and you can't assume the rest of the code takes no time at all.  The number of 4 uS interrupts from
Code: [Select]
interrupts();
through the "delay(10)" to the
Code: [Select]
noInterrupts();
averages to about 2535.  Multiply by 4 to get 10140 microseconds across the delay.

If you want to handle a million interrupts per second I think you will need a faster processor. 


Code: [Select]
volatile unsigned long timeTicks;
int Round;
unsigned int values[10];

const unsigned int TOP = 7;

void setup()
{
  Serial.begin(115200); // start serial
  while (!Serial) {}

  Serial.println("Started....");
  TCCR3A = 0; // Clear A control bits
  TCCR3B = 0; // Clear B control bits

  OCR3A = TOP; // Set Compare to two ( 2x 0.5us  = 1us )
  TIMSK3 = (1 << OCIE3A); //Set timer mas 1
  TCNT3 = 0; //Reset timer counter
  TCCR3B = (1 << CS31) | (1 << WGM32);  //Select prescaler ( 16MHz with 16 prescaler is 0.5us pulse ) And set CTC
  sei();
  Serial.println("Setup ready....");

}

void loop()       // print timer ticks in every one millisecond should be around 1000 because tick is every us)
{
  noInterrupts();
  unsigned long timeTicksStart = timeTicks;
  interrupts();
  delay(10);
  noInterrupts();
  values[Round++] = (timeTicks - timeTicksStart);
  interrupts();
  if (Round >= 10)
  {
    for (int i = 0; i < 10; i++)
    {
      Serial.print(values[i]);
      Serial.print(",");
    }
    Serial.println("");
    Round = 0;
  }
}

ISR (TIMER3_COMPA_vect)   //Ad timertick on rollover an reset ticks every 60000 to have even numbers)
{
  ++timeTicks;
}
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

johnwasser

Measuring with the timer running at 2 MHz gets me  20017 (+/= 4) ticks or 10.01 Milliseconds.

Code: [Select]
  unsigned timeTicksStart = TCNT3;
  delay(10);
  values[Round++] = (TCNT3 - timeTicksStart);
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

Go Up