Concepts First
- Log: text printed to the serial port while the program runs, used to observe state and locate bugs — the program's "diary".
- Log levels: severity classes. From highest to lowest, the example uses F (fatal), E (error), W (warning), I (info), D (debug), T (trace).
- Level colors: each level has its own color so severity is visible at a glance. The colors are defined by the actual
BFLB_LOG_COLOR_*macros (bflb_log_conf.h;bflog_conf_user.hin the example directory is a reference copy): F magenta, E red, W yellow, I no color (BFLB_LOG_SGR_RESET), D white, T dim white (BFLB_LOG_SGR_FAINT). In the example config the green INFO line is commented out, so INFO prints without color. - Log tags: names for log groups (e.g.
MAIN,TEST); tags can be enabled/disabled globally for filtering, so you can watch only the part you care about. - Sync / async mode: sync mode outputs immediately; async mode (the
freertos_asyncsibling example) queues log messages and outputs them from a dedicated thread, which suits high log volume.
Example Overview
This page is based on the barebone_sync example in the official Bouffalo SDK (examples/bflog/barebone_sync), which demonstrates BFLB_LOG logging, levels, and tag filtering:
- Creates a synchronous log recorder backed by a 4096-byte memory pool (
BFLB_LOG_MODE_SYNC); - Creates a UART stream outputter (with colors) and connects its output function to
uart0; - The main loop prints F/E/W/I/D/T level logs every second and cycles three filter states: all enabled → only
MAIN→ all disabled; log_test.cdefines theTESTtag, showing how tags are defined across multiple files and filtered.- Sibling example (
examples/bflog/):freertos_async(FreeRTOS multi-thread async logging).
Operation Steps
No external wiring is needed for this page. Open a terminal and enter the SDK logging example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):
cd examples/bflog/barebone_syncRun 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). Every second the program prints enable all output (both MAIN and TEST tags visible), then enable only MAIN output (only MAIN visible), then disable all output (neither visible), cycling forever. Each round prints the six levels F/E/W/I/D/T (hello world this is ... and hello test this is ...).
Code Execution Flow
The complete execution flow from startup to running is shown below (loop arrows mean repeated execution):
APIs Used by the Example
bflb_log_create(log, pool, size, mode)
Creates the log recorder, which receives logs and dispatches them to outputters.
Parameters:
log: thebflb_log_trecorder object (example_recorderin the example)pool: log memory pool pointer (4 KB alignedexample_poolarray)size: pool size in bytes (EXAMPLE_LOG_POOL_SIZE = 4096)mode:BFLB_LOG_MODE_SYNC(synchronous) or async mode
Return: 0 on success; negative error code on failure
bflb_log_direct_create(direct, type, color, lock, unlock)
Creates a log outputter (direct); the example uses a stream outputter with colors enabled.
Parameters:
direct: thebflb_log_direct_toutputter objecttype: output type,BFLB_LOG_DIRECT_TYPE_STREAMin the examplecolor:BFLB_LOG_DIRECT_COLOR_ENABLElock/unlock: mutex callbacks,NULLin the example
Return: 0 on success; negative error code on failure
bflb_log_direct_init_stream(direct, stream_output)
Binds the actual stream output function (the example writes each byte to uart0 via bflb_uart_putchar).
Parameters:
direct: the stream outputter objectstream_output: output callback,uint16_t (*)(void *, uint16_t)
Return: 0 on success; negative error code on failure
bflb_log_append(log, direct)
Adds the outputter to the recorder; logs are forwarded to the outputter only after this call.
Parameters:
log: recorder objectdirect: outputter object
Return: 0 on success; negative error code on failure
bflb_log_direct_resume / bflb_log_resume(direct / log)
Resumes the outputter / recorder to the working state (both start suspended and must be resumed to output).
Parameters:
direct/log: pointer to the corresponding object
Return: 0 on success; negative error code on failure
bflb_log_global_filter("MAIN", enable)
Globally enables/disables output for a given tag.
Parameters:
tag_string: tag name,"MAIN"/"TEST"in the exampleenable:trueto enable /falseto disable
Return: 0 on success; negative error code on failure
BFLB_LOG_F / E / W / I / D / T(recorder, fmt, ...)
Leveled log macros: F fatal, E error, W warning, I info, D debug, T trace.
Parameters:
recorder: recorder object (&example_recorderin the example)fmt, ...: printf-style format string and arguments
Return: none
BFLB_LOG_DEFINE_TAG / BFLB_LOG_GET_TAG(name, string, enable)
Defines a log tag: BFLB_LOG_DEFINE_TAG(MAIN, "MAIN", true) places the tag into a dedicated section; BFLB_LOG_GET_TAG(MAIN) fetches it and assigns it to BFLB_LOG_TAG, so log macros in this file carry the tag.
Parameters:
name: tag variable namestring: tag string (used when printing and filtering)enable: initial enabled state
Return: none
Complete Code
The complete source below matches the official example (examples/bflog/barebone_sync) verbatim. Collapsed by default, click to expand:
📜 Click to expand barebone_sync/main.c full code
#define DBG_TAG "MAIN"
#include "bflb_mtimer.h"
#include "bflb_uart.h"
#include "bflb_rtc.h"
#include "bflb_clock.h"
#include "board.h"
#include "bflb_log.h"
/*!< Adding the BFLB_LOG tag allows the use of tag filtering functionality */
/*!< If not added, the tag can still be displayed, but tag filtering will not work */
/*!< Define a BFLB_LOG tag */
BFLB_LOG_DEFINE_TAG(MAIN, DBG_TAG, true);
/*!< Cancel the previous BFLB_LOG tag */
#undef BFLB_LOG_TAG
/*!< Define the BFLB_LOG tag as a new tag */
#define BFLB_LOG_TAG BFLB_LOG_GET_TAG(MAIN)
/*!< Bflog bare-metal synchronization routine */
/*!< bflb_log barebone sync example */
struct bflb_device_s *uart0 = NULL;
static struct bflb_device_s *rtc = NULL;
/*!< Current UTC Timestamp 2022-12-16 17:52 */
uint32_t timestamp_base = 1671184300;
/** @defgroup example_bflb_log_port port
-----------------------------------------------------------------------------
* @{
----------------------------------------------------------------------------*/
uint64_t bflb_log_clock(void)
{
return bflb_mtimer_get_time_us();
}
uint32_t bflb_log_time(void)
{
return BFLB_RTC_TIME2SEC(bflb_rtc_get_time(rtc)) + timestamp_base;
}
char *bflb_log_thread(void)
{
return "";
}
/*---------------------------------------------------------------------------
* @} example_bflb_log_port port
----------------------------------------------------------------------------*/
#define EXAMPLE_LOG_POOL_SIZE 4096
bflb_log_t example_recorder;
static uint32_t example_pool[EXAMPLE_LOG_POOL_SIZE / 4];
bflb_log_direct_stream_t example_uart_stream;
uint16_t example_uart_stream_output(void *ptr, uint16_t size)
{
for (size_t i = 0; i < size; i++) {
bflb_uart_putchar(uart0, ((char *)ptr)[i]);
}
return size;
}
void example_log_init(void)
{
void *record = (void *)&example_recorder;
void *direct = (void *)&example_uart_stream;
/*!< Create a logger, configure the memory pool, set the memory pool size, and set the mode to synchronous.*/
/*!< create recorder */
if (0 != bflb_log_create(record, example_pool, EXAMPLE_LOG_POOL_SIZE, BFLB_LOG_MODE_SYNC)) {
printf("bflb_log_create faild\r\n");
}
/*!< Create an outputter, of the stream outputter type, enable color output, and set the mutex to NULL. */
/*!< create stream direct */
bflb_log_direct_create(direct, BFLB_LOG_DIRECT_TYPE_STREAM, BFLB_LOG_DIRECT_COLOR_ENABLE, NULL, NULL);
/*!< Configure the output function of the stream output */
bflb_log_direct_init_stream((void *)direct, example_uart_stream_output);
/*!< Add the outputter to the logger */
/*!< connect direct and recorder */
bflb_log_append(record, direct);
/*!< Restore the outputter to working mode*/
/*!< resume direct */
bflb_log_direct_resume(direct);
/*!< Restore the logger to working mode */
/*!< resume record */
bflb_log_resume(record);
}
extern void test_log(void);
int main(void)
{
board_init();
/*!< uart0 already initialized in bsp/board */
uart0 = bflb_device_get_by_name("uart0");
rtc = bflb_device_get_by_name("rtc");
bflb_rtc_set_time(rtc, 0);
example_log_init();
uint8_t test = 0;
while (1) {
if (test == 0) {
bflb_log_global_filter("MAIN", true);
bflb_log_global_filter("TEST", true);
printf("\r\n============================== enable all output\r\n\r\n");
} else if (test == 1) {
bflb_log_global_filter("MAIN", false);
bflb_log_global_filter("TEST", true);
printf("\r\n============================== enable only MAIN output\r\n\r\n");
} else if (test == 2) {
bflb_log_global_filter("MAIN", false);
bflb_log_global_filter("TEST", false);
printf("\r\n============================== disable all output\r\n\r\n");
}
if (++test >= 3) {
test = 0;
}
BFLB_LOG_F(&example_recorder, "hello world this is fatal error\r\n");
BFLB_LOG_E(&example_recorder, "hello world this is error\r\n");
BFLB_LOG_W(&example_recorder, "hello world this is warning\r\n");
BFLB_LOG_I(&example_recorder, "hello world this is information\r\n");
BFLB_LOG_D(&example_recorder, "hello world this is degug information\r\n");
BFLB_LOG_T(&example_recorder, "hello world this is trace information\r\n");
test_log();
bflb_mtimer_delay_ms(1000);
}
}📜 Click to expand barebone_sync/log_test.c full code
#define DBG_TAG "TEST"
#include "bflb_log.h"
BFLB_LOG_DEFINE_TAG(TEST, DBG_TAG, true);
#undef BFLB_LOG_TAG
#define BFLB_LOG_TAG BFLB_LOG_GET_TAG(TEST)
extern bflb_log_t example_recorder;
void test_log(void)
{
BFLB_LOG_F(&example_recorder, "hello test this is fatal error\r\n");
BFLB_LOG_E(&example_recorder, "hello test this is error\r\n");
BFLB_LOG_W(&example_recorder, "hello test this is warning\r\n");
BFLB_LOG_I(&example_recorder, "hello test this is information\r\n");
BFLB_LOG_D(&example_recorder, "hello test this is degug information\r\n");
BFLB_LOG_T(&example_recorder, "hello test this is trace information\r\n");
}FAQ
How do I enable blog logging (BFLB_LOG)
Enable it at three levels:
- Build time (project config): set
CONFIG_BFLB_LOG =yin the project'sdefconfigso the SDK compiles thebflb_logcomponent (already enabled in this example). Without it, theLOG_*macros degrade to no-ops and no logs appear. - Header (log levels):
components/utils/log/bflb_log/bflb_log_conf.his the default config (bflog_conf_user.hin the example directory is a reference copy). Its macros control what is compiled and output:BFLB_LOG_ENABLE: master switch; commenting it out excludes log code from the build;BFLB_LOG_LEVEL_ENABLE: the highest level compiled into the firmware (BFLB_LOG_LEVEL_TRACEin the example, i.e. all of F/E/W/I/D/T);BFLB_LOG_LEVEL_DEFAULT/BFLB_LOG_DIRECT_LEVEL_DEFAULT: default filter level of the recorder/outputter; logs below it are not recorded/output.
- Runtime (tag filter): the
enableargument ofBFLB_LOG_DEFINE_TAG(name, tag, enable)decides whether that tag outputs initially; at runtime usebflb_log_global_filter("MAIN", true/false)to toggle tags dynamically (the example cycles three filter states every second).
For your own project, start by copying the example's defconfig and bflog_conf_user.h; once levels 1 and 2 are enabled, logs are emitted on uart0.
No log output at all
First confirm the baud rate is 2000000; then check that both the recorder and the outputter were resumed (suspended objects output nothing), and that the global filter is not disabling both tags (bflb_log_global_filter with both tags false means no output).
The serial tool shows plain text instead of colors
Colors rely on ANSI escape sequences, so use a serial/terminal tool that supports ANSI colors (e.g. MobaXterm, Xshell, Windows Terminal), and confirm the outputter was created with BFLB_LOG_DIRECT_COLOR_ENABLE (enabled in the example). The actual colors follow the BFLB_LOG_COLOR_* macros in the code (F magenta / E red / W yellow / I none / D white / T dim white); the example's reference config has the green INFO definition commented out — uncomment it and rebuild if you want green INFO.
TEST tag logs are invisible
In the enable only MAIN output filter state TEST is disabled — that is the tag-filtering behavior being demonstrated. Keep both tags true to see both groups.
Log timestamps look wrong
The timestamp comes from bflb_log_time(), which is RTC time plus the fixed timestamp_base. If the RTC is not calibrated or the base does not match the current time, the display drifts, but functional verification is unaffected.
Have questions?
For any other questions, visit the unified Q&A and discussion board: Ai-Thinker Discussions

