Overview
GPIO (General Purpose Input/Output — the "metal pins" on the board that you can program) is the module's most basic peripheral. This tutorial uses GPIO output to blink an LED and walks you through the complete development flow: project setup → coding → build → flash (writing the compiled program into the board's chip) → run and verify. This is the foundation for all later peripheral tutorials, so completing it first is recommended.
In plain words: a GPIO pin is like a "wire end" sticking out of the board. When the program makes it output a high level (about 3.3V, like closing a switch), an LED connected to it lights up; when it outputs a low level (about 0V, like opening the switch), the LED goes off. This tutorial has the program toggle once every second, making the LED blink.
This tutorial is based on the official Ai-Thinker SDK (Ai-Thinker-Open/Ai-Thinker-WB2, version
release_bl_iot_sdk_1.6.40) exampleapplications/get-started/blink; the code can be found directly in your local SDK.
- Connect the Ai-WB2 development board to the computer with a Type-C data cable; the on-board power LED lights up.
- Locate the on-board LED: the Ai-WB2-32S-Kit has a blue LED (GPIO3); some board models use different pins — follow the silkscreen on your board.
- If the on-board LED is hard to see, connect an LED’s anode (long leg) through a 330Ω current-limiting resistor to a GPIO pin, and the cathode to ground.
💡 The example code in this tutorial uses GPIO 3 by default (
#define GPIO_LED_PIN 3); modify this macro (a macro = a named alias for a number, replaced with the actual value at compile time) to fit your board.
This tutorial directly uses the blink example project shipped with the official SDK. Open a terminal and enter that project directory:
cd ~/Ai-Thinker-WB2/applications/get-started/blink
Note:
cdis the “change directory” command; this enters the blink example project. All subsequentmakebuild andmake flashcommands must run inside this directory first.
📌 The official SDK’s example projects live under
applications/, organized by function (get-started,peripherals,wifi, etc.); this tutorial series is based on the official example projects.
Project directory structure:
| File | Purpose |
|---|---|
main/main.c |
Main program source, the file modified in this tutorial |
Makefile |
Build entry point, usually no changes needed |
proj_config.mk |
Project config (Flash size, feature toggles, etc.), usually no changes needed |
Open main/main.c. The full code for this step has been moved to the end of this page:
📜 Full Code — in the “Full Code” section below, collapsed by default — click to expand, identical to the official example (
applications/get-started/blink/blink/main.c).
Code highlights:
| API | Purpose |
|---|---|
bl_gpio_enable_output(pin, 0, 0) |
First configure the LED pin as push-pull output (can output high/low level); without this the program can’t control this pin |
bl_gpio_output_set(pin, value) |
Output a level on the pin: 1 lights the LED, 0 turns it off; without it the LED never lights |
vTaskDelay(1000) |
Sleep 1 second before continuing; without it the on/off switching is too fast to see |
xTaskCreate(...) |
Create an independently running task (the code loops inside the task); without it the program does nothing |
Build in the project directory:
make -j8
Note:
makeis the “build” command, turning code into firmware (a program file) the board can run;-j8builds with 8 parallel cores, faster.
On success a firmware build_out/blink.bin is generated, and you’ll see:
✓ Built target blink
⚠️ If it reports
riscv64-unknown-elf-gcc: command not found, the toolchain permissions aren’t configured — runcd toolchain/riscv/Linux && . chmod755.shfirst, then rebuild.
Keep the board connected via USB, confirm the serial device (usually /dev/ttyUSB0 on Linux), and flash:
make flash p=/dev/ttyUSB0 b=921600
Note:
make flashis the “flash” command, writing the compiled firmware into the board’s chip. Afterp=comes the serial device (change it to your computer’s actual port — check withls /dev/ttyUSB*);b=is the flash baud rate (transfer speed).
⏳ During flashing, press and hold the EN button on the board when prompted to enter download mode (some boards enter automatically); wait for the progress bar to complete — that means the flash succeeded. Windows flashing: see Windows Quick Start.
After flashing, the board automatically restarts; watch the on-board LED blink once every second.
Open a serial assistant (baud rate 921600 — the serial transfer speed; both ends must match) and check the logs:
Turning the LED ON!
Turning the LED OFF!
Turning the LED ON!
Turning the LED OFF!
...
The logs and the LED actions are in sync — GPIO output is working ✅
Seeing the LED blink once a second with the serial alternately printing Turning the LED ON/OFF! means success; if the LED doesn’t blink or there’s no log, check the “FAQ & Troubleshooting” section at the end.
API Summary for This Tutorial
bl_gpio_enable_output(pin, pullup, pulldown)
Configures the specified pin as push-pull output, capable of driving loads like LEDs and buzzers (used here to light the LED).
Parameters:
pin: pin number, values:0~22(GPIO0~GPIO22); this tutorial defaults to3(theGPIO_LED_PINmacro, change it per your board)pullup: enable internal pull-up, values:1enable /0disable (push-pull output needs no pull-up, pass0)pulldown: enable internal pull-down, values:1enable /0disable
Return: 0 on success; negative error code on failure
bl_gpio_output_set(pin, value)
Outputs a high or low level on a pin already configured as output.
Parameters:
pin: pin number, values asbl_gpio_enable_output(0~22)value: output level, values:1high (3.3V) /0low (0V)
Return: 0 on success; negative error code on failure
vTaskDelay(ms)
Suspends the current task for the specified number of milliseconds, yielding the CPU to other tasks.
Parameters:
ms: delay in milliseconds, values: any non-negative integer (internally converted to system ticks viapdMS_TO_TICKS)
Return: none
xTaskCreate(task, name, stack, param, prio, handle)
Creates a task and adds it to the ready queue; the scheduler runs it according to priority.
Parameters:
task: pointer to the task entry function, shapedvoid task(void *arg), requiredname: task name string (for debugging), e.g."led_task"stack: task stack size (in words), values: any size within memory limits, e.g.2048(too small a stack overflows easily and crashes)param: pointer to the argument passed to the entry function; passNULLif noneprio: task priority, values:0(lowest)~19(highest, SDK config), e.g.16handle: output pointer for the task handle; passNULLif not needed
Return: pdPASS on success; pdFAIL on failure (e.g. out of memory)
Full Code
Below is the complete main/main.c source, identical to the official example (applications/get-started/blink/blink/main.c):
📜 Click to expand the full main/main.c code
#include <stdio.h>
#include <string.h>
#include <FreeRTOS.h>
#include <task.h>
#include <bl_gpio.h>
#define GPIO_LED_PIN 3
void blink_test(void *param)
{
uint8_t value = 1;
while (1)
{
bl_gpio_enable_output(GPIO_LED_PIN, 0, 0);
printf("Turning the LED %s! \r\n", value == 1 ? "ON" : "OFF");
bl_gpio_output_set(GPIO_LED_PIN, value);
value = !value;
vTaskDelay(1000);
}
}
void main(void)
{
xTaskCreate(blink_test, "blink", 1024, NULL, 15, NULL);
}FAQ & Troubleshooting
⚠️ The LED doesn't light
Cause: LED polarity reversed, the current-limiting resistor is too large, or the GPIO pin doesn't match your board model
Fix: confirm the LED anode connects to GPIO and the cathode to ground; check that GPIO_LED_PIN is the actual pin on your board
⚠️ Build reports command not found
Cause: the toolchain has no execute permission
Fix: run cd toolchain/riscv/Linux && . chmod755.sh, then make again
⚠️ Flashing reports it can't open the serial port
Cause: wrong serial device or insufficient permissions
Fix: confirm the device with ls /dev/ttyUSB*; for permissions, run sudo usermod -aG dialout $USER then log in again
⚠️ Flashing keeps waiting, the progress bar doesn't move
Cause: download mode wasn't entered, or the cable only charges and can't transfer data
Fix: press and hold EN to enter download mode when prompted; try a Type-C cable that can transfer data and retry
⚠️ Running make reports no Makefile found
Cause: the build command ran in the wrong directory (it must run inside the example project)
Fix: first cd ~/Ai-Thinker-WB2/applications/get-started/blink into the project directory, then run make -j8
Self-Check
The LED blinks steadily at 1-second intervals and the serial prints Turning the LED ON/OFF! alternately — GPIO output is verified.

