Skip to content

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) example applications/get-started/blink; the code can be found directly in your local SDK.

🎯Page GoalUse GPIO output to blink the on-board LED at 1-second intervals and learn the SDK build and flash commands.
🧰Prerequisites① An Ai-WB2 development board (e.g. Ai-WB2-32S-Kit) ② Development environment set up per [SDK Installation](../sdk/sdk_intro).
🔗RelatedEnvironment not ready? See [SDK Introduction](../sdk/sdk_intro) and [Linux Quick Start](../sdk/get-start_for_Linux); GPIO input: [GPIO Input (Button Detection)](./gpio_button).

Hardware Preparation
  1. Connect the Ai-WB2 development board to the computer with a Type-C data cable; the on-board power LED lights up.
  2. 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.
  3. 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.

Enter the Example Project

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: cd is the “change directory” command; this enters the blink example project. All subsequent make build and make flash commands 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
Write the Code

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 the Project

Build in the project directory:

make -j8

Note: make is the “build” command, turning code into firmware (a program file) the board can run; -j8 builds 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 — run cd toolchain/riscv/Linux && . chmod755.sh first, then rebuild.

Flash the Firmware

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 flash is the “flash” command, writing the compiled firmware into the board’s chip. After p= comes the serial device (change it to your computer’s actual port — check with ls /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.

Run and Verify

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 to 3 (the GPIO_LED_PIN macro, change it per your board)
  • pullup: enable internal pull-up, values: 1 enable / 0 disable (push-pull output needs no pull-up, pass 0)
  • pulldown: enable internal pull-down, values: 1 enable / 0 disable

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 as bl_gpio_enable_output (0~22)
  • value: output level, values: 1 high (3.3V) / 0 low (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 via pdMS_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, shaped void task(void *arg), required
  • name: 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; pass NULL if none
  • prio: task priority, values: 0 (lowest)~19 (highest, SDK config), e.g. 16
  • handle: output pointer for the task handle; pass NULL if 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
c
#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.

Released under the MIT License. Build Time 2026-09-11 14:52:23