Piggyback on the millis() interrupt?

EDIT: jremington provided the answer. Attaching an interrupt to timer0 (which is tied to the millis function) is very simple. See: Timer Interrupts | Multi-tasking the Arduino - Part 2 | Adafruit Learning System where you also learn that the interrupt is slightly longer than 1ms.
EDIT2: stuart0 added: you can make it exactly 1 ms by issuing "OCR0A -=6;" at the start of each interrupt, but you interfere with analogWrite (see below).
EDIT3: cattledog made it understandable: The timer0 is an 8-bit timer incrementing from 0-FF(255) and then restarting from zero. The interrupt "TIMER0_COMPA_vect" occurs when the "OCR0A" value is equal to to the timer ("AF" according to the example above). However, PWM output on pin 5/6 (at least on Uno) are also using timer0. I.e., using analogWrite affect the value on "OCR0A" and will shift when the interrupt will occur. Thus, using analogWrite will move the interrupt within the window 0-FF. Normally you would not care (if you are not anal about getting one interrupt per ms) since you'd get one interrupt approximately every ms. Obviously, if you move OCR0A back and forth between 00 and 80 every millisecond you could end up never triggering the interrupt "TIMER0_COMPA_vect" but you'd feel really unlucky if you manage to do that.

I like the simplicity of not having to know everything. But I would also like to have an interrupt running every ms or two ... which does not seem to be too easy.

So far:
1: Run some PWM output and connect it to an interrupt pin would give me an interrupt ~ 1-2 ms. However, I'm already using my two interrupt pins on the Uno so that idea is not very usable.
2: Reprogram some timers. Very complicated when you don't want to know everything. Especially if you don't want unintended interactions with the millis() function or analogWrite or serial.

Back to the subject line. So why isn't there a simple way to piggyback on the millis() interrupt? I assume that there is such an interrupt running (since I'm lazy I have not bothered to find the relevant code sent to the shield).

So the suggestion is to provide: attachInterrupt(INTERNAL1MSINTERRUPTCONSTANT, ISR, mode); function to piggyback on the timer0 interrupt.

And the question is: How do I do that today?

Happy new years - Magnus

It is not too hard to set up a timer interrupt. There are libraries that handle it for you if you don't want to go bare metal. You won't affect millis unless you muck around with Timer 0 so just don't mess around with Timer 0 and you'll be alright.

I think what has caught you is this line:

masse12345:
since I'm lazy I have not bothered to find

If the only problem is that you are too lazy to do some reading then don't expect much sympathy here. Get off your lazy ass and spend an hour or two googling and reading and you'll see how dead simple this is.

If you only want something to happen once per millisec you may not need an interrupt. Debugging programs that use interrupts can be complex.

Have a look at how millis() is used to manage timing in several things at a time. You can use the same technique with micros() if you need short intervals.

...R

Thank you for not being too lazy to reply!

Robin2:: I'm fine ... I look at millis() and run my function whenever it updates. It will work but it's a bit suboptimal and you constantly have to think when coding instead of just using an interrupt.

Delta_G Ok. I can setup a timer and I've spent a couple of hours reading things of google. However, the problem is that various post seem to suggest that PWM output is running through the timers (as well as millis() and serial). Thus, I could use random google recipes to get interrupts of a timer. However, I could not be certain that other things work as expected (without investing a lot of time). I think the main point is convenience, Arduino is convenient. Adding a way to piggyback on the (assumed timer0 interrupt) would be 1) convenient, 2) simple to implement 3) extremely useful for all users.

So the question stands: How to piggyback on timer0 without affecting millis() etc.

masse12345:
I like the simplicity of not having to know everything. But I would also like to have an interrupt running every ms or two ... which does not seem to be too easy.

But it is easy and there is no need to muck up the millis() timer ISR.
There are a couple of libraries that will do it all for you.
Just look for them.
TimerOne, MsTimer2, FlexiTimer2, TimerThree to name a few.

Google, look in the IDE library manager, or look here:

https://www.pjrc.com/teensy/td_libs.html

--- bill

If you don't really need an ISR there are other libraries that manage calling functions at pre-determined times like the metro or SimpleTimer libraries.

