Timer documentation

I have solved my problem, but am looking for a pointer to the relevant part of the documentation.

I am planning to use an Elegoo Mega2650 board to drive ( amongst other things) the leadscrew motor for a micro lathe. The motor is a 100rpm 12v DC brushless geared motor. It has an open collector pulse signal to give speed feedback. As it's 1:60 geared, and 9 pulses/rev of the basic motor; counting the pulses in 1 second and dividing by 9 gives the output shaft rpm.

I only need to know the speed each second (900 pulses at full speed) so I have wired the pulse output to pin 47 on the Mega 2560 and am using timer 5 to count the pulses. The program loops once per second (approx.) using delay (1000).

I am setting up the counter by setting

  byte FGpulsepin = 47;

 pinMode (FGpulsepin, INPUT_PULLUP); //input pin for timer
  TCCR5A = B00000000;  //Ensure normal mode
  TCCR5B = TCCR5B & B11111000 | B10000111  ; //clock timer 5 on external rising edge for speed pulses high bit enables noise suppressio

and reading the data by

// check the leadscrew motor speed
  thismillisec = millis(); // time now - may overflow after 50 days running!!
  t5count = TCNT5; //grab the count
  TCNT5 = 0; //reset to zero
  elapsed = thismillisec - lastmillisec;
  lsrpm = (t5count * (111 / elapsed)); // calculate speed
  lastmillisec = thismillisec;  //remember the time
  dtostrf(lsrpm, 5, 1, lsrpmstring); //output shaft speed to one decimal place for display

According to the documentation (Atmel datasheet page 154), the default for TCCR5A is B00000000.
However unless I explicitly set TCCR5A to all zeros as above, the counter behaves as if it were an 8 bit counter and rolls over after 256 pulses. Explicitly reading TCNT5H always returns zero.

Explicitly setting TCCR5A to all zeros makes the timer work as documented.

I appreciate that being explicit is a good idea, but I am wondering if I have missed something somewhere else in the detailed documentation that defines the 8 bit behaviour, or is setting pinMode switching the mode of the counter behind the pin?

Can anyone with more expertise give me a pointer as to where I should look, and are there any other timer registers I need to be setting explicitly?

Thanks in advance.

Would you consider changing the way you count pulses? You can use one of the external interrupts for counting pulses, and use timer5 as your "seconds" counter?

Something that looks like these

// this is you pulse counter, it increments the value of pulseCounter every RISING or FALLING edge
ISR(INT0_vect)
{
   pulseCounter++;
}

// this is your accumulator, basically every second, this is called and it gets the current value (accumulated pulses) and copies it to another variable and zeroes out pulseCounter (to ready it for the next second of counting)
ISR(TIM5_vect)
{
   pulseTotal = pulseCounter;
   pulseCounter = 0;
   ready = true;
}

void loop()
{
   if(ready)
   {
         ready = false;
        // display number of pulse for the last second
   }
}

this way, you get a clean pulses per second value and you can do the Math from there. I think it easier than the way you are using tmer5 to count the pulses.

Thanks for the suggestion. I had considered using an interrupt (or two) to do the job, but I chose this way because I am using several interrupt routines already in the bigger sketch.

One monitors the spindle motor on the lathe (10,000rpm max - two pulses/rev from a Hall effect transducer), and a couple of pin change interrupts for the rotary encoder used to set the spindle speed. 100-10,000 is too big a range to set accurately with a pot and I don't want to get into the user interface complexity of a keypad as I will need to jog the speed up or down while turning metal and a rotary control is far easier to use for that.

As I only need the leadscrew speed once per loop to tweak the PWM output that drives the motor it felt more elegant to let the hardware count the pulses and read the count in the loop. It does work extremely well now I have solved the initialisation issue. The need for floating values to do the arithmetic is OK because in the final version I plan to display the leadscrew speed as microns of travel per revolution of the main spindle.

It was just that the hardware didn't quite default to the behaviour I was expecting and it took me quite a while to track down the problem - so I wondered if I was missing something in the documentation.

Thanks again.

wisty:
According to the documentation (Atmel datasheet page 154), the default for TCCR5A is B00000000.
However unless I explicitly set TCCR5A to all zeros as above, the counter behaves as if it were an 8 bit counter and rolls over after 256 pulses. Explicitly reading TCNT5H always returns zero.

Probably because the Arduino run-time (called before your setup() function) sets up most or all counters for use as 8-bit PWM generators for the PWM pins each timer controls. I recommend that you set all the Timer/Counter registers to 0, including the interrupt enable register, before you start programming them.

Thanks John - that was the explanation I was looking for.

Is there any accessible documentation on the Arduino run time and what it does?

wisty:
Thanks John - that was the explanation I was looking for.

Is there any accessible documentation on the Arduino run time and what it does?

Not really, unless I've really missed something. There probably should be. But all the sparsely documented code is here:

I think the philosophy is, "you shouldn't have to know".

For Timer initialization, see: hardware/arduino/avr/cores/arduino/wiring.c/init()

The 'init()' and initVariant() functions are called just before your setup() function. (See: hardware/arduino/avr/cores/arduino/main.cpp/main())

Thanks again John. That is very clear - once you know where to look.

For completeness, in case anyone else runs into this thread looking for help on Timer 5 input, the relevant init() code is

#if defined(TCCR5B) && defined(CS51) && defined(WGM50)
sbi(TCCR5B, CS51); // set timer 5 prescale factor to 64
sbi(TCCR5B, CS50);
sbi(TCCR5A, WGM50); // put timer 5 in 8-bit phase correct pwm mode
#endif

Clearly both TCCR5A and TCCR5B need to be explicitly set of you want to use Timer5 for anything other than 8 bit phase corrected PWM.

Thank you all.

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