Files
embedded-programming/interrupts/pin-interrupt-notes.md
2026-04-03 23:25:16 +11:00

210 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# External Interrupt Configuration (ATmega328P)
## SREG (Status Register)
SREG is AVR status register with 8-bit status:
- Bit 0 → Carry Flag (C) for ALU operations
- Bit 1 → Zero Flag (Z) result is zero
- Bit 2 → Negative Flag (N) result is negative
- Bit 3 → Twos Complement Overflow Flag (V) arithmetic overflow
- Bit 4 → Sign Bit (S) N ⊕ V
- Bit 5 → Half Carry Flag (H) carry from bit 3 to 4
- Bit 6 → Bit Copy Storage (T) used in bit operations
- Bit 7 → Global Interrupt Enable (I) Important for interrupt
### Enable Global Interrupt
SREG |= (1 << 7);
// or
sei();
### Disable Global Interrupt
SREG &= ~(1 << 7);
// or
cli();
---
## External Interrupt Pins
- PD2 → INT0
- PD3 → INT1
---
## EICRA (External Interrupt Control Register A)
Controls how external interrupts trigger.
### ISC (Interrupt Sense Control)
| ISCx1 | ISCx0 | Mode |
|------|------|--------------------|
| 0 | 0 | Low Level |
| 0 | 1 | Any Logical Change |
| 1 | 0 | Falling Edge |
| 1 | 1 | Rising Edge |
### Bit Positions
- INT0 → ISC01 (bit1), ISC00 (bit0)
- INT1 → ISC11 (bit3), ISC10 (bit2)
---
# Interrupt Trigger Modes (INT0)
## 1. Low Level (00)
EICRA &= ~((1 << ISC01) | (1 << ISC00));
Bit calculation:
- (1 << ISC01) = 00000010
- (1 << ISC00) = 00000001
- OR = 00000011
- NOT = 11111100
- Result → ISC01=0, ISC00=0
---
## 2. Any Logical Change (01)
EICRA &= ~(1 << ISC01);
EICRA |= (1 << ISC00);
Bit calculation:
- Clear ISC01 → 0
- Set ISC00 → 1
- Result → 01
---
## 3. Falling Edge (10)
EICRA |= (1 << ISC01);
EICRA &= ~(1 << ISC00);
Bit calculation:
- Set ISC01 → 1
- Clear ISC00 → 0
- Result → 10
---
## 4. Rising Edge (11)
EICRA |= (1 << ISC01) | (1 << ISC00);
Bit calculation:
- (1 << ISC01) = 00000010
- (1 << ISC00) = 00000001
- OR = 00000011
- Result → ISC01=1, ISC00=1
---
## INT1 (Same Logic)
Replace:
- ISC01 → ISC11
- ISC00 → ISC10
Example (Rising Edge INT1):
EICRA |= (1 << ISC11) | (1 << ISC10);
---
# Practical Note (Real Hardware Behavior)
- Button press is not 100% stable
- Causes:
- Mechanical bounce
- Loose wiring / plug-in noise
- Floating inputs
### Recommendation
- Avoid: Any Logical Change (too sensitive)
- Prefer:
- Falling Edge (more stable detection)
- Or implement HOLD logic in software
---
## EIMSK (External Interrupt Mask Register)
Controls enabling/disabling of interrupts.
### Bit Positions
- Bit 0 → INT0 enable
- Bit 1 → INT1 enable
---
## Enable / Disable Interrupt Lines
### Enable INT0
EIMSK |= (1 << INT0);
### Disable INT1
EIMSK &= ~(1 << INT1);
---
## Why Disable Unused Interrupts
- Prevent false triggering from floating pins
- Reduce noise impact
- Ensure controlled initialization
- Avoid unintended behaviour
---
## Interrupt Execution Flow
1. Configure trigger in EICRA
2. Enable interrupt in EIMSK
3. Enable global interrupt (sei)
4. Event occurs → CPU jumps to ISR
---
## ISR (Interrupt Service Routine)
ISR is executed automatically when interrupt occurs.
---
## Flag-Based Handling
### Global Flag
volatile uint8_t flag = 0;
- `volatile` required (value changes outside normal flow)
---
## ISR Definitions
### INT0 Interrupt
ISR(INT0_vect)
{
flag = 1;
}
### INT1 Interrupt
ISR(INT1_vect)
{
flag = 1;
}
---
## Important Notes
- Keep ISR short
- No delay or heavy processing inside ISR
- Use flag and handle logic in main loop
- Always use `volatile` for shared variables