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:
  • 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:
  • 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:
  • 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:
  • use volatile for 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:
  • 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.

  • 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:
  • 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:
  • 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:
  • variable-length operations
  • data-dependent loops

Determinism is the foundation of real-time behavior.
An ISR should do just enough work to defer the rest.
Anything more risks the stability of the entire system.