So basically libraries exists to make task scheduling easy from either ISRs or foreground loops.
There is no need to ever do the blink-without-delay technique that I see constantly recommended.

--- bill

bperrybap:
If you don't really need an ISR there are other libraries that manage calling functions at pre-determined times like the metro or SimpleTimer libraries.

So basically libraries exists to make task scheduling easy from either ISRs or foreground loops.
There is no need to ever do the blink-without-delay technique that I see constantly recommended.

--- bill

Actually the libraries you mention are doing just that, blink-without-delay behind the scenes. It can make it a lot easier to write code to use blink without delay if you use one of those libraries instead, but if you use the library as a way to avoid ever learning or understanding how blink without delay works then you're eventually headed for trouble you also won't be able to explain.

Delta_G:
Actually the libraries you mention are doing just that, blink-without-delay behind the scenes. It can make it a lot easier to write code to use blink without delay if you use one of those libraries instead, but if you use the library as a way to avoid ever learning or understanding how blink without delay works then you're eventually headed for trouble you also won't be able to explain.

Agreed, metro and SimpleTimer are doing foreground polling of the millis timer value.
But you could say not doing the code yourself is a crutch with respect to a lot of Arduino libraries and core code.
These two "timer" libraries are about ease of use and getting something up and going quickly, which is much more in line with the Arduino philosophy. Pushing people to dive down into the dirt of doing all the millis() calls and compares themselves - which is what all the blink-without-delay examples do - is definitely not as easy for many arduino users.
i.e. a lot of arduino is about giving non technical people or people with low technical programming skills the power to get things done.
Some of those people are not really interested in such low level details as it is not their field nor will it ever be.
They just want or need to get something done and using Arduino with a ready made library gives those people an easier alternative than having to learn and write the code themselves.

--- bill

bperrybap:
Agreed, metro and SimpleTimer are doing foreground polling of the millis timer value.
But you could say not doing the code yourself is a crutch with respect to a lot of Arduino libraries and core code.
These two "timer" libraries are about ease of use and getting something up and going quickly, which is much more in line with the Arduino philosophy. Pushing people to dive down into the dirt of doing all the millis() calls and compares themselves - which is what all the blink-without-delay examples do - is definitely not as easy for many arduino users.
i.e. a lot of arduino is about giving non technical people or people with low technical programming skills the power to get things done.
Some of those people are not really interested in such low level details as it is not their field nor will it ever be.
They just want or need to get something done and using Arduino with a ready made library gives those people an easier alternative than having to learn and write the code themselves.

--- bill

And that's cool, as long as they understand that they are using code that they don't understand and that will in many ways limit what they can do with it.

And I'm going to completely disagree with you about BWoD being either harder or closer to the metal programming. It's not a programming concept, it's a simple math concept. Understanding what subtraction means. And taking someone's word for it that subtraction protects you from rollover. In many cases these cruth libraries actually harder to use because you have to figure out all the OOP syntax AND the structure and how to use this library. Whereas with BWoD all you have to learn is how to subtract. It looks scarier, but it's really a lot easier in the end.

Adafruit has a tutorial on piggybacking the millis() interrupt, using the Timer0 compare feature.

How close to the ms do you need it? Can it be a "sloppy" timer?

-jim lee

jremington provided the perfect answer. 976.5625 Hz is close enough and I'll probably not even run my routine every interrupt. I'll try it out and then report back later today.

masse12345:
Robin2:: I'm fine ... I look at millis() and run my function whenever it updates. It will work but it's a bit suboptimal and you constantly have to think when coding instead of just using an interrupt.

Thinking is why I like programming.

in what way is it sub-optimal?

...R

If you have a piece of critical code that has to run you don't want to stick that in the main loop where it depends on the whole code being correct. Put it in an interrupt and you are sure that it will execute even if you have screwed up the main loop. (unless you do something wrong in the interrupt code itself)

The method pointed out by jremington: Timer Interrupts | Multi-tasking the Arduino - Part 2 | Adafruit Learning System is very simple and does not screw with the other timers as some of the other suggestions in the thread.

Although the code worked I managed to screw up yet another pair of FETs ... blue smoke again :slight_smile:

