hal::nvic

Nested Vectored Interrupt Controller - ARM Cortex-M

~380 satır ~18 fonksiyon ARM Cortex-M

Genel Bakış

NVIC modülü, ARM Cortex-M serisi işlemcilerde interrupt yönetimini sağlar. 240+ interrupt kaynağını 16 öncelik seviyesi ile yönetir, nested interrupts destekler ve kritik bölgeleri koruma mekanizmaları sunar. Gerçek zamanlı embedded sistemlerin omurgasıdır.

Temel Özellikler

Hızlı Başlangıç

içe_aktar hal::nvic

// Simple interrupt enable
nvic.enable_irq(nvic.USART1_IRQn, yap
    priority: 5  // 0-15 range
son)

// Priority grouping (preemption vs sub-priority)
nvic.set_priority_grouping(nvic.PRIGROUP_4_4)  // 4 bit preempt, 4 bit sub

// Preemption priority 2, sub-priority 1
nvic.set_priority(nvic.TIM2_IRQn, yap
    preempt: 2,
    sub: 1
son)

// Disable interrupt
nvic.disable_irq(nvic.USART1_IRQn)

// Software trigger interrupt
nvic.set_pending_irq(nvic.EXTI0_IRQn)

Tipler ve Enum'lar

// Priority Grouping
enum PriorityGroup {
    PRIGROUP_0_4,  // 0 bit preempt, 4 bit sub
    PRIGROUP_1_3,  // 1 bit preempt, 3 bit sub
    PRIGROUP_2_2,  // 2 bit preempt, 2 bit sub
    PRIGROUP_3_1,  // 3 bit preempt, 1 bit sub
    PRIGROUP_4_0   // 4 bit preempt, 0 bit sub (default)
}

// IRQ Numbers (platform-specific)
enum IRQn {
    // Cortex-M core exceptions
    NMI_IRQn = -14,
    HardFault_IRQn = -13,
    MemManage_IRQn = -12,
    BusFault_IRQn = -11,
    UsageFault_IRQn = -10,
    SVCall_IRQn = -5,
    PendSV_IRQn = -2,
    SysTick_IRQn = -1,
    
    // STM32-specific interrupts (0+)
    WWDG_IRQn = 0,
    PVD_IRQn = 1,
    TAMP_STAMP_IRQn = 2,
    RTC_WKUP_IRQn = 3,
    FLASH_IRQn = 4,
    RCC_IRQn = 5,
    EXTI0_IRQn = 6,
    EXTI1_IRQn = 7,
    // ... 80+ more
    USART1_IRQn = 37,
    TIM2_IRQn = 28,
    DMA1_Stream0_IRQn = 11
}

yapı NVICConfig yap
    irq: IRQn,
    priority: sayı,        // Combined or preemption priority
    sub_priority: sayı = 0, // Sub-priority (if grouping allows)
    enabled: mantık = doğru
son

Örnek 1: Priority Grouping & Preemption

Problem: USART ve Timer interrupt'larının öncelik yönetimi

içe_aktar hal::nvic, hal::usart, hal::timer

fonksiyon interrupt_sistemi_init() yap
    // Set priority grouping: 3-bit preempt, 1-bit sub
    nvic.set_priority_grouping(nvic.PRIGROUP_3_1)
    
    // USART1 (high priority, preempt=1, sub=0)
    nvic.enable_irq(nvic.USART1_IRQn, yap
        priority: 1,      // Preemption priority
        sub_priority: 0
    son)
    
    // Timer2 (medium priority, preempt=3, sub=0)
    nvic.enable_irq(nvic.TIM2_IRQn, yap
        priority: 3,
        sub_priority: 0
    son)
    
    // ADC (low priority, preempt=5, sub=1)
    nvic.enable_irq(nvic.ADC_IRQn, yap
        priority: 5,
        sub_priority: 1
    son)
son

// USART handler (can preempt TIM2 and ADC)
fonksiyon USART1_IRQHandler() yap
    eğer usart.get_flag(usart.USART1, usart.FLAG_RXNE) yap
        değişken data = usart.receive_data(usart.USART1)
        buffer_yaz(data)
        usart.clear_flag(usart.USART1, usart.FLAG_RXNE)
    son
son

// Timer handler (can preempt ADC, but NOT USART)
fonksiyon TIM2_IRQHandler() yap
    eğer timer.get_flag(timer.TIM2, timer.FLAG_UPDATE) yap
        // Timer tick processing
        systick_emulate()
        timer.clear_flag(timer.TIM2, timer.FLAG_UPDATE)
    son
son

// ADC handler (lowest priority, cannot preempt anyone)
fonksiyon ADC_IRQHandler() yap
    eğer adc.get_flag(adc.ADC1, adc.FLAG_EOC) yap
        değişken value = adc.read_value(adc.ADC1)
        sensor_buffer[buffer_idx] = value
        buffer_idx = (buffer_idx + 1) % 32
        adc.clear_flag(adc.ADC1, adc.FLAG_EOC)
    son
son

Çıktı: USART interrupt'ı TIM2'ye girebilir (preempt), ama TIM2 USART'a giremez. ADC her ikisi tarafından preempt edilebilir.

