Sanity check on some timing code

Hello,

I’m working on a musical sequencer project and could use a second opinion on some code. I’m using an Arduino Due and I’m taking advantage of the DueTimer.h library.

Originally, my code was organized like this:

    Timer0.attachInterrupt(clockTickInterrupt).setFrequency(192).start(); 

    void loop()
    {
       // poll inputs
    }

    void clockTickInterrupt()
    {
      // step sequencer and output sequencer notes
    }

This worked great. But I wanted to add a feature where the sequence could be changed based on some input information. Those changes could be (but aren’t always) a tiny bit CPU intensive and only need to happen before the sequencer outputs notes. One solution would be to put that code in the clockTickInterrupt, like so:

    Timer0.attachInterrupt(clockTickInterrupt).setFrequency(192).start(); 

    void loop()
    {
       // poll inputs
    }

    void clockTickInterrupt()
    {
      // do calculations <==== added here
      // step sequencer and output sequencer notes
    }

But those calculations are not always going to take the same amount of time, and putting them here will cause my sequencer’s timing to be jittery.

Another option would be to add the calculations to the main loop:

    void loop()
    {
       // poll inputs
       // do calculations <==== added here
    }

    void clockTickInterrupt()
    {
      // step sequencer and output sequencer notes
    }

But now I’m running the calculations a lot more than necessary. I only need to run them once per interrupt cycle.

So, my solution is to add another interrupt:

    Timer0.attachInterrupt(clockTickInterrupt).setFrequency(192).start(); 
    Timer1.attachInterrupt(computationInterrupt).setFrequency(384).start(); 

    void loop()
    {
       // poll inputs
    }

    void clockTickInterrupt()
    {
      // step sequencer and output sequencer notes
    }

    void calculationInterrupt()
    {
      // do calculations <==== added here
    }

Since the calculationInterrupt is set to happen at twice the speed of the clockTickInterrupt, it’s certain to run before the clockTickInterrupt. The only drawback, that I can see, is that the calculations get run twice when they only need to be run once. I maybe able to run the calculationInterrupt at the same speed as the clockTickInterrupt. I haven’t thought that entirely through yet.

Any suggestions? Does it sound like I’m on the right track?

Cheers,
Bret

I don't know anything about the Timer libraries but I am suspicious of something that wraps a simple concept in a black box. If I remember correctly there was another Thread recently in which the Timer library didn't like overlapping events (not necessarily the same library you have).

I wrote a demo sketch in this Thread that illustrates how several things can be timed using millis().

...R

Hi,

You can use multiple timers at the same time without problems, but if one interruption occurst on the middle of another, it will wait (default behavior).

What you can use to simplify even more, is to use my other Library ArduinoThread (GitHub - ivanseidel/ArduinoThread: ⏳ A simple way to run Threads on Arduino)

After reading it's main page, should give you an idea on how to implement it...

Also, notice that: Doing no calculations, and, running a empty loop consumes the same power on the uC. So, if you are not doing it because of that... it won't be a problem.

Ivan

Thanks for the responses.

What if I used the "noInterrupts" command in my clockTickInterrupt? For example:

    void clockTickInterrupt()
    {
      noInterrupts();
      // do time sensitive stuff
      interrupts();
    }

Also, invaneidel, thanks for your ideas. Are you sure that one thread can interrupt another one? On this StackOverflow answer, the person is saying that it isn't possible: When Arduino catch interrupt, is noInterrupts() called? - Electrical Engineering Stack Exchange

I'm playing around with moving the code from the calculationInterrupt back into the loop(). I'll see if I can get that to work.

Cheers,
Bret

clone45:
Also, invaneidel, thanks for your ideas. Are you sure that one thread can interrupt another one?

I don't think that invaneidel has made any comments about threads - and it wouldn't make sense to, since the Arduino does not have threads.

If your clockTickInterrupt() is called as a result of an interrupt then interrupts will be off automatically.

