Concepts First
- POSIX: a standard set of OS interfaces (pthread threads, semaphores, message queues, etc.). These are the APIs used for multithreaded programming on Linux.
- Compatibility layer: makes the embedded system "pretend" to be Linux — POSIX APIs implemented on top of FreeRTOS, so code written on a PC can be ported to the MCU.
- pthread: POSIX threads.
pthread_createcreates a thread,pthread_mutex_lock/unlocklock/unlock,pthread_cond_wait/signalare condition variables,pthread_barrier_waitsynchronizes groups. - POSIX semaphores & message queues:
sem_open/sem_wait/sem_postandmq_open/mq_send/mq_receiveare the standard interfaces for synchronization and data passing between tasks. - Relation to native FreeRTOS APIs: underneath, the compatibility layer still uses FreeRTOS tasks/queues/semaphores; only the "skin" is POSIX. Which to use depends on preference and portability needs.
Example Overview
This page is based on the freertos_posix example in the official Bouffalo SDK (examples/posix/freertos_posix), which demonstrates the FreeRTOS POSIX compatibility layer:
- The example is a POSIX API test suite: 9 groups covering pthread (create/attr/mutex/cond/barrier), semaphores, message queues, clock/timer, and sched/unistd;
- Shell commands run all tests (
posix_test) or a single group (posix_test_single <group>); - Each case counts run/pass/fail/skip, and
print_test_summary()prints the totals; - With
CONFIG_POSIX=y, your project can#include <pthread.h>,<semaphore.h>,<mqueue.h>directly.
Note
This page has little code but dense concepts: to write your own multithreaded code, first run posix_test, then study the test cases under test/.
Operation Steps
Open a terminal and enter the SDK POSIX compatibility example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):
cd examples/posix/freertos_posixThe example defconfig already contains CONFIG_POSIX=y; if you start a new project, add this line to defconfig or enable POSIX support in make menuconfig and save.
grep CONFIG_POSIX defconfigRun the build command. The Ai-M62 (BL616) and Ai-M61 (BL618) belong to the same series, so both use bl616:
make CHIP=bl616 BOARD=bl616dkConnect the board with a USB cable, hold the BOOT button (IO2 on the Ai-M61-32S-Kit), briefly press EN/RST to enter download mode, then flash (replace the serial port with the one on your computer):
make flash CHIP=bl616 COMX=/dev/ttyUSB0Open a serial tool (baud rate 2000000). At the bouffalolab /> prompt, type posix_test and press Enter: the suite runs 9 test groups (pthread, pthread_attr, mutex, cond, barrier, sem, mqueue, clock, sched) and prints a PASSED/FAILED summary. Use posix_test_single pthread to run one group.
Code Execution Flow
The flow from boot to completing the tests is:
APIs Used by the Example
pthread_create / pthread_join / pthread_attr_*(...)
Creates/joins threads and configures thread attributes (detach state, stack size, scheduling parameters). Used by test/test_pthread.c and others.
Parameters:
thread: output thread IDattr: thread attributes (orNULLfor defaults)start_routine/arg: thread function and argument
Returns: 0 on success; an error code on failure
pthread_mutex_lock / pthread_mutex_unlock(mutex)
Locks/unlocks a mutex to protect shared data. The tests also cover attributes (pthread_mutexattr_*) and the timed variant (pthread_mutex_timedlock).
Parameters:
mutex: the mutex object
Returns: 0 on success; an error code on failure
sem_open / sem_wait / sem_post(...)
Creates a named semaphore and performs P/V operations (wait/release) for task synchronization.
Parameters:
name: semaphore name (e.g.,/sem0)value: initial valuesem: semaphore pointer
Returns: 0 on success; -1 on failure with errno set
mq_open / mq_send / mq_receive(...)
Creates a message queue and sends/receives messages — the standard way to pass prioritized data between tasks.
Parameters:
name: queue nameattr: queue attributes (length, message size)msg/prio: message data and priority
Returns: mqd_t descriptor / bytes sent on success; (mqd_t)-1 on failure
Complete Code
The following is the complete source of posix/freertos_posix/main.c, identical to the official example, collapsed by default (test groups live in the test/ subdirectory):
📜 Click to expand posix/freertos_posix/main.c full code
#include <stdio.h>
#include <string.h>
#include "board.h"
#include "shell.h"
#include "bflb_core.h"
#include <FreeRTOS.h>
#include "task.h"
#include "test_common.h"
/* Forward declaration for shell_init_with_task (not declared in shell.h) */
extern void shell_init_with_task(struct bflb_device_s *uart);
/* Stack overflow hook - called when FreeRTOS detects stack overflow */
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
{
printf("\r\n[STACK OVERFLOW] Task: %s\r\n", pcTaskName);
while (1) {
/* Halt to allow debugging */
}
}
/* Global test counters */
int g_tests_run = 0;
int g_tests_passed = 0;
int g_tests_failed = 0;
int g_tests_skipped = 0;
/* External declarations for each test group */
extern void test_pthread_run(void);
extern void test_pthread_attr_run(void);
extern void test_pthread_mutex_run(void);
extern void test_pthread_cond_run(void);
extern void test_pthread_barrier_run(void);
extern void test_semaphore_run(void);
extern void test_mqueue_run(void);
extern void test_clock_timer_run(void);
extern void test_sched_unistd_run(void);
/* Run all tests */
static void run_all_tests(void)
{
printf("\r\n===== POSIX API Test Suite Start =====\r\n\r\n");
/* Reset counters */
g_tests_run = 0;
g_tests_passed = 0;
g_tests_failed = 0;
g_tests_skipped = 0;
printf("--- 1. pthread tests ---\r\n");
test_pthread_run();
printf("\r\n--- 2. pthread_attr tests ---\r\n");
test_pthread_attr_run();
printf("\r\n--- 3. pthread_mutex tests ---\r\n");
test_pthread_mutex_run();
printf("\r\n--- 4. pthread_cond tests ---\r\n");
test_pthread_cond_run();
printf("\r\n--- 5. pthread_barrier tests ---\r\n");
test_pthread_barrier_run();
printf("\r\n--- 6. semaphore tests ---\r\n");
test_semaphore_run();
printf("\r\n--- 7. mqueue tests ---\r\n");
test_mqueue_run();
printf("\r\n--- 8. clock/timer tests ---\r\n");
test_clock_timer_run();
printf("\r\n--- 9. sched/unistd tests ---\r\n");
test_sched_unistd_run();
print_test_summary();
}
/* Shell command: run all tests */
static void cmd_posix_test(int argc, char **argv)
{
/* Run tests directly in shell task context */
run_all_tests();
}
SHELL_CMD_EXPORT_ALIAS(cmd_posix_test, posix_test, Run all POSIX tests);
/* Shell command: run single test group */
static void cmd_posix_test_single(int argc, char **argv)
{
if (argc < 2) {
printf("Usage: posix_test_single <group>\r\n");
printf("Groups: pthread, pthread_attr, mutex, cond, barrier, sem, mqueue, clock, sched\r\n");
return;
}
g_tests_run = 0;
g_tests_passed = 0;
g_tests_failed = 0;
g_tests_skipped = 0;
if (strcmp(argv[1], "pthread") == 0) {
test_pthread_run();
} else if (strcmp(argv[1], "pthread_attr") == 0) {
test_pthread_attr_run();
} else if (strcmp(argv[1], "mutex") == 0) {
test_pthread_mutex_run();
} else if (strcmp(argv[1], "cond") == 0) {
test_pthread_cond_run();
} else if (strcmp(argv[1], "barrier") == 0) {
test_pthread_barrier_run();
} else if (strcmp(argv[1], "sem") == 0) {
test_semaphore_run();
} else if (strcmp(argv[1], "mqueue") == 0) {
test_mqueue_run();
} else if (strcmp(argv[1], "clock") == 0) {
test_clock_timer_run();
} else if (strcmp(argv[1], "sched") == 0) {
test_sched_unistd_run();
} else {
printf("Unknown test group: %s\r\n", argv[1]);
return;
}
print_test_summary();
}
SHELL_CMD_EXPORT_ALIAS(cmd_posix_test_single, posix_test_single, Run single POSIX test group);
int main(void)
{
board_init();
printf("\r\n========================================\r\n");
printf(" FreeRTOS POSIX Test Application\r\n");
printf("========================================\r\n");
printf("\r\nShell commands:\r\n");
printf(" posix_test - Run all tests\r\n");
printf(" posix_test_single - Run single test group\r\n");
printf("\r\n");
/* Initialize shell task */
struct bflb_device_s *uart0 = bflb_device_get_by_name("uart0");
shell_init_with_task(uart0);
vTaskStartScheduler(); /* starts scheduler, never returns */
while (1) {
/* Should never reach here */
}
}FAQ
Build fails with \"pthread.h / semaphore.h not found\".
The POSIX compatibility layer is not enabled. Add CONFIG_POSIX=y to defconfig (the example already has it) or enable it in make menuconfig, then rebuild.
POSIX APIs or native FreeRTOS APIs?
No absolute winner: POSIX APIs are more portable (code can move to Linux or other RTOSes); FreeRTOS native APIs are closer to the hardware and better documented. Courses often ask for "standard interfaces"; real projects often mix both.
`posix_test` reports FAILED cases. What now?
First verify your board and defconfig match the example (PSRAM/heap size affects thread creation). If a few cases fail, the stack or heap is usually too small — increase configTOTAL_HEAP_SIZE or thread stacksize and retry.
How long do the tests take?
All 9 groups take a few seconds to tens of seconds, depending on clock/timer waits. Use posix_test_single <group> when debugging one interface.

