
Freertos
- 404 installs
- 155 repo stars
- Updated June 27, 2026
- mohitmishra786/low-level-dev-skills
Port firmware to FreeRTOS on MCUs: tasks, queues, timers, and drivers for IoT devices, wearables, and embedded gateways needing deterministic scheduling.
About
Covers FreeRTOS fundamentals for embedded backends: scheduling tasks, synchronizing with queues, configuring clocks, and debugging stack overflows on resource-constrained targets serving mobile peripherals and edge APIs.
- Task creation and priority inheritance
- Queues, semaphores, and event groups
- Tickless idle and power modes
- Heap and stack watermark checks
- Port-specific startup and ISRs
Freertos by the numbers
- 404 all-time installs (skills.sh)
- +42 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #1,073 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill freertosAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 404 |
|---|---|
| repo stars | ★ 155 |
| Last updated | June 27, 2026 |
| Repository | mohitmishra786/low-level-dev-skills ↗ |
What it does
Port firmware to FreeRTOS on MCUs: tasks, queues, timers, and drivers for IoT devices, wearables, and embedded gateways needing deterministic scheduling.
Files
FreeRTOS
Purpose
Guide agents through FreeRTOS application development: task creation and priorities, inter-task communication with queues and semaphores, stack overflow detection, configASSERT, and FreeRTOS-aware debugging with GDB and OpenOCD.
Triggers
- "How do I create a FreeRTOS task?"
- "How do I pass data between FreeRTOS tasks?"
- "My FreeRTOS task is crashing — how do I detect stack overflow?"
- "How do I use FreeRTOS mutexes?"
- "How do I debug FreeRTOS tasks with GDB?"
- "How do I configure FreeRTOSConfig.h?"
Workflow
1. Task creation and priorities
#include "FreeRTOS.h"
#include "task.h"
// Task function signature
void vMyTask(void *pvParameters) {
const char *name = (const char *)pvParameters;
for (;;) {
// Task body — must never return
printf("Task %s running\n", name);
vTaskDelay(pdMS_TO_TICKS(500)); // yield for 500ms
}
}
int main(void) {
// xTaskCreate(function, name, stack_depth_words, param, priority, handle)
TaskHandle_t xHandle = NULL;
xTaskCreate(vMyTask, "MyTask",
configMINIMAL_STACK_SIZE + 128, // words, not bytes!
(void *)"sensor",
tskIDLE_PRIORITY + 2, // higher = more urgent
&xHandle);
vTaskStartScheduler(); // never returns if heap is sufficient
for (;;); // should never reach here
}Priority guidelines:
tskIDLE_PRIORITY(0) — idle task, never block here- ISR-deferred tasks — highest priority to service interrupts quickly
- Avoid priorities above
configMAX_PRIORITIES - 1
2. Queues — inter-task data passing
#include "queue.h"
typedef struct { uint32_t sensor_id; float value; } SensorReading_t;
QueueHandle_t xSensorQueue;
void vProducerTask(void *pvParam) {
SensorReading_t reading;
for (;;) {
reading.sensor_id = 1;
reading.value = read_adc();
// Send; block max 10ms if queue full
xQueueSend(xSensorQueue, &reading, pdMS_TO_TICKS(10));
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void vConsumerTask(void *pvParam) {
SensorReading_t reading;
for (;;) {
// Block forever until item available
if (xQueueReceive(xSensorQueue, &reading, portMAX_DELAY) == pdTRUE) {
process(reading.value);
}
}
}
// Create before starting scheduler
xSensorQueue = xQueueCreate(10, sizeof(SensorReading_t));From ISR: use xQueueSendFromISR() and pass &xHigherPriorityTaskWoken.
3. Semaphores and mutexes
#include "semphr.h"
// Binary semaphore — signaling (ISR→task)
SemaphoreHandle_t xSem = xSemaphoreCreateBinary();
void UART_ISR(void) {
BaseType_t xWoken = pdFALSE;
xSemaphoreGiveFromISR(xSem, &xWoken);
portYIELD_FROM_ISR(xWoken);
}
void vUartTask(void *p) {
for (;;) {
xSemaphoreTake(xSem, portMAX_DELAY);
// process received data
}
}
// Mutex — mutual exclusion (NOT from ISR)
SemaphoreHandle_t xMutex = xSemaphoreCreateMutex();
void vCriticalSection(void) {
if (xSemaphoreTake(xMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
// protected access
shared_resource++;
xSemaphoreGive(xMutex);
}
}
// Recursive mutex (same task can take multiple times)
SemaphoreHandle_t xRecursive = xSemaphoreCreateRecursiveMutex();
xSemaphoreTakeRecursive(xRecursive, portMAX_DELAY);
xSemaphoreGiveRecursive(xRecursive);Use mutex (not binary semaphore) for shared resources to get priority inheritance.
4. Stack overflow detection
// FreeRTOSConfig.h
#define configCHECK_FOR_STACK_OVERFLOW 2 // Method 2 (pattern + watermark)
#define configUSE_MALLOC_FAILED_HOOK 1
// Implement the hook (called when overflow detected)
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) {
// Log the offending task name, then halt
configASSERT(0); // triggers assertion failure
}
void vApplicationMallocFailedHook(void) {
configASSERT(0);
}Check watermarks at runtime:
// Returns minimum ever free stack words
UBaseType_t uxHighWaterMark = uxTaskGetStackHighWaterMark(xHandle);
printf("Stack headroom: %lu words\n", uxHighWaterMark);
// Rule of thumb: keep headroom > 20 words5. Essential FreeRTOSConfig.h settings
// FreeRTOSConfig.h — adapt to your MCU
#define configCPU_CLOCK_HZ (SystemCoreClock)
#define configTICK_RATE_HZ 1000 // 1ms tick
#define configMAX_PRIORITIES 8
#define configMINIMAL_STACK_SIZE 128 // words
#define configTOTAL_HEAP_SIZE (16 * 1024) // bytes
#define configMAX_TASK_NAME_LEN 16
// Debug / safety
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configCHECK_FOR_STACK_OVERFLOW 2
#define configUSE_MALLOC_FAILED_HOOK 1
#define configASSERT(x) if((x)==0) { taskDISABLE_INTERRUPTS(); for(;;); }
// Features
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_TIMERS 1
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2)6. GDB debugging with OpenOCD
# Connect GDB with FreeRTOS thread awareness
# OpenOCD provides FreeRTOS-aware RTOS plugin
# openocd.cfg addition
# source [find rtos/FreeRTOS.cfg] # auto-loads with most targets
# GDB session
(gdb) info threads # lists all FreeRTOS tasks
(gdb) thread 3 # switch to task 3
(gdb) bt # backtrace of that task's stack
(gdb) frame 2 # inspect specific frame
# Print task list from GDB (if trace facility enabled)
(gdb) call vTaskList(buf)
(gdb) printf "%s\n", bufFor OpenOCD setup details, see skills/embedded/openocd-jtag. For FreeRTOSConfig.h reference, see references/freertos-config.md.
Related skills
- Use
skills/embedded/openocd-jtagfor GDB/OpenOCD remote debugging setup - Use
skills/embedded/linker-scriptsfor placing FreeRTOS heap in specific RAM regions - Use
skills/debuggers/gdbfor general GDB session management - Use
skills/embedded/zephyrfor an alternative RTOS with built-in device management
FreeRTOS Configuration Reference
Source: https://www.freertos.org/a00110.html
Table of Contents
1. Core Configuration 2. Memory Management 3. Hook Functions 4. Timer Configuration 5. Interrupt Configuration (ARM Cortex-M)
Core Configuration
/* Scheduler behavior */
#define configUSE_PREEMPTION 1 // preemptive (0=cooperative)
#define configUSE_TIME_SLICING 1 // round-robin at same priority
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 // 1=CLZ instruction on Cortex-M
#define configUSE_TICKLESS_IDLE 0 // 1=low-power tickless mode
/* Tick and clock */
#define configCPU_CLOCK_HZ (SystemCoreClock) // Hz
#define configTICK_RATE_HZ 1000 // ticks/second
#define configSYSTICK_CLOCK_HZ (configCPU_CLOCK_HZ / 8) // if different
/* Task limits */
#define configMAX_PRIORITIES 8
#define configMINIMAL_STACK_SIZE 128 // words (NOT bytes)
#define configMAX_TASK_NAME_LEN 16
#define configIDLE_SHOULD_YIELD 1 // idle yields to equal-priority tasks
/* Heap */
#define configTOTAL_HEAP_SIZE ((size_t)(32 * 1024)) // bytesMemory Management
FreeRTOS has five heap implementations (heap_1.c through heap_5.c):
| Heap | Allocation | Free | Notes |
|---|---|---|---|
| heap_1 | Yes | No | Simplest; no free; deterministic |
| heap_2 | Yes | Yes | Best-fit; no coalescence; fragmentation |
| heap_3 | malloc/free | malloc/free | Thread-safe wrapper around stdlib |
| heap_4 | Yes | Yes | First-fit with coalescence; recommended |
| heap_5 | Yes | Yes | heap_4 across multiple non-contiguous regions |
For heap_5 (multiple memory regions):
#include "heap_5.h"
// Define memory regions
const HeapRegion_t xHeapRegions[] = {
{ (uint8_t *)0x20000000, 0x8000 }, // SRAM1: 32KB
{ (uint8_t *)0x10000000, 0x4000 }, // CCM: 16KB
{ NULL, 0 } // terminator
};
// Call before vTaskStartScheduler()
vPortDefineHeapRegions(xHeapRegions);Hook Functions
// Must define if configUSE_MALLOC_FAILED_HOOK=1
void vApplicationMallocFailedHook(void) {
__disable_irq();
for (;;);
}
// Must define if configCHECK_FOR_STACK_OVERFLOW > 0
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) {
(void)xTask;
// Log pcTaskName, halt
__disable_irq();
for (;;);
}
// Called by idle task (configUSE_IDLE_HOOK=1)
void vApplicationIdleHook(void) {
// Can enter low-power mode here
__WFI(); // ARM: wait for interrupt
}
// Called every tick (configUSE_TICK_HOOK=1)
void vApplicationTickHook(void) {
// Keep SHORT — runs at tick rate inside ISR
}Timer Configuration
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2)// One-shot timer example
TimerHandle_t xTimer = xTimerCreate(
"WdogTimer", // name (debug only)
pdMS_TO_TICKS(5000), // period
pdFALSE, // pdTRUE=auto-reload, pdFALSE=one-shot
(void *)0, // timer ID
vTimerCallback // callback
);
xTimerStart(xTimer, 0);
void vTimerCallback(TimerHandle_t xTimer) {
// Runs in timer task context — no direct ISR interaction
}Interrupt Configuration (ARM Cortex-M)
// These must match your MCU's NVIC priority grouping
#define configPRIO_BITS 4 // Cortex-M4/M7: 4 bits
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
// Derived (do not change)
#define configKERNEL_INTERRUPT_PRIORITY \
(configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
#define configMAX_SYSCALL_INTERRUPT_PRIORITY \
(configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))Rule: ISRs that call FreeRTOS API (FromISR variants) must have numeric priority ≥ configMAX_SYSCALL_INTERRUPT_PRIORITY. ISRs with LOWER numeric priority (higher urgency) must NOT call FreeRTOS APIs.
// In NVIC setup
NVIC_SetPriority(USART1_IRQn, 6); // OK: 6 >= 5 (MAX_SYSCALL)
NVIC_SetPriority(DMA1_IRQn, 2); // NOT OK for FromISR: 2 < 5