Concepts First
- Shell (command line): a human-machine interface where you type text commands over serial, press Enter to execute, and see results — like a terminal on a PC. Embedded systems use it for debugging and configuration.
- SHELL_CMD_EXPORT_ALIAS: the macro that registers a function as a command.
SHELL_CMD_EXPORT_ALIAS(shell_test, test, shell test.)means typingtestcallsshell_test(). - shell_os vs shell_no_os: the SDK provides two variants —
shell_osruns on FreeRTOS (a dedicated shell task, input never blocks business logic), whileshell_no_osis a bare-metal polling version (callsshell_handlerin awhile(1)loop). - Command entry: almost every wireless example command (
wifi_sta_connect,mqtt_connect, etc.) is registered withSHELL_CMD_EXPORT_ALIAS; typing it over serial triggers the function.
Example Overview
This page is based on the shell_os example in the official Bouffalo SDK (examples/shell/shell_os), which demonstrates a FreeRTOS-based Shell:
- Initializes serial 0 (
uart0) and creates the shell task withshell_init_with_task(uart0); - Starts the FreeRTOS scheduler (
vTaskStartScheduler); the shell task starts listening for serial input; - Registers a custom command
testviaSHELL_CMD_EXPORT_ALIAS, printingshell testwhen invoked; - Sibling example:
examples/shell/shell_no_os(bare-metal polling variant without FreeRTOS).
Note
Registering your own commands in the shell is the fastest way to debug your code: flash once, then trigger functions from the serial console without rebuilding.
Operation Steps
Open a terminal and enter the SDK Shell example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):
cd examples/shell/shell_osRun 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 help to list commands (including the test command registered by this example), then type test and press Enter — the serial prints shell test.
Code Execution Flow
The flow from boot to receiving commands is:
APIs Used by the Example
shell_init_with_task(uart)
Initializes the shell and creates a dedicated shell task that reads serial input and parses commands. Typing commands does not affect other tasks.
Parameters:
uart: serial device handle (herebflb_device_get_by_name("uart0"))
Returns: none
SHELL_CMD_EXPORT_ALIAS(func, cmd, help)
Registers a function as a shell command at compile time. Typing the command name invokes func(argc, argv).
Parameters:
func: the function to call (signatureint func(int argc, char **argv))cmd: command name (e.g.,test)help: help text shown by thehelpcommand
Returns: none (macro)
vTaskStartScheduler()
Starts the FreeRTOS scheduler; the shell task begins running. main never returns after this call.
Parameters: none
Returns: none (never returns)
Complete Code
The following is the complete source of shell_os/main.c, identical to the official example, collapsed by default:
📜 Click to expand shell_os/main.c full code
#include "bflb_mtimer.h"
#include "bflb_uart.h"
#include "shell.h"
#include <FreeRTOS.h>
#include "semphr.h"
#include "board.h"
static struct bflb_device_s *uart0;
extern void shell_init_with_task(struct bflb_device_s *shell);
int main(void)
{
board_init();
configASSERT((configMAX_PRIORITIES > 4));
uart0 = bflb_device_get_by_name("uart0");
shell_init_with_task(uart0);
vTaskStartScheduler();
while (1) {
}
}
int shell_test(int argc, char **argv)
{
printf("shell test\r\n");
return 0;
}
SHELL_CMD_EXPORT_ALIAS(shell_test, test, shell test.);📜 Click to expand shell_no_os/main.c full code (bare-metal)
#include "bflb_mtimer.h"
#include "bflb_uart.h"
#include "shell.h"
#include "board.h"
static struct bflb_device_s *uart0;
int main(void)
{
int ch;
board_init();
uart0 = bflb_device_get_by_name("uart0");
shell_init();
while (1) {
if((ch = bflb_uart_getchar(uart0)) != -1)
{
shell_handler(ch);
}
}
}
int shell_test(int argc, char **argv)
{
printf("shell test\r\n");
return 0;
}
SHELL_CMD_EXPORT_ALIAS(shell_test, test, shell test.);FAQ
Typing a command does nothing. What's wrong?
First check the serial baud rate is 2000000 and the terminal sends a carriage return; then verify the command name matches the registered one (e.g., test). If the prompt itself never appears, the firmware likely wasn't flashed or the wrong serial port is selected.
What is the difference between shell_os and shell_no_os?
shell_os is FreeRTOS-based: the shell is a dedicated task, ideal for OS projects. shell_no_os needs no RTOS: it polls serial input in a while(1) loop, ideal for bare-metal projects. Command registration is identical in both.
How do I list all commands supported by the firmware?
Type help at the bouffalolab /> prompt. It lists every command registered with SHELL_CMD_EXPORT_ALIAS plus its help text, including wireless commands such as wifi_sta_connect.
Can command functions take arguments?
Yes. The signature is int func(int argc, char **argv): argc is the argument count and argv the argument array. For example, after registering set_led, typing set_led 1 gives argv[1] = "1", which you can convert with atoi.

