⚡ hal::exti
External Interrupts - GPIO Pin Event Detection
~360 satır
~15 fonksiyon
STM32/GD32/ESP32
📖 Genel Bakış
EXTI modülü, GPIO pinlerinde meydana gelen değişiklikleri (rising edge, falling edge) yakalayarak interrupt üretir. Buton basımları, harici sensör sinyalleri ve asenkron olaylar için kritik öneme sahiptir. Polling gerektirmeden düşük güç tüketimi ve yüksek tepki süresi sağlar.
🔑 Temel Özellikler
- 16 EXTI Hattı: EXTI0-EXTI15 (GPIO pinleri için)
- Trigger Modları: Rising edge, falling edge veya her ikisi
- Maskeleme: Interrupt enable/disable desteği
- Software Interrupt: Yazılımdan interrupt tetikleme
- Event Mode: Interrupt olmadan DMA tetikleme
- Wake-up Source: Stop/Standby modundan çıkış
- Debounce Desteği: Yazılım bazlı gürültü filtreleme
- Priority Control: NVIC ile öncelik yönetimi
🚀 Hızlı Başlangıç
içe_aktar hal::exti, hal::gpio, hal::nvic
// Button pin setup (PA0 - User Button)
gpio.pin_init(gpio.PORT_A, 0, yap
mode: gpio.MODE_INPUT,
pull: gpio.PULL_DOWN,
speed: gpio.SPEED_LOW
son)
// EXTI configuration (falling edge for button press)
değişken exti_cfg = exti.init(0, yap // EXTI line 0 -> PA0
trigger: exti.TRIGGER_FALLING,
mode: exti.MODE_INTERRUPT,
callback: buton_callback
son)
// Enable interrupt in NVIC
nvic.enable_irq(nvic.EXTI0_IRQn, yap
priority: 5
son)
// Callback function
fonksiyon buton_callback() yap
// Button pressed!
led_toggle()
son
📦 Tipler ve Enum'lar
// EXTI Lines (0-15 for GPIO pins)
enum Line {
LINE_0, LINE_1, LINE_2, LINE_3, LINE_4,
LINE_5, LINE_6, LINE_7, LINE_8, LINE_9,
LINE_10, LINE_11, LINE_12, LINE_13, LINE_14, LINE_15,
LINE_PVD = 16, // PVD output
LINE_RTC = 17, // RTC alarm
LINE_USB = 18, // USB wakeup
LINE_ETH = 19 // Ethernet wakeup
}
// Trigger Mode
enum Trigger {
TRIGGER_RISING, // 0->1 transition
TRIGGER_FALLING, // 1->0 transition
TRIGGER_BOTH // Any edge
}
// EXTI Mode
enum Mode {
MODE_INTERRUPT, // Generate interrupt
MODE_EVENT // Generate event (for DMA)
}
yapı EXTIConfig yap
trigger: Trigger,
mode: Mode,
callback: fonksiyon(),
debounce_ms: sayı = 0 // Software debounce
son
💡 Örnek 1: Button with Debounce
Problem: Mekanik butonlarda bouncing problemi
içe_aktar hal::exti, hal::gpio, hal::systick
değişken son_basin_zamani: sayı64 = 0
sabit DEBOUNCE_SURESI: sayı = 50 // 50 ms
fonksiyon buton_init() yap
// PA0 -> User Button (Active Low)
gpio.pin_init(gpio.PORT_A, 0, yap
mode: gpio.MODE_INPUT,
pull: gpio.PULL_UP
son)
// EXTI0 -> Falling edge (button press)
exti.init(0, yap
trigger: exti.TRIGGER_FALLING,
mode: exti.MODE_INTERRUPT,
callback: buton_handler
son)
nvic.enable_irq(nvic.EXTI0_IRQn, 5)
son
fonksiyon buton_handler() yap
değişken simdiki_zaman = systick.get_ms()
// Debounce check
eğer (simdiki_zaman - son_basin_zamani < DEBOUNCE_SURESI) yap
dön // Ignore bouncing
son
son_basin_zamani = simdiki_zaman
// Real button press detected
buton_basildi()
son
fonksiyon buton_basildi() yap
io.yazdir_satır("Button pressed!")
led_toggle()
son
Çıktı: Bouncing problemi olmadan temiz buton algılama. 50ms içinde tekrar tetiklemeleri filtreler.
💡 Örnek 2: Rotary Encoder (Quadrature Decoder)
Problem: Mekanik encoder ile konum okuma
içe_aktar hal::exti, hal::gpio
değişken encoder_konum: sayı = 0
değişken son_A: mantık = yanlış
değişken son_B: mantık = yanlış
fonksiyon encoder_init() yap
// PA1 -> Encoder A channel
gpio.pin_init(gpio.PORT_A, 1, yap
mode: gpio.MODE_INPUT,
pull: gpio.PULL_UP
son)
// PA2 -> Encoder B channel
gpio.pin_init(gpio.PORT_A, 2, yap
mode: gpio.MODE_INPUT,
pull: gpio.PULL_UP
son)
// EXTI on both channels (both edges)
exti.init(1, yap
trigger: exti.TRIGGER_BOTH,
callback: encoder_A_handler
son)
exti.init(2, yap
trigger: exti.TRIGGER_BOTH,
callback: encoder_B_handler
son)
nvic.enable_irq(nvic.EXTI1_IRQn, 5)
nvic.enable_irq(nvic.EXTI2_IRQn, 5)
// Read initial state
son_A = gpio.pin_read(gpio.PORT_A, 1)
son_B = gpio.pin_read(gpio.PORT_A, 2)
son
fonksiyon encoder_A_handler() yap
değişken A = gpio.pin_read(gpio.PORT_A, 1)
değişken B = son_B
// Quadrature decoding logic
eğer (A != son_A) yap
eğer (A == B) yap
encoder_konum = encoder_konum + 1 // CW
yoksa yap
encoder_konum = encoder_konum - 1 // CCW
son
son
son_A = A
son
fonksiyon encoder_B_handler() yap
değişken A = son_A
değişken B = gpio.pin_read(gpio.PORT_A, 2)
eğer (B != son_B) yap
eğer (A != B) yap
encoder_konum = encoder_konum + 1 // CW
yoksa yap
encoder_konum = encoder_konum - 1 // CCW
son
son
son_B = B
son
fonksiyon encoder_oku() -> sayı yap
dön encoder_konum
son
Çıktı: Rotary encoder konumunu gerçek zamanlı takip eder. CW/CCW yönü otomatik algılanır.
💡 Örnek 3: Multi-Source Priority Handling
Problem: Birden fazla interrupt kaynağını öncelik sırasına göre yönetme
içe_aktar hal::exti, hal::gpio, hal::nvic
sabit KRITIK_OLAY_PIN: sayı = 0 // PA0 -> Emergency stop
sabit NORMAL_OLAY_PIN: sayı = 1 // PA1 -> Regular sensor
sabit DUSUK_OLAY_PIN: sayı = 2 // PA2 -> Low priority event
fonksiyon coklu_interrupt_init() yap
// Critical event (highest priority)
gpio.pin_init(gpio.PORT_A, KRITIK_OLAY_PIN, yap
mode: gpio.MODE_INPUT, pull: gpio.PULL_UP
son)
exti.init(KRITIK_OLAY_PIN, yap
trigger: exti.TRIGGER_FALLING,
callback: kritik_handler
son)
nvic.enable_irq(nvic.EXTI0_IRQn, 0) // Highest priority
// Normal event (medium priority)
gpio.pin_init(gpio.PORT_A, NORMAL_OLAY_PIN, yap
mode: gpio.MODE_INPUT, pull: gpio.PULL_UP
son)
exti.init(NORMAL_OLAY_PIN, yap
trigger: exti.TRIGGER_FALLING,
callback: normal_handler
son)
nvic.enable_irq(nvic.EXTI1_IRQn, 5) // Medium priority
// Low priority event
gpio.pin_init(gpio.PORT_A, DUSUK_OLAY_PIN, yap
mode: gpio.MODE_INPUT, pull: gpio.PULL_UP
son)
exti.init(DUSUK_OLAY_PIN, yap
trigger: exti.TRIGGER_FALLING,
callback: dusuk_handler
son)
nvic.enable_irq(nvic.EXTI2_IRQn, 10) // Low priority
son
fonksiyon kritik_handler() yap
// Emergency stop - preempt everything!
motor_durdur()
alarm_calar()
io.yazdir_satır("CRITICAL: Emergency stop!")
son
fonksiyon normal_handler() yap
// Regular sensor reading
değişken deger = sensor_oku()
io.yazdir_satır("Sensor value: " + deger.metne())
son
fonksiyon dusuk_handler() yap
// Low priority background task
log_olay("Low priority event")
son
Çıktı: Kritik olaylar düşük öncelikli interrupt'ları preempt eder. Sistem güvenliği sağlanır.
📚 API Referansı
Temel Fonksiyonlar
// EXTI hattını yapılandırır
fonksiyon init(line: sayı, config: EXTIConfig) -> Sonuç
// EXTI hattını etkinleştirir
fonksiyon enable(line: sayı)
// EXTI hattını devre dışı bırakır
fonksiyon disable(line: sayı)
// Pending flag'i temizler
fonksiyon clear_pending(line: sayı)
// Pending flag'i kontrol eder
fonksiyon is_pending(line: sayı) -> mantık
// Software interrupt tetikler
fonksiyon trigger_software(line: sayı)
// GPIO pin ile EXTI hattını eşleştirir
fonksiyon connect_gpio(line: sayı, port: gpio.Port, pin: sayı)
⚠️ Önemli Notlar:
- Shared IRQs: EXTI5-9 ve EXTI10-15 paylaşımlı IRQ kullanır
- Pin Mapping: Aynı pin numarası farklı portlarda aynı EXTI hattını kullanır (PA0, PB0, PC0 -> EXTI0)
- Callback Safety: Callback fonksiyonları kısa olmalı (ağır işlemler main loop'a ertelenmeli)
- Debounce: Donanım debounce yok, yazılım filtreleme gerekli
🖥️ Platform Desteği
| Platform | EXTI Hatları | Interrupt Groups | Event Mode |
|---|---|---|---|
| STM32F1 | 20 (0-15 + 4 özel) | 7 IRQ | Evet |
| STM32F4 | 23 (0-15 + 8 özel) | 7 IRQ | Evet |
| STM32F7 | 23 | 7 IRQ | Evet |
| GD32VF103 | 20 | ECLIC (47 IRQ) | Evet |
| ESP32 | Tüm GPIO | 2 CPU core | Hayır |
✅ Best Practices
- ✅ Debounce kullan: Mekanik butonlarda 20-50ms debounce uygula
- ✅ Callback kısa olsun: Interrupt handler'da minimum işlem yap, flag set et
- ✅ Priority ayarla: Kritik olaylar için düşük priority numarası kullan
- ✅ Pending temizle: Interrupt handler sonunda pending bit'i temizle
- ❌ Float işlem yapma: Interrupt'ta floating-point hesaplamalardan kaçın
- ❌ Uzun delay kullanma: Blocking delay callback içinde kullanılmamalı
🔗 İlgili Modüller
- hal::gpio - GPIO pin configuration
- hal::nvic - Interrupt priority management
- hal::power - Low power modes with wakeup
- hal::systick - Timing for debounce
- hal::timer - Hardware encoder mode