Common Causes of Microcontroller Crashes and Solutions

Follow+Star Public Account Number, don’t miss exciting contentSource | Embedded Software Guest House

During the development of microcontroller projects, crashes are one of the most troublesome issues. A crash can affect user experience at best, and at worst, it may lead to device damage or safety incidents.

Common Causes of Crashes

Classification of Causes

Hardware Level

  • Unstable Power Supply: Voltage fluctuations, excessive ripple
  • Clock Abnormalities: Crystal failure, incorrect clock configuration
  • Peripheral Conflicts: Interrupt conflicts, DMA configuration errors
  • Overheating: Poor heat dissipation leading to chip overheating

Software Level

  • Infinite Loops: Logical errors leading to dead loops
  • Stack Overflow: Too deep recursion or too many local variables
  • Memory Leaks: Dynamic memory allocation not released
  • Interrupt Handling Exceptions: Interrupt service routine execution time too long
  • Task Blocking: Tasks waiting on each other in a multitasking system

Hardware-Level Protection Strategies

Watchdog Timer (WDT) Design

Independent Hardware Watchdog

// STM32F4 Independent Watchdog Configuration Example
#include "stm32f4xx.h"

// Watchdog configuration structure
typedef struct {
    uint32_t prescaler;    // Prescaler
    uint32_t reload;       // Reload value
    uint32_t window;       // Window value
} IWDG_Config_t;

// Independent Watchdog Initialization
void IWDG_Init(IWDG_Config_t *config) {
    // Enable IWDG clock
    RCC->CSR |= RCC_CSR_LSION;
    
    // Wait for LSI to stabilize
    while(!(RCC->CSR & RCC_CSR_LSIRDY));
    
    // Configure prescaler
    IWDG->PR = config->prescaler;
    
    // Configure reload value
    IWDG->RLR = config->reload;
    
    // Configure window value (if using window watchdog)
    if(config->window != 0) {
        IWDG->WINR = config->window;
    }
    
    // Start watchdog
    IWDG->KR = 0xCCCC;
}

// Feed watchdog function
void IWDG_Refresh(void) {
    IWDG->KR = 0xAAAA;
}

// Watchdog status check
uint8_t IWDG_GetStatus(void) {
    return (IWDG->SR != 0) ? 1 : 0;
}

Window Watchdog (WWDG) Implementation

// Window Watchdog Configuration
void WWDG_Init(void) {
    // Enable WWDG clock
    RCC->APB1ENR |= RCC_APB1ENR_WWDGEN;
    
    // Configure window value (0x40-0x7F)
    WWDG->CFR = (0x40 << WWDG_CFR_W_Pos) | 
                 (0x7 << WWDG_CFR_PRESCALER_Pos) |
                 WWDG_CFR_EWI;  // Enable early wakeup interrupt
    
    // Configure counter value
    WWDG->CR = 0x7F;
    
    // Enable WWDG
    WWDG->CR |= WWDG_CR_WDGA;
}

// Feed window watchdog
void WWDG_Refresh(uint8_t counter) {
    if(counter < 0x40) {
        WWDG->CR = (WWDG->CR & ~WWDG_CR_T) | counter;
    }
}

Power Management Strategies

Voltage Monitoring Circuit

// Voltage monitoring implementation
typedef struct {
    float vcc_threshold;    // VCC threshold
    float vdd_threshold;    // VDD threshold
    uint16_t adc_channel;   // ADC channel
} Voltage_Monitor_t;

// Voltage monitoring initialization
void Voltage_Monitor_Init(Voltage_Monitor_t *monitor) {
    // Configure ADC
    ADC_Init(monitor->adc_channel);
    
    // Configure comparator (if hardware supports)
    COMP_Init();
}

