ISR Rules That Prevent System Crashes
Interrupts don’t forgive mistakes.
They run anytime.
They must finish fast and leave a clean state.
1. Keep It Short
An ISR runs with high priority and blocks other work.
Do the minimum required:
Long ISRs increase:
Do the minimum required:
- Capture the event, set a flag, and exit.
Long ISRs increase:
- interrupt latency across the system
- the likelihood of missed deadlines
- overall system jitter
2. Avoid Heavy Operations
Inside an ISR, you must strictly avoid:
These make execution time unpredictable and can completely stall the system.
- loops waiting on conditions
- dynamic memory allocation (
malloc/free) - complex mathematical calculations
These make execution time unpredictable and can completely stall the system.
3. No Blocking Calls
Never call code that can block.
This includes:
An ISR must never wait. It should react and return immediately.
This includes:
- software delays
- polling loops (waiting for slow peripherals)
- mutex locks or thread suspensions
An ISR must never wait. It should react and return immediately.
4. Protect Shared Data
ISRs and main code share data asynchronously—usually by interrupting the main code
mid-operation.
Rules for safety:
Without this:
Rules for safety:
- use
volatilefor shared variables so the compiler doesn't cache them - ensure atomic access where required
Without this:
- silent data corruption
- catastrophic race conditions
- inconsistent reads
5. Avoid Read-Modify-Write on Shared State
If both the ISR and main loop modify the exact same variable:
one update can invisibly overwrite the other.
Always use:
one update can invisibly overwrite the other.
Always use:
- atomic operations
- critical sections (briefly disabling interrupts in the main code to perform the write safely)
6. Be Careful with Stack Usage
ISRs generally use the same runtime stack as normal code in many bare-metal systems.
Keep the ISR's stack footprint as minimal as possible. Do not declare large arrays inside them.
- large local variables → rapid stack overflow
- deep call chains → extreme crash risk
Keep the ISR's stack footprint as minimal as possible. Do not declare large arrays inside them.
7. Clear the Interrupt Source
Always clear the interrupt flag correctly before exiting.
If you fail to do this:
Follow hardware-specific behavior strictly (e.g., write-1-to-clear, read-to-clear).
If you fail to do this:
- the ISR may retrigger immediately upon exiting
- the system will permanently lock inside an infinite interrupt loop
Follow hardware-specific behavior strictly (e.g., write-1-to-clear, read-to-clear).
8. Limit Nested Interrupt Impact
Allowing interrupts to be interrupted (nesting) is a powerful, dangerous technique.
Frequent or heavily nested interrupts can:
Design your interrupt priorities carefully and avoid excessive trigger rates across multiple lines.
Frequent or heavily nested interrupts can:
- starve the main execution entirely indefinitely
- increase latency unpredictably
Design your interrupt priorities carefully and avoid excessive trigger rates across multiple lines.
9. Deterministic Execution
ISR execution time must be perfectly predictable.
Avoid:
Determinism is the foundation of real-time behavior.
Next
→ Delays in ISRs
Avoid:
- variable-length operations
- data-dependent loops
Determinism is the foundation of real-time behavior.