Örnek 2: Critical Section (Disable All Interrupts)

Problem: Paylaşımlı değişkeni koruma (thread-safe erişim)

içe_aktar hal::nvic

değişken paylasilanOlan sayac: sayı = 0

fonksiyon kritik_islem() yap
    // Disable all interrupts (PRIMASK = 1)
    nvic.disable_all_interrupts()
    
    // Critical section (atomic operation)
    sayac = sayac + 1
    değişken local_sayac = sayac
    
    // Re-enable interrupts
    nvic.enable_all_interrupts()
    
    dön local_sayac
son

// Alternative: BASEPRI (disable interrupts with priority >= threshold)
fonksiyon basepri_koruma() yap
    // Disable interrupts with priority >= 3 (only allow 0-2)
    nvic.set_basepri(3)
    
    // Critical section
    paylasilanOlan veri = veri_oku()
    veri_isle(veri)
    
    // Restore (allow all)
    nvic.set_basepri(0)
son

Çıktı: sayac değişkeni interrupt'lardan korunur. Race condition önlenir.

Örnek 3: Vector Table Relocation (Bootloader)

Problem: Bootloader'dan application'a geçiş

içe_aktar hal::nvic, hal::flash

sabit BOOTLOADER_BASE: sayı = 0x0800_0000
sabit APP_BASE: sayı = 0x0800_8000  // 32 KB offset

fonksiyon jump_to_application() yap
    // Read application's stack pointer
    değişken app_sp = *(APP_BASE kayıt sayı*)
    
    // Read application's reset handler
    değişken app_reset = *((APP_BASE + 4) kayıt sayı*)
    
    io.yazdir_satır('Jumping to application at 0x' + APP_BASE.onaltılıya())
    
    // Disable all interrupts
    nvic.disable_all_interrupts()
    
    // Relocate vector table to application address
    nvic.set_vector_table(APP_BASE)
    
    // Set stack pointer
    asm yap
        'MSR MSP, r0' // Set Main Stack Pointer
    son with app_sp
    
    // Jump to application reset handler
    değişken app_func = app_reset kayıt fonksiyon()
    app_func()
son

// Bootloader mode check
fonksiyon bootloader_mode() -> mantık yap
    // Check if user button pressed during reset
    gpio.pin_init(gpio.PORT_A, 0, yap mode: gpio.MODE_INPUT son)
    
    değişken buton = gpio.pin_read(gpio.PORT_A, 0)
    
    eğer (buton == 1) yap
        io.yazdir_satır('Bootloader mode (button pressed)')
        dön doğru
    son
    
    // Check if application is valid (stack pointer in RAM)
    değişken app_sp = *(APP_BASE kayıt sayı*)
    eğer (app_sp >= 0x2000_0000 ve app_sp < 0x2002_0000) yap
        io.yazdir_satır('Valid application found')
        dön yanlış  // Jump to app
    son
    
    io.yazdir_satır('No valid application, staying in bootloader')
    dön doğru
son

Çıktı: Bootloader 0x0800_0000'den çalışır, uygulama 0x0800_8000'e yüklenir. Reset sonrası doğru vector table kullanılır.

API Referansı

Temel Fonksiyonlar

// Interrupt enable/disable
fonksiyon enable_irq(irq: IRQn, config: NVICConfig)
fonksiyon disable_irq(irq: IRQn)

// Priority configuration
fonksiyon set_priority_grouping(group: PriorityGroup)
fonksiyon set_priority(irq: IRQn, preempt: sayı, sub: sayı)
fonksiyon get_priority(irq: IRQn) -> (sayı, sayı)

// Pending management
fonksiyon set_pending_irq(irq: IRQn)
fonksiyon clear_pending_irq(irq: IRQn)
fonksiyon is_pending_irq(irq: IRQn) -> mantık

// Active status
fonksiyon is_active_irq(irq: IRQn) -> mantık

// Global interrupt control
fonksiyon disable_all_interrupts()  // PRIMASK = 1
fonksiyon enable_all_interrupts()   // PRIMASK = 0
fonksiyon set_basepri(priority: sayı)  // Disable pri >= threshold
fonksiyon get_basepri() -> sayı

// Vector table relocation
fonksiyon set_vector_table(offset: sayı)
fonksiyon get_vector_table() -> sayı

// System reset
fonksiyon system_reset()
Önemli Notlar:
  • Priority Inversion: Düşük öncelikli interrupt uzun sürerse, yüksek öncelikli bekler
  • Shared Peripherals: Aynı periferali kullanan interrupt'ların önceliği dikkatli ayarlanmalı
  • Stack Overflow: Nested interrupt çok derinleşirse stack overflow olabilir
  • Vector Table: RAM'e relocation yaparken alignment (0x200) gerekli

Platform Desteği

Platform Core IRQ Count Priority Bits
STM32F1 Cortex-M3 60 4 bit (16 levels)
STM32F4 Cortex-M4F 82 4 bit
STM32F7 Cortex-M7 97 4 bit
STM32H7 Cortex-M7 150 4 bit
GD32VF103 RISC-V 87 (ECLIC) 4 bit

Best Practices

İlgili Modüller

HAL Modülleri | English