The code in an interrupt service routine should be as short as possible (2 or 3 lines) so the routine can complete quickly and return from the interrupt.

It’s beginning to look like you are devoting your time to the Timer library rather than your own project.

…R

Thanks Robin and Peter,

You're right. I misspoke when I asked if two threads could run at the same time. I meant interrupts.

This is all very valuable information, whether related to my project or not. I've moved a majority of my code back into the loop() successfully, and I've been able to reduce the amount of code in the interrupt significantly. (Thanks for that tip, Robin.) I did have to wrap some code with noInterrupts(); / interrupts(); to avoid a sort-of race condition. Having solved that issue, things seem to be working great now.

Ivan, could you elaborate when you said, "Doing no calculations, and, running a empty loop consumes the same power on the uC."?

Cheers,
Bret

clone45:
"Doing no calculations, and, running a empty loop consumes the same power on the uC."?

If a microprocessor is powered up it is executing code and using energy. It makes no difference whether it is executing useful code or just chasing its tail.

...R

Robin2:
If a microprocessor is powered up it is executing code and using energy. It makes no difference whether it is executing useful code or just chasing its tail.

That's it =)

About your code. Avoid using no-interrupts and interrupts. Always remember that you must have two goals:

  • Execute things fast (as Robin Said too)
  • Do not skip interruptions/delay it

The second one occurs when you put a 'nointerrupt'. If I'm not mistaken, interruption will NOT occur anymore. What it means is: it will be skipped.

Try to do your calculation as much indepedent from it's Timer function. Example:

int x;

void loop(){
x = x*2;

x = x/2;
}

Robin2:
If a microprocessor is powered up it is executing code and using energy. It makes no difference whether it is executing useful code or just chasing its tail.

That’s it =)

About your code. Avoid using no-interrupts and interrupts. Always remember that you must have two goals:

  • Execute things fast (as Robin Said too)
  • Do not skip interruptions/delay it

The second one occurs when you put a ‘nointerrupt’. If I’m not mistaken, interruption will NOT occur anymore. What it means is: it will be skipped.

Try to do your calculation as much indepedent from it’s Timer function. (simple example, but you get the idea):

int x = 10;

void loop(){
  x = x*2;
  // <--- If interruption get called here. x will be twice it's value.
  x = x+2;
  delay(100);
}

You can fix it easily with helper variables:

int x = 10;
void loop(){
  int helperX = x;
  helperX = helperX * 2;
  helperX = helperX + 2;
  x = helperX;
 // In no situation, x will be in the middle of its 'calculations';
}

And that’s correct… Arduino do not support Real threads, but you can take advantage of such library to help you with code organization. It would even be possible to use no timers at all, with a great control over what’s is going on… But, keep with Timers. They are more precise for your case.

Ivan

ivanseidel:
If I'm not mistaken, interruption will NOT occur anymore. What it means is: it will be skipped.

You're mistaken.

Using interrupts introduces various issues that can trip up the unwary, and my advice is to not use them unless absolutely essential, and then only reluctantly and to the minimum extent possible. However, when you're using interrupts correctly there are times when you need to disable interrupts. Doing this will cause interrupt handling to be delayed but (when done correctly) does not mean that interrupts would be 'skipped' entirely.

PeterH:

ivanseidel:
If I'm not mistaken, interruption will NOT occur anymore. What it means is: it will be skipped.

You're mistaken.

Using interrupts introduces various issues that can trip up the unwary, and my advice is to not use them unless absolutely essential, and then only reluctantly and to the minimum extent possible. However, when you're using interrupts correctly there are times when you need to disable interrupts. Doing this will cause interrupt handling to be delayed but (when done correctly) does not mean that interrupts would be 'skipped' entirely.

I don't think so. Interruptions are the most effective way of doing things on the microcontroller. For both precision on timing or even low-power consumption. They are made to be used, not to be left asside...

