vTaskStartScheduler causing UsageFault_Handler

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:

  1. The fault occurs after starting the scheduler (when it tries to execute __asm volatile function in port.c file) .
  2. 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.
  1. 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();
    }
}

Have you correctly installed the SysTick and Svc Isrs into your ivt? What aer their respective priorities?

The latest FreeRTOS version has asserts to catch incorrect installation of interrupt handlers. Would you please updated to the latest version and define configASSERT?