Point me to timer tutorial and examples

I am a newb who has read many tutorials, did the Hello World LED example, and have the board driving multiple servos. I have been unsuccessful finding examples of using timer interrupts. I am not looking for someone to write code, just lead me to where it is explained.

The tutorials I have found so far have not included timers.

And just for a sanity check, my intention is to have one function calculate the values for each servo and then wait. Another function, fired off by the timer, will push the calculated values to the servos, and then clear the wait state for the first function.

Does this make sense?

Thanks, Vince

Does this make sense?

Not when there are perfectly good servo libraries, no, not really.

Hi AWOL, Thanks for replying. :) I am using the servo library to write values to the servos.

What I want is to write a newly calculated set of values for every frame that is sent to the servo.

I could just constantly calculate the desired servo values and push them out many times per frame, but I had hoped to do this once per servo refresh period, and leave the CPU open for other tasks.

My first thought is to use a timer interrupt with the period set to the same as the servo refresh rate, and have the calculations and the servo writes in a function triggered by the timer interrupt. Is there some construct in the servo library that will allow me to fire a function each time a servo refresh signal is sent?

Why not just slow the calculation to, say once every 10ms? Alternatively, mod the servo library to add the function you need - if there is already a timer firing at the required frequency, why invent a new one?

Groove, you gave me the right suggestion; mod the servo library.

I created a function calculations_each_frame(). I put a prototype near the top of servo.h

void calculations_each_frame();

And I call my function near the end of handle_interupts

static inline void handle_interrupts(servoTimer_t timer, volatile uint16_t *TCNTn, volatile uint16_t* OCRnA)
{
  if( Channel[timer] < 0 )
    *TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer 
  else{
    if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && SERVO(timer,Channel[timer]).Pin.isActive == true )  
      digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,LOW); // pulse this channel low if activated   
  }

  Channel[timer]++;    // increment to the next channel
  if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) {
    *OCRnA = *TCNTn + SERVO(timer,Channel[timer]).ticks;
    if(SERVO(timer,Channel[timer]).Pin.isActive == true)     // check if activated
      digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high   
  }  
  else { 
    // finished all channels so wait for the refresh period to expire before starting over 
    if( (unsigned)*TCNTn < (((unsigned int)REFRESH_INTERVAL * TICKS_PER_uS) + 4) )  // allow a few ticks to ensure the next OCR1A not missed
      *OCRnA = (unsigned int)REFRESH_INTERVAL * TICKS_PER_uS;  
    else 
      *OCRnA = *TCNTn + 4;  // at least REFRESH_INTERVAL has elapsed
    Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
      calculations_each_frame();
  }
}

At first, I just put a counter incrementer in my function, and in my main loop, printed the counter value once per second. The counter incremented 50 between each serial print, so I am relatively confident that my function is being called once per each servo refresh frame.

Now, I have a place to put my servo calculations so that the get called once each servo refresh frame, and I get should have good synchronization between servo value generation and the servo frame refresh.

Thanks for your help!

I'm not too keen on putting calculations in ISRs - you don't say what they are, but any unnecessary time spent in an ISR should be avoided.

I'd be more inclined to limit you code additions to setting a flag in the ISR, and polling and resetting it in background

I would like to reinforce Groove's advice. It is much better to modify the channel values from within the sketch rather than in the interrupt – every additional microsecond of added calculation time potentially disrupts other code waiting for interrupts.

Perhaps you can say more about your application and what kind of calculations are needed, but the fragment below may give you an idea of how to achieve what you want. Its not exactly synchronized to the frame rate but I would be surprised if that makes a practical difference.

const int NBR_SERVOS = 12;
Servo myServos[NBR_SERVOS];

// setup code removed

void loop()
{  
  for(int servoNumber = 0; servoNumber = NBR_SERVOS; servoNumber++)
  {
      int Value = calculations_each_frame(servoNumber);
      myServos[servoNumber].write(Value); 
  }
  delay(20); 
}