If I'm not wrong (I would need to test, but I can't be sure). If you set no-interrupts, and let's say... 5 interruptions occurs in the mean time. Those wont happen, even after interrupts is called.

ARM Cortex has a very complex structure, that allows many ways to deal with interruptions. One of them, is to dispose interruptions, other, is to run after one is complete. Other, is to run imediatly if priority of the new one is higher...

But that would lead us to a deep talking about the microprocessor datasheet... Something I avoid looking at, but it's essential some time...

My advice is: Use Interruptions (Timers, border...), and be aware of all it's requirements, to not create problems yourself... As I said, it's really easy to fix some small issues, but you just must be aware of them to develop a more robust code.

There are times, you will need to use noInterrupts, but that's only a few, when, perhaps, you are communicating with some peripheral, or doing a highly time sensitive action...

Well, try it yourself... I really like timing of things, and I spent a big part of my developments looking and testing it. Maybe it explain why I bough an FPGA :slight_smile:

ivanseidel:
If I'm not wrong (I would need to test, but I can't be sure). If you set no-interrupts, and let's say... 5 interruptions occurs in the mean time. Those wont happen, even after interrupts is called.

I'm afraid you are wrong. The interrupt handling mechanism will latch one pending interrupt for each interrupt source. If your interrupt handler takes so long that you get more than one subsequent interrupt before it completes, or you leave interrupts disabled for so long that you get multiple interrupts generated, you're doing it wrong. I'm not particularly surprised that you are gung ho about using interrupts, but once you get more familiar with the pitfalls and design issues they introduce I suspect you will see things rather differently. My advice regarding interrupts is to not use them unless absolutely necessary, and then only reluctantly and to the minimum extent necessary. By the time you're competent enough to ignore that advice you'll also be experienced enough not to be taking advice from strangers on the internet - and I expect that by then you will appreciate that the best advice for somebody who doesn't have that experience is to not use interrupts.

PeterH:
but once you get more familiar with the pitfalls and design issues they introduce I suspect you will see things rather differently. My advice regarding interrupts is to not use them unless absolutely necessary, and then only reluctantly and to the minimum extent necessary. By the time you’re competent enough to ignore that advice you’ll also be experienced enough not to be taking advice from strangers on the internet - and I expect that by then you will appreciate that the best advice for somebody who doesn’t have that experience is to not use interrupts.

+1

If you can avoid it, don’t use interrupts unless you are competent to debug them without needing advice from us.

…R

As to the original question, can you do your calculations one timer phase in advance? For example:

    void clockTickInterrupt()
    {
      // output notes for time(n)
      // do calculations for time(n+1)
    }

That way, you lose the jitter and the calculations always happen on-time. The only drawback I can see is if the calculations require up-to-date information, e.g. the state of various inputs. In that case, the calculations will be using inputs that are one timer-cycle stale.

Your other option is to run the calculations in the main thread, just in time. Requires that you have a ceiling for how long they will take, in order to ensure that they are completed:

const int int_period=10;  ///< 100Hz?
const int calculation_time=3; ///< say we can do the number crunching in 2ms
int last_int=0;    ///< time of last interrupt
bool calculated=false;  ///< have we done the calculations yet?

void loop()
{
  // wait until we have only just enough time
  if(last_int + int_period - millis() >= calculation_time && !calculated){
    calculations();
    calculated=true;
  }
}

void clockTickInterrupt()
{
  output();
  last_int=millis();
  calculated=false;
}

While it is true in the general case (especially for quite complex systems) that minimising the interrupt code is a good thing, it’s not a necessity. What really matters is that your CPU has always enough time to do what it needs to do, on time. So if your timer interrupt takes a long time, the only downside is that it might delay some other interrupt a bit. But my guess is this is your only interrupt, so that’s probably not a problem at all. It would be bad if you were to drop some input serial data because this interrupt was running though…

If your timer interrupt takes longer than the timer period, it will start skipping events.