masse12345:
If you have a piece of critical code that has to run you don't want to stick that in the main loop where it depends on the whole code being correct. Put it in an interrupt and you are sure that it will execute even if you have screwed up the main loop. (unless you do something wrong in the interrupt code itself)

For me, the essence of writing microprocessor code is to ensure that the whole thing is nicely tuned so that everything can operate at the time it needs to operate and nothing is " screwed up the main loop".

Using an interrupt as a band-aid for poor programming is like ordering a take-away before you sit down to dinner at your favourite restaurant in case the service is too slow.

...R

Not only that but it is also one of those things that gets the code fixed for now, but when you finally get to the point where it finally bites you then you generally have a huge rewrite on your hands.

But I’ve learned that the noobie will not take that advice. They’d mostly rather learn these things the hard way.

Robin2:
For me, the essence of writing microprocessor code is to ensure that the whole thing is nicely tuned so that everything can operate at the time it needs to operate and nothing is " screwed up the main loop".

Using an interrupt as a band-aid for poor programming is like ordering a take-away before you sit down to dinner at your favourite restaurant in case the service is too slow.

...R

Variable timing that can create lots of jitter in the calling of a critical function is not necessarily due to poor programming.
I think the point he was making is that you can't trust a main foreground loop to always give you guaranteed deterministic consistent timing.
It is possible in some situations, but in order to provide consistent timing or even a maximum guaranteed worst case latency requires lots of thinking and design of a main loop and often requires being in control of all the s/w used.
In the end, it is often not possible.
Once you get beyond doing simple things that are very quick operations like blinking LEDs or polling switches, things can get complicated quickly and the main idle loop code can start to create lots of jitter in the calling of a function, particularly if using more complex devices that involve using libraries like graphical LCDs, or network protocol stacks.
i.e. more complex i/o devices can have unpredictable or lengthy times for various i/o operations that are not acceptable and it is possible that no amount of re-writing or "good programming" in the main loop or device library could solve the issue.
This is particularly true in a bare metal environment resource limited environment like Arduino which tends to have most of its s/w run in the foreground using blocking APIs.

Often the only way to get the needed deterministic timing is to use an interrupt since it can pre-empt the foreground when needed vs have to trust that the foregound can ALWAYS meet the needed loop timing.

--- bill

masse12345:
jremington provided the perfect answer. 976.5625 Hz is close enough and I'll probably not even run my routine every interrupt. I'll try it out and then report back later today.

And you can make it exactly 1kHz if you wish. It's set for 4.0 microseconds per count, so the only reason to it's not exactly 1kHz is that there are 256 counts per cycle instead of 250.

To make it 1kHz exactly just start with any value that you like in OCR0A and subtract 6 from it each time the interrupt is executed.

For example "OCR0A -=6;" at the start of each interrupt would do it.

Also be aware that you will lose PWM (analogWrite) functionality on the pin (PD6 or PD5) corresponding to the compare unit that you're using.

stuart0:
And you can make it exactly 1kHz if you wish. It's set for 4.0 microseconds per count, so the only reason to it's not exactly 1kHz is that there are 256 counts per cycle instead of 250.

To make it 1kHz exactly just start with any value that you like in OCR0A and subtract 6 from it each time the interrupt is executed.

For example "OCR0A -=6;" at the start of each interrupt would do it.

Also be aware that you will lose PWM (analogWrite) functionality on the pin (PD6 or PD5) corresponding to the compare unit that you're using.

Are you saying that using the TIMER0_COMPA_vect interrupt interfere with analogWrite? Or that the modification of OCR0A throws the timing/interfere with the PWM output? If the former I'd like make it clear to everyone reading the forum.

I was just in the basement and the PWM output on pin 6 (uno) was at least driving a motor ... and I'm happy that there have been no more FETs dying yet :slight_smile:

You can use the overflow interrupt and PWM at the same time as long as you don't pick a PWM mode that prevents you from hitting the top of the counter.

You can use OCR register to make a new top value, but the OCR register is where your PWM switching comes from so you eliminate PWM on that timer if you go that route.

The timers sections of the datasheet might be worth reading at this point if you want to get into those sorts of particulars.