Just to help me come up to speed, can you elaborate on the desire to avoid calcs in the ISR? Is it the possibility of a lockup if one set of calcs does not finish before the next interrupt triggers? If so, I hope to handle that with a 'busy' bit. The calculations_each_frame function will immediately return if the busy bit is true. Then it sets the busy bit true, performs the calculations, sets the busy bit false and finaly terminates.

Are there other concerns I should keep in mind?

And as for the what the calculations are, it is 18 calls to the Atan function, 18 to the Sqrt function and a hundred or so floating point adds and multiplies. I expect this to take way less than the 20 ms servo refresh cycle time. But I will do some time captures to see how long it is taking in reality. Capture the time, run my calculation a thousand times and capture the time again.

Make sense?

Please do keep coming with the advice. I am new to this environment, and this forum has already provided me with a ton of information.

Mem, thank you for chiming in. I did have almost exactly what you put in your code snippet in one of my earlier versions.

I had hoped to leave the main loop for doing higher level control, and keep the servo calculations running in the interrupt.

As for what I am doing, I am working on a hexapod. Probably more of a programming exercise than any particular project goal. The low level routines will handle the servo calculations to place the foot in a particular location. I have that logic coded and working now. The next level of routines will handle step decisions, defining the locations to place the feet. The next level of routines will handle overall navigation.

The pie in the sky goal might be to have an on-board computer doing stereoscopic video processing, but that is a way down the road. :)

I know that I can buy a hexapod kit with working software. But I am not looking for a radio controlled toy. I am having a blast working through the math and the programming challenges.

Those calculations will take a relatively long time, too long for inclusion in an interrupt handler.

I suggest you try the approach along the lines I posted above. It will be much easier to debug and it won't interfere with any interrupts. Because your calculations will take a relatively long period of time, you may want to replace the fixed delay with a calculation using millis so the updates will repeat every 20ms irrespective of how long the calculations take (assuming the calculations take less than 20ms!!)

const int NBR_SERVOS = 12;
Servo myServos[NBR_SERVOS];
long previousMillis = 0;        // will store last time Servos were updated

void loop()
{
  if (millis() - previousMillis > 20) 
  {
    // here if 20ms has elapsed since the last servo write
    previousMillis = millis();    
    for(int servoNumber = 0; servoNumber = NBR_SERVOS; servoNumber++)
    {
      int Value = calculations_each_frame(servoNumber);
      myServos[servoNumber].write(Value); 
    }
  }
}

If you want to keep your loop code clean, you can do something like this:

void loop()
{
   servoService()
   // loop code here
   
}

void servoService()
{
  if (millis() - previousMillis > 20)
  {
    // here if 20ms has elapsed since the last servo write
    previousMillis = millis();
    for(int servoNumber = 0; servoNumber = NBR_SERVOS; servoNumber++)
    {
      int Value = calculations_each_frame(servoNumber);
      myServos[servoNumber].write(Value);
    }
  }
}

18 calls to the Atan function, 18 to the Sqrt function and a hundred or so floating point adds and multiplies

Waaaay too much for an ISR!

Hmmm.....

I am getting this vague impression that I have stuffed too much into my ISR. :D

If my calculations take anywhere close to 20ms then I have chosen too small of a processor. But I believe that they will take much less time. And my future testing will give me a quantitative answer.

I do like the idea of modifying the example Mem gave to run every 20ms rather than with a 20ms gap between the end of one and the start of the next calculation.

I will work with this logic and let you know how it goes. Thanks for the tips. Don't be shy about offering more.

It's not necessarily the 20ms frame time you need to worry about, it's the much shorter servo pulse which are more likely to be affected.

The main problem with spending a lot of time in an ISR is that it blocks out any other interrupts that need to run. The millis timer, delay function and anything else that relies on millis would have incorrect values if your calculations were done in the ISR and took more than one millisecond. Also, if you wanted to later add some code that used interrupts (perhaps a library that produced audio tones, or counted encoder pulses or whatever) it could disrupt or disable the new functionality.

Good design means choosing an implementation that will have minimal interference with other aspects of the system and is no more complex than necessary. Adding calculations into an ISR that don't need to be synchronized with the interrupt breaks both of those guidelines.

I think you will be much better off ignoring the interrupts and doing the calculations in the sketch code.