What's the maximum time an interrupt service routine can take to execute on atmega328p?Interrupt Service Routine in C - function at specific addressAVR interrupt service routine not executing as fast as expected (instruction overhead?)Use PWM and ISR at same time on AVRAVR ISR causes unexpected behaviorWhat's the difference between all of the Atmega328p clocking options?how to use interrupt service routine without interrupt.h file in avr?Questions for a personal LED/ATmega328P-PU projectPIC32 GPIO pins Hardware Abstraction Layer questionwill For loop in MikroC for dspic block the interrupt service routine?Atmega328p - Program works with 2.7V power supply but doesnt with 3.3V
What explains 9 speed cassettes price differences?
Book where the stars go black due to aliens stopping human observation collapsing quantum possibilities
How would my creatures handle groups without a strong concept of numbers?
Parse source code of the RAPID robot-automation language
Single word for "refusing to move to next activity unless present one is completed."
Managing and organizing the massively increased number of classes after switching to SOLID?
Was the Ford Model T black because of the speed black paint dries?
Can I play a first turn Simic Growth Chamber to have 3 mana available in the second turn?
Is "take care'n of" correct?
How did the hit man miss?
The monorail explodes before I can get on it
During copyediting, journal disagrees about spelling of paper's main topic
Robbers: The Hidden OEIS Substring
A pyramid from a square
Why isn't there research to build a standard lunar, or Martian mobility platform?
How can an advanced civilization forget how to manufacture its technology?
For a hashing function like MD5, how similar can two plaintext strings be and still generate the same hash?
How to tell someone I'd like to become friends without causing them to think I'm romantically interested in them?
Is there a word for a message that is intended to be intercepted by an adversary?
Why was hardware diversification an asset for the IBM PC ecosystem?
Can fluent English speakers distinguish “steel”, “still” and “steal”?
Who has taken "my" Managed package namespace? Can we find out?
Why do people keep referring to Leia as Princess Leia, even after the destruction of Alderaan?
How to know whether a Tamron lens is compatible with Canon EOS 60D?
What's the maximum time an interrupt service routine can take to execute on atmega328p?
Interrupt Service Routine in C - function at specific addressAVR interrupt service routine not executing as fast as expected (instruction overhead?)Use PWM and ISR at same time on AVRAVR ISR causes unexpected behaviorWhat's the difference between all of the Atmega328p clocking options?how to use interrupt service routine without interrupt.h file in avr?Questions for a personal LED/ATmega328P-PU projectPIC32 GPIO pins Hardware Abstraction Layer questionwill For loop in MikroC for dspic block the interrupt service routine?Atmega328p - Program works with 2.7V power supply but doesnt with 3.3V
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
$begingroup$
I have an atmega328p that checks if a button was pressed via pin change interrupts. Now, I want to turn on an led for 200ms.
Can i just turn the led on, wait 200ms and turn it back off in the ISR like so?
ISR(PCINT1_vect)
if(PINB & 0b1)
PORT = 0b10;
_delay_ms(200);
PORT = 0;
In a few forum posts on AVRfreaks, I've read that you shouldn't spend much time in an ISR, but I've never seen any exact numbers. I sadly can't find those posts anymore, so I cant link them. As far as I can remember, they all said, that if you spent to much time in the ISR, the µC might crash.
Is that true? And if so, is there an exact time limit after that this might happen?
microcontroller avr atmega atmega328p
New contributor
thebear8 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
$endgroup$
add a comment |
$begingroup$
I have an atmega328p that checks if a button was pressed via pin change interrupts. Now, I want to turn on an led for 200ms.
Can i just turn the led on, wait 200ms and turn it back off in the ISR like so?
ISR(PCINT1_vect)
if(PINB & 0b1)
PORT = 0b10;
_delay_ms(200);
PORT = 0;
In a few forum posts on AVRfreaks, I've read that you shouldn't spend much time in an ISR, but I've never seen any exact numbers. I sadly can't find those posts anymore, so I cant link them. As far as I can remember, they all said, that if you spent to much time in the ISR, the µC might crash.
Is that true? And if so, is there an exact time limit after that this might happen?
microcontroller avr atmega atmega328p
New contributor
thebear8 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
$endgroup$
add a comment |
$begingroup$
I have an atmega328p that checks if a button was pressed via pin change interrupts. Now, I want to turn on an led for 200ms.
Can i just turn the led on, wait 200ms and turn it back off in the ISR like so?
ISR(PCINT1_vect)
if(PINB & 0b1)
PORT = 0b10;
_delay_ms(200);
PORT = 0;
In a few forum posts on AVRfreaks, I've read that you shouldn't spend much time in an ISR, but I've never seen any exact numbers. I sadly can't find those posts anymore, so I cant link them. As far as I can remember, they all said, that if you spent to much time in the ISR, the µC might crash.
Is that true? And if so, is there an exact time limit after that this might happen?
microcontroller avr atmega atmega328p
New contributor
thebear8 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
$endgroup$
I have an atmega328p that checks if a button was pressed via pin change interrupts. Now, I want to turn on an led for 200ms.
Can i just turn the led on, wait 200ms and turn it back off in the ISR like so?
ISR(PCINT1_vect)
if(PINB & 0b1)
PORT = 0b10;
_delay_ms(200);
PORT = 0;
In a few forum posts on AVRfreaks, I've read that you shouldn't spend much time in an ISR, but I've never seen any exact numbers. I sadly can't find those posts anymore, so I cant link them. As far as I can remember, they all said, that if you spent to much time in the ISR, the µC might crash.
Is that true? And if so, is there an exact time limit after that this might happen?
microcontroller avr atmega atmega328p
microcontroller avr atmega atmega328p
New contributor
thebear8 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
thebear8 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
thebear8 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
asked 9 hours ago
thebear8thebear8
132 bronze badges
132 bronze badges
New contributor
thebear8 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
thebear8 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
add a comment |
add a comment |
4 Answers
4
active
oldest
votes
$begingroup$
If nothing else is running in the MCU, then you are free to take as long as you like in the ISR. BUT, this is a bad habit to get into, and it means that if you want to do anything else, you'll likely have to rework the code.
A particular case is if the MCU is using a serial library, that expects interrupts to be working often enough to service individual characters received. At 115200 baud (a high serial speed often used to minimise download time), there is less than 100uS between characters. If you block the interrupts for longer than that, you risk losing input characters.
As a general rule, do the absolute minimum in an ISR. In your application, a reasonable design would be to have an interrupt every mS, which increments and checks a counter value. I'm sure you can work out some suitable logic to set and test the counter to get 200mS between turn on and turn off events.
$endgroup$
add a comment |
$begingroup$
While the practice is to allocate the minimum possible execution cycles inside an interruption, and beside other general hardware specifications, there are not technical limitations for increasing them, if there are not any other interruption to be executed.
At attachInterrupt() Arduino Reference:
Generally, an ISR should be as short and fast as possible. If your
sketch uses multiple ISRs, only one can run at a time, other
interrupts will be executed after the current one finishes in an order
that depends on the priority they have. millis() relies on interrupts
to count, so it will never increment inside an ISR. Since delay()
requires interrupts to work, it will not work if called inside an ISR.
micros() works initially but will start behaving erratically after 1-2
ms. delayMicroseconds() does not use any counter, so it will work as
normal.
Having 25 possible interruptions in this processor family, it is encouraged to deal with them like punctual events, for allowing other interruptions to happen.
$endgroup$
1
$begingroup$
While delay in an ISR is generally a bad idea, the question uses what appears to be avr-gcc's_delay_ms()which is cycles based unlike the Arduinodelay()function which relies on the timer interrupt.
$endgroup$
– Chris Stratton
8 hours ago
add a comment |
$begingroup$
In the worst case, an ISR can run until the next interrupt of the same type occurs again.
But in general, it's poor design practice to spend more time in an ISR than absolutely necessary, because it prevents all other code from running at all. This is a big issue for anything other than trivial programs.
$endgroup$
add a comment |
$begingroup$
You have a single-core, single-threaded CPU. This means that at any given time, it's doing exactly one thing. If your application requires it to do several things, then the code has to be designed to switch between all of them. This can be as trivial or as complex as you like.
Normally, the CPU putters around the main loop, doing whatever is in there, and that's all well and good until an interrupt occurs. The interrupt hardware basically forces a function call to the appropriate ISR, even though there's no call instruction for it in the main loop. This unpredictability is where most of the rules come from for writing ISR's.
Whatever time you spend in an ISR is time that the main loop is paused, waiting for the ISR to return. If the main loop is the only one to reset an active watchdog timer (very good practice), then the watchdog will not be reset during that time. If the watchdog times out, it gives you a hard reset. Just like the external reset, but with different flags that you can check on startup. This is probably the "crash" that you heard of.
It's very good practice to use the watchdog, and to only reset it once each trip around the main loop. This forces you to write code that stays responsive. If you need to wait for something, you can set up an event (timer finished, next character received, etc.), and move on. Check periodically for that event or set another interrupt for its completion, and get back to it then. Meanwhile, you continue with whatever else you were doing.
My main structure is typically something like this:
#include "module1.h"
#include "module2.h"
void main(void)
//overall
//chip
//setup
mod1_init();
mod2_init();
//clear interrupt flags
//global interrupt enable
while(1)
//clear watchdog
mod1_run();
mod2_run();
And my modules are like this:
void modX_init(void)
//hardware and variable init for this module only
//don't use interrupts if polling is good enough
void modX_run(void)
if (POLLED_INTERRUPT_FLAG)
POLLED_INTERRUPT_FLAG = 0;
//non-blocking "ISR" code
void ISR modX_ISR(void)
//okay, this does require an *immediate* response
//spend the absolute minimum time here and get out
The function signatures don't have to be void, but most of them are. Sometimes I'll have some broad timing in one module that is also used by another, and it's handy to use the return value of one modX_run() and the arguments of another (or some basic logic) to make that connection. For example:
if (DMX_run()) //includes its own timing, and returns true at the start of each 30Hz interval, otherwise false
I2C_start(); //I2C frames are sync'ed to DMX
I2C_run(); //once started, an I2C frame runs freely until finished
If you study the datasheet, you may also find that the hardware peripherals can be massaged to do what you want without any CPU intervention at all.
Output pulse generation, for example, is a common one. Turn it on, set the peripheral to turn it off some time later, and forget about it. It's typically in the same general area as PWM.
$endgroup$
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
return StackExchange.using("schematics", function ()
StackExchange.schematics.init();
);
, "cicuitlab");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "135"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
thebear8 is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2felectronics.stackexchange.com%2fquestions%2f447850%2fwhats-the-maximum-time-an-interrupt-service-routine-can-take-to-execute-on-atme%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
If nothing else is running in the MCU, then you are free to take as long as you like in the ISR. BUT, this is a bad habit to get into, and it means that if you want to do anything else, you'll likely have to rework the code.
A particular case is if the MCU is using a serial library, that expects interrupts to be working often enough to service individual characters received. At 115200 baud (a high serial speed often used to minimise download time), there is less than 100uS between characters. If you block the interrupts for longer than that, you risk losing input characters.
As a general rule, do the absolute minimum in an ISR. In your application, a reasonable design would be to have an interrupt every mS, which increments and checks a counter value. I'm sure you can work out some suitable logic to set and test the counter to get 200mS between turn on and turn off events.
$endgroup$
add a comment |
$begingroup$
If nothing else is running in the MCU, then you are free to take as long as you like in the ISR. BUT, this is a bad habit to get into, and it means that if you want to do anything else, you'll likely have to rework the code.
A particular case is if the MCU is using a serial library, that expects interrupts to be working often enough to service individual characters received. At 115200 baud (a high serial speed often used to minimise download time), there is less than 100uS between characters. If you block the interrupts for longer than that, you risk losing input characters.
As a general rule, do the absolute minimum in an ISR. In your application, a reasonable design would be to have an interrupt every mS, which increments and checks a counter value. I'm sure you can work out some suitable logic to set and test the counter to get 200mS between turn on and turn off events.
$endgroup$
add a comment |
$begingroup$
If nothing else is running in the MCU, then you are free to take as long as you like in the ISR. BUT, this is a bad habit to get into, and it means that if you want to do anything else, you'll likely have to rework the code.
A particular case is if the MCU is using a serial library, that expects interrupts to be working often enough to service individual characters received. At 115200 baud (a high serial speed often used to minimise download time), there is less than 100uS between characters. If you block the interrupts for longer than that, you risk losing input characters.
As a general rule, do the absolute minimum in an ISR. In your application, a reasonable design would be to have an interrupt every mS, which increments and checks a counter value. I'm sure you can work out some suitable logic to set and test the counter to get 200mS between turn on and turn off events.
$endgroup$
If nothing else is running in the MCU, then you are free to take as long as you like in the ISR. BUT, this is a bad habit to get into, and it means that if you want to do anything else, you'll likely have to rework the code.
A particular case is if the MCU is using a serial library, that expects interrupts to be working often enough to service individual characters received. At 115200 baud (a high serial speed often used to minimise download time), there is less than 100uS between characters. If you block the interrupts for longer than that, you risk losing input characters.
As a general rule, do the absolute minimum in an ISR. In your application, a reasonable design would be to have an interrupt every mS, which increments and checks a counter value. I'm sure you can work out some suitable logic to set and test the counter to get 200mS between turn on and turn off events.
answered 9 hours ago
Neil_UKNeil_UK
83.2k2 gold badges85 silver badges192 bronze badges
83.2k2 gold badges85 silver badges192 bronze badges
add a comment |
add a comment |
$begingroup$
While the practice is to allocate the minimum possible execution cycles inside an interruption, and beside other general hardware specifications, there are not technical limitations for increasing them, if there are not any other interruption to be executed.
At attachInterrupt() Arduino Reference:
Generally, an ISR should be as short and fast as possible. If your
sketch uses multiple ISRs, only one can run at a time, other
interrupts will be executed after the current one finishes in an order
that depends on the priority they have. millis() relies on interrupts
to count, so it will never increment inside an ISR. Since delay()
requires interrupts to work, it will not work if called inside an ISR.
micros() works initially but will start behaving erratically after 1-2
ms. delayMicroseconds() does not use any counter, so it will work as
normal.
Having 25 possible interruptions in this processor family, it is encouraged to deal with them like punctual events, for allowing other interruptions to happen.
$endgroup$
1
$begingroup$
While delay in an ISR is generally a bad idea, the question uses what appears to be avr-gcc's_delay_ms()which is cycles based unlike the Arduinodelay()function which relies on the timer interrupt.
$endgroup$
– Chris Stratton
8 hours ago
add a comment |
$begingroup$
While the practice is to allocate the minimum possible execution cycles inside an interruption, and beside other general hardware specifications, there are not technical limitations for increasing them, if there are not any other interruption to be executed.
At attachInterrupt() Arduino Reference:
Generally, an ISR should be as short and fast as possible. If your
sketch uses multiple ISRs, only one can run at a time, other
interrupts will be executed after the current one finishes in an order
that depends on the priority they have. millis() relies on interrupts
to count, so it will never increment inside an ISR. Since delay()
requires interrupts to work, it will not work if called inside an ISR.
micros() works initially but will start behaving erratically after 1-2
ms. delayMicroseconds() does not use any counter, so it will work as
normal.
Having 25 possible interruptions in this processor family, it is encouraged to deal with them like punctual events, for allowing other interruptions to happen.
$endgroup$
1
$begingroup$
While delay in an ISR is generally a bad idea, the question uses what appears to be avr-gcc's_delay_ms()which is cycles based unlike the Arduinodelay()function which relies on the timer interrupt.
$endgroup$
– Chris Stratton
8 hours ago
add a comment |
$begingroup$
While the practice is to allocate the minimum possible execution cycles inside an interruption, and beside other general hardware specifications, there are not technical limitations for increasing them, if there are not any other interruption to be executed.
At attachInterrupt() Arduino Reference:
Generally, an ISR should be as short and fast as possible. If your
sketch uses multiple ISRs, only one can run at a time, other
interrupts will be executed after the current one finishes in an order
that depends on the priority they have. millis() relies on interrupts
to count, so it will never increment inside an ISR. Since delay()
requires interrupts to work, it will not work if called inside an ISR.
micros() works initially but will start behaving erratically after 1-2
ms. delayMicroseconds() does not use any counter, so it will work as
normal.
Having 25 possible interruptions in this processor family, it is encouraged to deal with them like punctual events, for allowing other interruptions to happen.
$endgroup$
While the practice is to allocate the minimum possible execution cycles inside an interruption, and beside other general hardware specifications, there are not technical limitations for increasing them, if there are not any other interruption to be executed.
At attachInterrupt() Arduino Reference:
Generally, an ISR should be as short and fast as possible. If your
sketch uses multiple ISRs, only one can run at a time, other
interrupts will be executed after the current one finishes in an order
that depends on the priority they have. millis() relies on interrupts
to count, so it will never increment inside an ISR. Since delay()
requires interrupts to work, it will not work if called inside an ISR.
micros() works initially but will start behaving erratically after 1-2
ms. delayMicroseconds() does not use any counter, so it will work as
normal.
Having 25 possible interruptions in this processor family, it is encouraged to deal with them like punctual events, for allowing other interruptions to happen.
edited 9 hours ago
answered 9 hours ago
BrethloszeBrethlosze
4962 silver badges17 bronze badges
4962 silver badges17 bronze badges
1
$begingroup$
While delay in an ISR is generally a bad idea, the question uses what appears to be avr-gcc's_delay_ms()which is cycles based unlike the Arduinodelay()function which relies on the timer interrupt.
$endgroup$
– Chris Stratton
8 hours ago
add a comment |
1
$begingroup$
While delay in an ISR is generally a bad idea, the question uses what appears to be avr-gcc's_delay_ms()which is cycles based unlike the Arduinodelay()function which relies on the timer interrupt.
$endgroup$
– Chris Stratton
8 hours ago
1
1
$begingroup$
While delay in an ISR is generally a bad idea, the question uses what appears to be avr-gcc's
_delay_ms() which is cycles based unlike the Arduino delay() function which relies on the timer interrupt.$endgroup$
– Chris Stratton
8 hours ago
$begingroup$
While delay in an ISR is generally a bad idea, the question uses what appears to be avr-gcc's
_delay_ms() which is cycles based unlike the Arduino delay() function which relies on the timer interrupt.$endgroup$
– Chris Stratton
8 hours ago
add a comment |
$begingroup$
In the worst case, an ISR can run until the next interrupt of the same type occurs again.
But in general, it's poor design practice to spend more time in an ISR than absolutely necessary, because it prevents all other code from running at all. This is a big issue for anything other than trivial programs.
$endgroup$
add a comment |
$begingroup$
In the worst case, an ISR can run until the next interrupt of the same type occurs again.
But in general, it's poor design practice to spend more time in an ISR than absolutely necessary, because it prevents all other code from running at all. This is a big issue for anything other than trivial programs.
$endgroup$
add a comment |
$begingroup$
In the worst case, an ISR can run until the next interrupt of the same type occurs again.
But in general, it's poor design practice to spend more time in an ISR than absolutely necessary, because it prevents all other code from running at all. This is a big issue for anything other than trivial programs.
$endgroup$
In the worst case, an ISR can run until the next interrupt of the same type occurs again.
But in general, it's poor design practice to spend more time in an ISR than absolutely necessary, because it prevents all other code from running at all. This is a big issue for anything other than trivial programs.
answered 9 hours ago
Dave Tweed♦Dave Tweed
130k10 gold badges164 silver badges278 bronze badges
130k10 gold badges164 silver badges278 bronze badges
add a comment |
add a comment |
$begingroup$
You have a single-core, single-threaded CPU. This means that at any given time, it's doing exactly one thing. If your application requires it to do several things, then the code has to be designed to switch between all of them. This can be as trivial or as complex as you like.
Normally, the CPU putters around the main loop, doing whatever is in there, and that's all well and good until an interrupt occurs. The interrupt hardware basically forces a function call to the appropriate ISR, even though there's no call instruction for it in the main loop. This unpredictability is where most of the rules come from for writing ISR's.
Whatever time you spend in an ISR is time that the main loop is paused, waiting for the ISR to return. If the main loop is the only one to reset an active watchdog timer (very good practice), then the watchdog will not be reset during that time. If the watchdog times out, it gives you a hard reset. Just like the external reset, but with different flags that you can check on startup. This is probably the "crash" that you heard of.
It's very good practice to use the watchdog, and to only reset it once each trip around the main loop. This forces you to write code that stays responsive. If you need to wait for something, you can set up an event (timer finished, next character received, etc.), and move on. Check periodically for that event or set another interrupt for its completion, and get back to it then. Meanwhile, you continue with whatever else you were doing.
My main structure is typically something like this:
#include "module1.h"
#include "module2.h"
void main(void)
//overall
//chip
//setup
mod1_init();
mod2_init();
//clear interrupt flags
//global interrupt enable
while(1)
//clear watchdog
mod1_run();
mod2_run();
And my modules are like this:
void modX_init(void)
//hardware and variable init for this module only
//don't use interrupts if polling is good enough
void modX_run(void)
if (POLLED_INTERRUPT_FLAG)
POLLED_INTERRUPT_FLAG = 0;
//non-blocking "ISR" code
void ISR modX_ISR(void)
//okay, this does require an *immediate* response
//spend the absolute minimum time here and get out
The function signatures don't have to be void, but most of them are. Sometimes I'll have some broad timing in one module that is also used by another, and it's handy to use the return value of one modX_run() and the arguments of another (or some basic logic) to make that connection. For example:
if (DMX_run()) //includes its own timing, and returns true at the start of each 30Hz interval, otherwise false
I2C_start(); //I2C frames are sync'ed to DMX
I2C_run(); //once started, an I2C frame runs freely until finished
If you study the datasheet, you may also find that the hardware peripherals can be massaged to do what you want without any CPU intervention at all.
Output pulse generation, for example, is a common one. Turn it on, set the peripheral to turn it off some time later, and forget about it. It's typically in the same general area as PWM.
$endgroup$
add a comment |
$begingroup$
You have a single-core, single-threaded CPU. This means that at any given time, it's doing exactly one thing. If your application requires it to do several things, then the code has to be designed to switch between all of them. This can be as trivial or as complex as you like.
Normally, the CPU putters around the main loop, doing whatever is in there, and that's all well and good until an interrupt occurs. The interrupt hardware basically forces a function call to the appropriate ISR, even though there's no call instruction for it in the main loop. This unpredictability is where most of the rules come from for writing ISR's.
Whatever time you spend in an ISR is time that the main loop is paused, waiting for the ISR to return. If the main loop is the only one to reset an active watchdog timer (very good practice), then the watchdog will not be reset during that time. If the watchdog times out, it gives you a hard reset. Just like the external reset, but with different flags that you can check on startup. This is probably the "crash" that you heard of.
It's very good practice to use the watchdog, and to only reset it once each trip around the main loop. This forces you to write code that stays responsive. If you need to wait for something, you can set up an event (timer finished, next character received, etc.), and move on. Check periodically for that event or set another interrupt for its completion, and get back to it then. Meanwhile, you continue with whatever else you were doing.
My main structure is typically something like this:
#include "module1.h"
#include "module2.h"
void main(void)
//overall
//chip
//setup
mod1_init();
mod2_init();
//clear interrupt flags
//global interrupt enable
while(1)
//clear watchdog
mod1_run();
mod2_run();
And my modules are like this:
void modX_init(void)
//hardware and variable init for this module only
//don't use interrupts if polling is good enough
void modX_run(void)
if (POLLED_INTERRUPT_FLAG)
POLLED_INTERRUPT_FLAG = 0;
//non-blocking "ISR" code
void ISR modX_ISR(void)
//okay, this does require an *immediate* response
//spend the absolute minimum time here and get out
The function signatures don't have to be void, but most of them are. Sometimes I'll have some broad timing in one module that is also used by another, and it's handy to use the return value of one modX_run() and the arguments of another (or some basic logic) to make that connection. For example:
if (DMX_run()) //includes its own timing, and returns true at the start of each 30Hz interval, otherwise false
I2C_start(); //I2C frames are sync'ed to DMX
I2C_run(); //once started, an I2C frame runs freely until finished
If you study the datasheet, you may also find that the hardware peripherals can be massaged to do what you want without any CPU intervention at all.
Output pulse generation, for example, is a common one. Turn it on, set the peripheral to turn it off some time later, and forget about it. It's typically in the same general area as PWM.
$endgroup$
add a comment |
$begingroup$
You have a single-core, single-threaded CPU. This means that at any given time, it's doing exactly one thing. If your application requires it to do several things, then the code has to be designed to switch between all of them. This can be as trivial or as complex as you like.
Normally, the CPU putters around the main loop, doing whatever is in there, and that's all well and good until an interrupt occurs. The interrupt hardware basically forces a function call to the appropriate ISR, even though there's no call instruction for it in the main loop. This unpredictability is where most of the rules come from for writing ISR's.
Whatever time you spend in an ISR is time that the main loop is paused, waiting for the ISR to return. If the main loop is the only one to reset an active watchdog timer (very good practice), then the watchdog will not be reset during that time. If the watchdog times out, it gives you a hard reset. Just like the external reset, but with different flags that you can check on startup. This is probably the "crash" that you heard of.
It's very good practice to use the watchdog, and to only reset it once each trip around the main loop. This forces you to write code that stays responsive. If you need to wait for something, you can set up an event (timer finished, next character received, etc.), and move on. Check periodically for that event or set another interrupt for its completion, and get back to it then. Meanwhile, you continue with whatever else you were doing.
My main structure is typically something like this:
#include "module1.h"
#include "module2.h"
void main(void)
//overall
//chip
//setup
mod1_init();
mod2_init();
//clear interrupt flags
//global interrupt enable
while(1)
//clear watchdog
mod1_run();
mod2_run();
And my modules are like this:
void modX_init(void)
//hardware and variable init for this module only
//don't use interrupts if polling is good enough
void modX_run(void)
if (POLLED_INTERRUPT_FLAG)
POLLED_INTERRUPT_FLAG = 0;
//non-blocking "ISR" code
void ISR modX_ISR(void)
//okay, this does require an *immediate* response
//spend the absolute minimum time here and get out
The function signatures don't have to be void, but most of them are. Sometimes I'll have some broad timing in one module that is also used by another, and it's handy to use the return value of one modX_run() and the arguments of another (or some basic logic) to make that connection. For example:
if (DMX_run()) //includes its own timing, and returns true at the start of each 30Hz interval, otherwise false
I2C_start(); //I2C frames are sync'ed to DMX
I2C_run(); //once started, an I2C frame runs freely until finished
If you study the datasheet, you may also find that the hardware peripherals can be massaged to do what you want without any CPU intervention at all.
Output pulse generation, for example, is a common one. Turn it on, set the peripheral to turn it off some time later, and forget about it. It's typically in the same general area as PWM.
$endgroup$
You have a single-core, single-threaded CPU. This means that at any given time, it's doing exactly one thing. If your application requires it to do several things, then the code has to be designed to switch between all of them. This can be as trivial or as complex as you like.
Normally, the CPU putters around the main loop, doing whatever is in there, and that's all well and good until an interrupt occurs. The interrupt hardware basically forces a function call to the appropriate ISR, even though there's no call instruction for it in the main loop. This unpredictability is where most of the rules come from for writing ISR's.
Whatever time you spend in an ISR is time that the main loop is paused, waiting for the ISR to return. If the main loop is the only one to reset an active watchdog timer (very good practice), then the watchdog will not be reset during that time. If the watchdog times out, it gives you a hard reset. Just like the external reset, but with different flags that you can check on startup. This is probably the "crash" that you heard of.
It's very good practice to use the watchdog, and to only reset it once each trip around the main loop. This forces you to write code that stays responsive. If you need to wait for something, you can set up an event (timer finished, next character received, etc.), and move on. Check periodically for that event or set another interrupt for its completion, and get back to it then. Meanwhile, you continue with whatever else you were doing.
My main structure is typically something like this:
#include "module1.h"
#include "module2.h"
void main(void)
//overall
//chip
//setup
mod1_init();
mod2_init();
//clear interrupt flags
//global interrupt enable
while(1)
//clear watchdog
mod1_run();
mod2_run();
And my modules are like this:
void modX_init(void)
//hardware and variable init for this module only
//don't use interrupts if polling is good enough
void modX_run(void)
if (POLLED_INTERRUPT_FLAG)
POLLED_INTERRUPT_FLAG = 0;
//non-blocking "ISR" code
void ISR modX_ISR(void)
//okay, this does require an *immediate* response
//spend the absolute minimum time here and get out
The function signatures don't have to be void, but most of them are. Sometimes I'll have some broad timing in one module that is also used by another, and it's handy to use the return value of one modX_run() and the arguments of another (or some basic logic) to make that connection. For example:
if (DMX_run()) //includes its own timing, and returns true at the start of each 30Hz interval, otherwise false
I2C_start(); //I2C frames are sync'ed to DMX
I2C_run(); //once started, an I2C frame runs freely until finished
If you study the datasheet, you may also find that the hardware peripherals can be massaged to do what you want without any CPU intervention at all.
Output pulse generation, for example, is a common one. Turn it on, set the peripheral to turn it off some time later, and forget about it. It's typically in the same general area as PWM.
answered 14 mins ago
AaronDAaronD
4,2895 silver badges28 bronze badges
4,2895 silver badges28 bronze badges
add a comment |
add a comment |
thebear8 is a new contributor. Be nice, and check out our Code of Conduct.
thebear8 is a new contributor. Be nice, and check out our Code of Conduct.
thebear8 is a new contributor. Be nice, and check out our Code of Conduct.
thebear8 is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Electrical Engineering Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2felectronics.stackexchange.com%2fquestions%2f447850%2fwhats-the-maximum-time-an-interrupt-service-routine-can-take-to-execute-on-atme%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown