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 ————

● 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.