Giao diện
⚡ Interrupts — ISR Basics
Interrupt cho phép hardware ngắt CPU để xử lý events quan trọng ngay lập tức.
Analogy: Chuông cửa
┌─────────────────────────────────────────────────────────────────┐
│ DOORBELL ANALOGY │
├─────────────────────────────────────────────────────────────────┤
│ │
│ POLLING (Không có interrupt): │
│ ────────────────────────────── │
│ Bạn đang nấu ăn → đi ra cửa kiểm tra → không có ai │
│ Quay lại nấu → 5 phút sau → đi ra kiểm tra → không có ai │
│ → Mất thời gian, có thể bỏ lỡ khách! │
│ │
│ INTERRUPT (Có interrupt): │
│ ───────────────────────── │
│ Bạn đang nấu ăn │
│ 🔔 DING DONG! (Chuông reo) │
│ → Dừng nấu → Mở cửa → Xử lý khách → Quay lại nấu │
│ │
│ CPU = Bạn │
│ Nấu ăn = Main program │
│ Chuông = Interrupt signal │
│ Mở cửa = ISR (Interrupt Service Routine) │
│ │
└─────────────────────────────────────────────────────────────────┘1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
How Interrupts Work
┌─────────────────────────────────────────────────────────────────┐
│ INTERRUPT FLOW │
├─────────────────────────────────────────────────────────────────┤
│ │
│ main() running │
│ │ │
│ │ ←──── 🔔 Hardware event (button press, timer, UART) │
│ │ │
│ ├─────► CPU saves context (registers, PC) │
│ │ │
│ │ ┌─────────────────────┐ │
│ │ │ ISR (short & fast!) │ │
│ │ │ • Read hardware │ │
│ │ │ • Set flag │ │
│ │ │ • Clear interrupt │ │
│ │ └─────────────────────┘ │
│ │ │
│ ├─────► CPU restores context │
│ │ │
│ ▼ main() continues from where it stopped │
│ │
└─────────────────────────────────────────────────────────────────┘1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ISR Example
cpp
#include <cstdint>
// Shared flag - MUST be volatile!
volatile bool buttonPressed = false;
volatile uint32_t systemTicks = 0;
// Button interrupt handler
extern "C" void EXTI0_IRQHandler() {
// 1. Check if our interrupt
if (EXTI->PR & (1 << 0)) {
// 2. Do minimal work
buttonPressed = true;
// 3. Clear interrupt flag
EXTI->PR = (1 << 0);
}
}
// System tick interrupt (every 1ms)
extern "C" void SysTick_Handler() {
systemTicks++;
}
int main() {
setupButton();
setupSysTick();
while (true) {
// Main loop - process flags set by ISR
if (buttonPressed) {
buttonPressed = false;
handleButtonPress(); // Heavy work here, not in ISR!
}
// Use tick count for timing
static uint32_t lastTick = 0;
if (systemTicks - lastTick >= 1000) {
lastTick = systemTicks;
blinkLED();
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
ISR Rules — Keep It Short!
⚠️ GOLDEN RULES
- Keep ISRs SHORT — Microseconds, not milliseconds!
- No blocking — No delays, no waiting for I/O
- Volatile variables — For data shared with main
- Clear interrupt flag — Or interrupt fires again!
- No heap allocation — No
new,malloc,std::vector
cpp
// ❌ BAD ISR - Too long!
extern "C" void UART_IRQHandler() {
char buffer[100];
readString(buffer); // Blocking!
processString(buffer); // Takes too long!
sendResponse(buffer); // More blocking!
}
// ✅ GOOD ISR - Just set flag
volatile bool dataReady = false;
volatile uint8_t rxByte;
extern "C" void UART_IRQHandler() {
rxByte = UART->DR; // Read byte
dataReady = true; // Set flag
UART->SR &= ~UART_SR_RXNE; // Clear flag
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Disabling Interrupts
Đôi khi cần disable interrupts để protect shared data:
cpp
// Critical section - no interrupts
inline void disableInterrupts() {
__disable_irq(); // ARM Cortex-M intrinsic
}
inline void enableInterrupts() {
__enable_irq();
}
// RAII pattern
class CriticalSection {
uint32_t primask_;
public:
CriticalSection() {
primask_ = __get_PRIMASK();
__disable_irq();
}
~CriticalSection() {
__set_PRIMASK(primask_);
}
};
// Usage
void safeIncrement() {
CriticalSection cs;
sharedCounter++; // Safe from interrupts
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Common Interrupt Sources
| Source | Typical Use |
|---|---|
| Timer | Periodic tasks, PWM, delays |
| UART/USART | Serial communication |
| GPIO/EXTI | Button press, sensors |
| ADC | Analog conversion complete |
| DMA | Data transfer complete |
| I2C/SPI | Communication events |
Interrupt Priority
cpp
// Higher priority = handles first
// Lower number = higher priority (ARM Cortex-M)
// Set priority: UART is more important than Timer
NVIC_SetPriority(UART1_IRQn, 1); // High priority
NVIC_SetPriority(TIM2_IRQn, 3); // Lower priority
// Enable interrupts
NVIC_EnableIRQ(UART1_IRQn);
NVIC_EnableIRQ(TIM2_IRQn);1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
┌─────────────────────────────────────────────────────────────────┐
│ NESTED INTERRUPTS │
├─────────────────────────────────────────────────────────────────┤
│ │
│ main() │
│ │ │
│ │ ←── Timer interrupt (priority 3) │
│ │ │ │
│ │ │ ←── UART interrupt (priority 1) ← Preempts Timer! │
│ │ │ │ │
│ │ │ └─ UART ISR finishes │
│ │ │ │
│ │ └─── Timer ISR finishes │
│ │ │
│ ▼ main() continues │
│ │
└─────────────────────────────────────────────────────────────────┘1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
📚 Tổng kết
| Aspect | Rule |
|---|---|
| ISR Length | As short as possible |
| Shared Variables | Must be volatile |
| Heavy Work | Do in main(), not ISR |
| Interrupt Flag | Always clear it |
| Critical Sections | Disable interrupts briefly |
🎯 Module Complete!
Bạn đã hoàn thành Module 8: Embedded Programming:
- ✅ Memory Constraints
- ✅ Bit Manipulation
- ✅ volatile Keyword
- ✅ Smart Pointers in Embedded
- ✅ Interrupts (ISR)
Welcome to the world of embedded systems! 🔌