// Voltage check
uint8_t Voltage_Check(Voltage_Monitor_t *monitor) {
    uint16_t adc_value = ADC_Read(monitor->adc_channel);
    float voltage = (float)adc_value * 3.3f / 4096.0f;
    
    if(voltage < monitor->vcc_threshold) {
        // Voltage too low, enter low power mode
        System_Enter_LowPower();
        return 0;
    }
    
    return 1;
}

Power Failure Detection and Data Protection

// Power failure detection interrupt handler
void PVD_IRQHandler(void) {
    if(EXTI->PR & EXTI_PR_PR16) {
        // Clear interrupt flag
        EXTI->PR = EXTI_PR_PR16;
        
        // Immediately save critical data
        Save_Critical_Data();
        
        // Enter safe mode
        System_Enter_SafeMode();
    }
}

// Save critical data
void Save_Critical_Data(void) {
    // Save to backup registers
    RTC->BKP0R = critical_data.param1;
    RTC->BKP1R = critical_data.param2;
    RTC->BKP2R = critical_data.param3;
    
    // Save to Flash
    Flash_Write(CRITICAL_DATA_ADDR, &critical_data, sizeof(critical_data));
}

Software-Level Protection Strategies

Exception Handling Mechanism

Exception Vector Table Configuration

// Exception vector table
__attribute__((section(".isr_vector")))
void (* const g_pfnVectors[])(void) = {
    (void (*)(void))((uint32_t)&_estack),  // Stack top
    Reset_Handler,                          // Reset
    NMI_Handler,                            // NMI
    HardFault_Handler,                      // Hard fault
    MemManage_Handler,                      // Memory management fault
    BusFault_Handler,                       // Bus fault
    UsageFault_Handler,                     // Usage fault
    0, 0, 0, 0,                            // Reserved
    SVC_Handler,                            // SVCall
    DebugMon_Handler,                       // Debug monitor
    0,                                      // Reserved
    PendSV_Handler,                         // PendSV
    SysTick_Handler,                        // SysTick
    // External interrupts
    EXTI0_IRQHandler,
    EXTI1_IRQHandler,
    // ... other interrupts
};

// Hard fault handler
void HardFault_Handler(void) {
    // Save fault information
    fault_info.fault_type = FAULT_HARD;
    fault_info.fault_addr = __get_MSP();
    fault_info.fault_lr = __get_LR();
    
    // Record fault time
    fault_info.timestamp = HAL_GetTick();
    
    // Save to Flash
    Save_Fault_Info();
    
    // System reset
    NVIC_SystemReset();
}

Software Exception Detection

// Software exception detection structure
typedef struct {
    uint32_t magic_number;      // Magic number
    uint32_t stack_pointer;     // Stack pointer
    uint32_t program_counter;   // Program counter
    uint32_t fault_flags;       // Fault flags
    uint32_t timestamp;         // Timestamp
} Exception_Info_t;

// Exception detection macro
#define EXCEPTION_CHECK() do { \
    static uint32_t last_check = 0; \
    uint32_t current_time = HAL_GetTick(); \
    if(current_time - last_check > 1000) { \
        Exception_Check(); \
        last_check = current_time; \
    } \
} while(0)

// Exception check function
void Exception_Check(void) {
    // Check stack overflow
    if(__get_MSP() < STACK_MIN_ADDR || __get_MSP() > STACK_MAX_ADDR) {
        Exception_Handler(EXCEPTION_STACK_OVERFLOW);
    }
    
    // Check heap overflow
    if(heap_usage > HEAP_MAX_SIZE) {
        Exception_Handler(EXCEPTION_HEAP_OVERFLOW);
    }
    
    // Check task timeout
    Task_Timeout_Check();
}

Task Monitoring System

Task Status Monitoring

// Task monitoring structure
typedef struct {
    uint8_t task_id;           // Task ID
    uint8_t priority;          // Priority
    uint32_t max_runtime;      // Maximum runtime
    uint32_t start_time;       // Start time
    uint32_t last_wake_time;   // Last wake time
    uint8_t status;            // Task status
    uint32_t watchdog_count;   // Watchdog count
} Task_Monitor_t;

