Cortex-M bir MCU'da HardFault aldınız. Sorunun nedenini nasıl bulursunuz?

Cevap

Strateji şudur: Fault anında donanımın stack'e kaydettiği register'ları (özellikle PC ve LR) ve fault status register'larını okuyup hatayı oluşturan talimata ulaşmak. Aşağıdaki bilgiler Cortex-M3/M4/M7 içindir; M0/M0+'da fault status register'ları yoktur.

1. Stack frame'i yakalamak

Exception girişinde donanım R0-R3, R12, LR, PC, xPSR değerlerini aktif stack'e yazar. LR içindeki EXC_RETURN değerinin 2. biti, MSP mi PSP mi kullanıldığını gösterir (RTOS task'larında PSP kullanılır).

__attribute__((naked)) void HardFault_Handler(void)
{
    __asm volatile(
        "tst lr, #4        \n"
        "ite eq            \n"
        "mrseq r0, msp     \n"
        "mrsne r0, psp     \n"
        "b hardfault_c     \n");
}

void hardfault_c(uint32_t *sf)
{
    volatile uint32_t r0  = sf[0];
    volatile uint32_t lr  = sf[5];
    volatile uint32_t pc  = sf[6];   /* hatayı yapan talimat (precise fault ise) */
    volatile uint32_t cfsr = SCB->CFSR;
    volatile uint32_t hfsr = SCB->HFSR;
    volatile uint32_t mmfar = SCB->MMFAR;
    volatile uint32_t bfar  = SCB->BFAR;
    (void)r0; (void)lr; (void)pc; (void)cfsr; (void)hfsr; (void)mmfar; (void)bfar;
    __BKPT(0);
    for (;;) { }
}
arm-none-eabi-addr2line -e firmware.elf -f -C 0x08001A3C

2. Register'ları yorumlamak

  • HFSR.FORCED: Asıl hata Bus, Mem veya Usage fault'tur ve bu handler'lar kapalı olduğu için HardFault'a yükseltilmiştir. Ayrıntıya CFSR'de bakılır.
  • CFSR (0xE000ED28) = MMFSR + BFSR + UFSR:
  • PRECISERR + BFARVALID: Geçersiz adrese erişim; adres BFAR'da (NULL pointer, kapalı saatli çevre birimi).
  • IMPRECISERR: Yazma tamponu nedeniyle PC tam doğru değildir. Debug için yazma tamponu kapatılabilir (M3/M4'te ACTLR.DISDEFWBUF).
  • UNDEFINSTR / INVSTATE: Bozuk fonksiyon pointer'ı veya Thumb biti sıfır olan bir adrese atlama.
  • UNALIGNED, DIVBYZERO: İlgili trap bitleri (CCR) açıksa oluşur.
  • STKERR / MSTKERR: Stacking sırasında hata; büyük olasılıkla stack overflow.

3. Sık kök nedenler

  • Stack overflow (RTOS task'ında küçük stack, büyük yerel dizi)
  • NULL veya serbest bırakılmış pointer, dizi taşması
  • Saatini açmadığınız çevre birimine erişim
  • Hatalı kesme önceliği yüzünden bozulan RTOS veri yapıları
  • Yanlış cast ile hizalanmamış LDRD/LDM erişimi

4. Sahada (debugger yokken)

Fault bilgilerini noinit RAM bölümüne veya Flash'a yazıp reset atın, bir sonraki açılışta raporlayın. Memfault gibi araçlar bu coredump yaklaşımını hazır sunar.

  1. Kesme (interrupt) nedir? ISR yazarken nelere dikkat edilir?OrtaMikrodenetleyicilerEmbedded
  2. Watchdog timer nedir, ne işe yarar?KolayMikrodenetleyicilerEmbedded
  3. Bir bootloader nasıl çalışır? Uygulamaya atlama ve güvenli firmware güncellemesi nasıl tasarlanır?ZorMikrodenetleyicilerEmbedded
  4. Mekanik bir butonun debounce işlemi neden gereklidir ve yazılımda nasıl yapılır?KolayMikrodenetleyicilerEmbedded
  5. DMA nedir, ne zaman kullanılır? DMA kullanırken cache coherency ve double buffering gibi konularda nelere dikkat edilmelidir?ZorMikrodenetleyicilerEmbedded
  6. ADC çözünürlüğü, referans voltajı ve örnekleme hızı nedir? ADC okumasında doğruluğu etkileyen faktörler nelerdir?OrtaMikrodenetleyicilerEmbedded

Bu konuda başka bir soru biliyor musun?

Mülakatta karşılaştığın soruları ekle, onaylandıktan sonra yayına alınsın.

Soru ekle