Hello,
I am working on an embedded project using the STM32F401CCU6 microcontroller, and I recently ported FreeRTOS to my application. While running the code, I encounter a UsageFault_Handler, and the system halts unexpectedly.
Here are some details about my setup:
Microcontroller: STM32F401CCU6
Toolchain: GCC (Bare Metal)
FreeRTOS Configuration:
- Heap size: 16 KB (configTOTAL_HEAP_SIZE)
- Stack size: 256 bytes (configMINIMAL_STACK_SIZE)
- Features enabled: Timers, queues, semaphores, and mutexes.
What I’ve Observed:
- The fault occurs after starting the scheduler (when it tries to execute __asm volatile function in port.c file) .
- Debugging through the Fault Analyzer and registers indicates that the UsageFault is triggered by:
- Invalid memory access (e.g., unaligned memory).
- Stack overflow or corruption in tasks.
- I have enabled stack overflow detection in FreeRTOS using `configCHECK_FOR_STACK_OVERFLOW.
Are there any specific configurations for FreeRTOS or the STM32F4 series that might help resolve this?
I have pasted my program below
#include "stm32f401ccu6.h"
#include "FreeRTOS.h"
#include "task.h"
#include <stdio.h>
#include <string.h>
// Function prototypes
void ok_status(void);
void error_status(void);
void all_led_init(void);
void vTask1(void *pvParameters);
void vTask2(void *pvParameters);
void delay(void);
void HardFault_Handler(void);
void MemManage_Handler(void);
void BusFault_Handler(void);
void userFaultHandler(void);
GPIO_Handle_t LED, STATUS;
// Main function
int main(void)
{
// sprintf(msg, "USART Initialized\n");
// Initialize GPIO for LED
all_led_init();
printf("OK\n");
ok_status();
// Create Task 1
(xTaskCreate(vTask1, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, NULL)) ? ok_status() : error_status();
// Create Task 2
(xTaskCreate(vTask2, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, NULL)) ? ok_status() : error_status();
// Start Scheduler
vTaskStartScheduler();
// Should never reach here
while (1);
}
// Task 1: Toggles LED1
void vTask1(void *pvParameters)
{
(void)pvParameters; // Prevent unused parameter warning
while (1)
{
GPIO_ToggleOutputPin(GPIOA, GPIO_PIN_0); // Toggle A0 pin
vTaskDelay(pdMS_TO_TICKS(500)); // Delay 500 ms
}
}
// Task 2: Toggles LED2
void vTask2(void *pvParameters)
{
(void)pvParameters; // Prevent unused parameter warning
while (1)
{
GPIO_ToggleOutputPin(GPIOA, GPIO_PIN_1); // Toggle A1 pin
vTaskDelay(pdMS_TO_TICKS(300)); // Delay 300 ms
}
}
// Initialize GPIO for LEDs
void all_led_init(void)
{
LED.pGPIOx = GPIOA;
LED.GPIO_PinConfig.GPIO_PinMode = GPIO_MODE_OUT;
LED.GPIO_PinConfig.GPIO_PinOPType = GPIO_OP_TYPE_PP;
LED.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_PIN_PD;
LED.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_0;
GPIO_Init(&LED);
LED.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_1;
GPIO_Init(&LED);
STATUS.pGPIOx = GPIOB;
STATUS.GPIO_PinConfig.GPIO_PinMode = GPIO_MODE_OUT;
STATUS.GPIO_PinConfig.GPIO_PinOPType = GPIO_OP_TYPE_PP;
STATUS.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_PIN_PD;
STATUS.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_0;
GPIO_Init(&STATUS);
STATUS.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_1;
GPIO_Init(&STATUS);
}
void ok_status(void)
{
GPIO_ToggleOutputPin(GPIOB, GPIO_PIN_0);
delay();
GPIO_ToggleOutputPin(GPIOB, GPIO_PIN_0);
delay();
GPIO_ToggleOutputPin(GPIOB, GPIO_PIN_0);
delay();
GPIO_ToggleOutputPin(GPIOB, GPIO_PIN_0);
delay();
delay();
}
void error_status(void)
{
while(1)
{
GPIO_ToggleOutputPin(GPIOB, GPIO_PIN_1);
delay();
}
}
// Hook function to handle stack overflow
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
{
(void)xTask; // Suppress unused variable warning
(void)pcTaskName; // Suppress unused variable warning
error_status();
while (1); // Optionally, hang the system in an infinite loop
}
// Hook function to handle malloc failures
void vApplicationMallocFailedHook(void)
{
error_status();
// This function is called when a memory allocation fails.
while (1); // Optionally, hang the system in an infinite loop
}
void delay(void)
{
for(uint32_t i = 0 ; i < 500000/2 ; i ++);
}
void HardFault_Handler(void)
{
error_status();
while (1); // Breakpoint here to analyze fault
}
void MemManage_Handler(void)
{
error_status();
while (1); // Breakpoint here to analyze fault
}
void BusFault_Handler(void)
{
error_status();
while (1); // Breakpoint here to analyze fault
}
void userFaultHandler(void)
{
// Disable interrupts to prevent further faults or context switches.
taskDISABLE_INTERRUPTS();
// Optionally, stop the scheduler or enter an infinite loop to halt the system.
vTaskSuspendAll(); // Suspend all tasks
while (1)
{
// Optionally blink an LED or provide some other fault indication.
error_status();
}
}