⚡ 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

🚀 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

🔗 İlgili Modüller

🔙 HAL Modülleri | 🌐 English