#define MAX_TASKS 16
static Task_Monitor_t task_monitors[MAX_TASKS];
static uint8_t task_count = 0;

// Task registration
uint8_t Task_Register(uint8_t task_id, uint8_t priority, uint32_t max_runtime) {
    if(task_count >= MAX_TASKS) return 0;
    
    task_monitors[task_count].task_id = task_id;
    task_monitors[task_count].priority = priority;
    task_monitors[task_count].max_runtime = max_runtime;
    task_monitors[task_count].status = TASK_READY;
    task_monitors[task_count].watchdog_count = 0;
    
    return task_count++;
}

// Task start
void Task_Start(uint8_t task_index) {
    if(task_index < task_count) {
        task_monitors[task_index].start_time = HAL_GetTick();
        task_monitors[task_index].status = TASK_RUNNING;
    }
}

// Task complete
void Task_Complete(uint8_t task_index) {
    if(task_index < task_count) {
        task_monitors[task_index].status = TASK_COMPLETED;
        task_monitors[task_index].watchdog_count = 0;
    }
}

// Task timeout check
void Task_Timeout_Check(void) {
    uint32_t current_time = HAL_GetTick();
    
    for(int i = 0; i < task_count; i++) {
        if(task_monitors[i].status == TASK_RUNNING) {
            if(current_time - task_monitors[i].start_time > task_monitors[i].max_runtime) {
                // Task timeout, record exception
                Exception_Handler(EXCEPTION_TASK_TIMEOUT);
                task_monitors[i].status = TASK_TIMEOUT;
            }
        }
    }
}

Deadlock Detection

// Resource lock structure
typedef struct {
    uint8_t resource_id;       // Resource ID
    uint8_t owner_task;        // Owner task
    uint32_t lock_time;        // Lock time
    uint8_t is_locked;         // Lock status
} Resource_Lock_t;

#define MAX_RESOURCES 8
static Resource_Lock_t resource_locks[MAX_RESOURCES];

// Deadlock detection
uint8_t Deadlock_Detection(void) {
    uint32_t current_time = HAL_GetTick();
    
    for(int i = 0; i < MAX_RESOURCES; i++) {
        if(resource_locks[i].is_locked) {
            // Check if lock holding time is too long
            if(current_time - resource_locks[i].lock_time > MAX_LOCK_TIME) {
                // Possible deadlock, record exception
                Exception_Handler(EXCEPTION_DEADLOCK);
                return 1;
            }
        }
    }
    
    return 0;
}

Memory Management Strategies

Memory Pool Management

// Memory block structure
typedef struct Memory_Block {
    uint8_t is_allocated;      // Allocation status
    uint16_t size;             // Block size
    uint32_t alloc_time;       // Allocation time
    struct Memory_Block *next;  // Next block
} Memory_Block_t;

// Memory pool structure
typedef struct {
    uint8_t *pool_start;       // Pool start address
    uint32_t pool_size;        // Pool size
    Memory_Block_t *free_list; // Free list
    uint32_t total_allocated;  // Total allocated amount
    uint32_t peak_usage;       // Peak usage amount
} Memory_Pool_t;

// Memory pool initialization
void Memory_Pool_Init(Memory_Pool_t *pool, uint8_t *start, uint32_t size) {
    pool->pool_start = start;
    pool->pool_size = size;
    pool->total_allocated = 0;
    pool->peak_usage = 0;
    
    // Initialize the first free block
    Memory_Block_t *first_block = (Memory_Block_t *)start;
    first_block->is_allocated = 0;
    first_block->size = size - sizeof(Memory_Block_t);
    first_block->next = NULL;
    first_block->alloc_time = 0;
    
    pool->free_list = first_block;
}

// Memory allocation
void* Memory_Allocate(Memory_Pool_t *pool, uint16_t size) {
    Memory_Block_t *current = pool->free_list;
    Memory_Block_t *best_fit = NULL;
    uint16_t min_frag = 0xFFFF;
    
    // Find best fit block
    while(current) {
        if(!current->is_allocated && current->size >= size) {
            uint16_t fragment = current->size - size;
            if(fragment < min_frag) {
                min_frag = fragment;
                best_fit = current;
            }
        }
        current = current->next;
    }
    
    if(best_fit) {
        best_fit->is_allocated = 1;
        best_fit->alloc_time = HAL_GetTick();
        
        pool->total_allocated += size;
        if(pool->total_allocated > pool->peak_usage) {
            pool->peak_usage = pool->total_allocated;
        }
        
        return (void*)((uint8_t*)best_fit + sizeof(Memory_Block_t));
    }
    
    return NULL; // Allocation failed
}

// Memory free
void Memory_Free(Memory_Pool_t *pool, void *ptr) {
    Memory_Block_t *block = (Memory_Block_t*)((uint8_t*)ptr - sizeof(Memory_Block_t));
    
    if(block->is_allocated) {
        block->is_allocated = 0;
        pool->total_allocated -= block->size;
        
        // Merge adjacent free blocks
        Memory_Block_Merge(pool);
    }
}

Memory Leak Detection

// Memory leak detection
void Memory_Leak_Detection(Memory_Pool_t *pool) {
    uint32_t current_time = HAL_GetTick();
    Memory_Block_t *current = (Memory_Block_t*)pool->pool_start;
    
    while((uint8_t*)current < pool->pool_start + pool->pool_size) {
        if(current->is_allocated) {
            // Check memory block holding time
            if(current_time - current->alloc_time > MAX_ALLOC_TIME) {
                // Possible memory leak
                Exception_Handler(EXCEPTION_MEMORY_LEAK);
            }
        }
        
        current = (Memory_Block_t*)((uint8_t*)current + 
                                   sizeof(Memory_Block_t) + current->size);
    }
}

Testing and Validation

Stress Testing

// Stress testing function
void Stress_Test(void) {
    // Memory stress test
    Memory_Stress_Test();
    
    // CPU stress test
    CPU_Stress_Test();
    
    // Interrupt stress test
    Interrupt_Stress_Test();
    
    // Task stress test
    Task_Stress_Test();
}

// Memory stress test
void Memory_Stress_Test(void) {
    void *ptrs[100];
    
    // Continuous memory allocation
    for(int i = 0; i < 100; i++) {
        ptrs[i] = Memory_Allocate(&memory_pool, 64);
        if(!ptrs[i]) {
            Exception_Handler(EXCEPTION_MEMORY_ALLOCATION_FAILED);
            break;
        }
    }
    
    // Randomly free memory
    for(int i = 0; i < 100; i++) {
        if(ptrs[i]) {
            Memory_Free(&memory_pool, ptrs[i]);
        }
    }
}

Fault Injection Testing

// Fault injection testing
void Fault_Injection_Test(void) {
    // Inject stack overflow
    Stack_Overflow_Test();
    
    // Inject infinite loop
    Infinite_Loop_Test();
    
    // Inject memory leak
    Memory_Leak_Test();
    
    // Inject interrupt conflict
    Interrupt_Conflict_Test();
}

// Stack overflow test
void Stack_Overflow_Test(void) {
    // Recursive call leading to stack overflow
    Recursive_Function(1000);
}

void Recursive_Function(int depth) {
    if(depth > 0) {
        char buffer[100]; // Local variable occupies stack space
        Recursive_Function(depth - 1);
    }
}

———— END ————

Common Causes of Microcontroller Crashes and Solutions

● Column “Embedded Tools”

● Column “Embedded Development”

● Column “Keil Tutorials”

● Selected Tutorials from Embedded Column

Follow the public account Reply “Add Group” to join the technical exchange group according to the rules, reply “1024” to see more content.

Click “Read the original text” to see more shares.

Leave a Comment