Overview
IoT devices often run on batteries, and sleep mode is the core way to cut power consumption. The Ai-WB2 supports Deep Sleep (deep sleep, in plain words: the board sleeps like a person — CPU stops, peripherals shut down, almost no power used): keeping only the 4KB Retention RAM (retention memory, in plain words: a small memory that keeps power while sleeping, so data doesn't get lost) and RTC (real-time clock, in plain words: the chip's built-in "alarm clock" that wakes the board up at the set time) wake capability, power consumption can drop to the µA level (microampere, a current unit — in deep sleep it's like a coin cell battery lasting years). This tutorial demonstrates entering deep sleep by button + timed auto-wake, and uses Retention RAM to verify data survives the wake-up.
In plain words: deep sleep is like sleeping at night — a sleeping person uses almost no energy, but the body's biological clock (like the board's RTC alarm) wakes you at the set time, and when you wake you still remember what happened before bed (like the data in Retention RAM not being lost). This tutorial has the board "sleep 10 seconds then wake", and checks whether the data noted before sleeping is still there.
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/system/deep_sleep; the code can be found directly in your local SDK.
Wire per the official example:
| Ai-WB2 Pin | Peripheral |
|---|---|
| IO4 | Button (pressed to GND, detects entering sleep) |
| IO7 | Wake pin (leave floating; timed wake needs no external trigger) |
| GND | Other end of the button |
💡 The official example
sleep_time_ms = 10000: timed auto-wake (RTC wakes after 10 seconds); set to0and only IO7 level change can wake (connect a button to wake by press). Wake pins only support GPIO7 / GPIO8.
Open a terminal and enter the official deep_sleep example project directory:
cd ~/Ai-Thinker-WB2/applications/system/deep_sleep
Note:
cdis the “change directory” command and~means your user home directory. This enters the deep_sleep example project; all subsequentmakecommands must run in this directory. If it saysNo such file or directory, the path is wrong — see the FAQ at the end.
Open deep_sleep/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/system/deep_sleep/deep_sleep/main.c).
Code highlights:
| Code | Purpose |
|---|---|
#define test (*(volatile uint8_t*)0x40010000) |
Define a test variable in Retention RAM; only with it can you verify data isn’t lost after sleep |
bl_gpio_enable_input(ENTER_SLEEP_PIN, 0, 0) |
Configure IO4 as input; without input mode the button press can’t be read |
!bl_gpio_input_get_value(ENTER_SLEEP_PIN) |
Read IO4’s level; button pressed pulls low returning 0, negated to enter sleep |
test++ |
Counter +1 before every sleep; the value increased after wake means data wasn’t lost |
hal_hbn_init(&weakup_pin, 1) |
Tell the chip to use IO7 as the wake pin; without it external wake doesn’t work |
hal_hbn_enter(sleep_time_ms) |
Really “sleep” for 10 seconds; pass 0 to not auto-wake, only IO7 can trigger |
💡 Retention RAM: the 4KB memory at
0x40010000, kept powered during Deep Sleep, used to restore the scene after wake. The variable value is still there after wake — that’s the key to verifying sleep in this example.
Build in the project directory:
make -j8
Note:
makeis the “build” command, translating the source code into machine code the board can run;-j8builds with 8 parallel cores, faster.
On success a firmware build_out/deep_sleep.bin is generated (firmware: the program burned into the board after compilation, like the board’s “operating system + your program”).
Keep the board connected via USB, confirm the serial device, and flash:
make flash p=/dev/ttyUSB0 b=921600
Note:
make flashis the “flash” command, writing the compiled firmware into the chip (flashing: the process of writing a program into the chip);p=/dev/ttyUSB0is the serial device — change it to your computer’s actual port (likeCOM3on Windows),b=921600is the flash baud rate (transfer speed).
⏳ During flashing, press and hold the EN button on the board when prompted to enter download mode; wait for the progress bar to complete — that means the flash succeeded. If it keeps waiting or reports the serial port can’t open, see the FAQ at the end.
After flashing, open a serial assistant (baud rate 921600); the initial print:
test:0
Press the IO4 button, the log becomes:
test:0
enter sleep
The board enters deep sleep (whole-board current drops to the µA level), auto-wakes after 10 seconds, printing again:
test:1
💡 Key verification: after wake
testchanged from 0 to 1, meaning Retention RAM didn’t lose data during deep sleep.test++runs before every sleep entry, so the value keeps accumulating after each wake (0→1→2→…).
⚠️ Power measurement: use a multimeter in series with the board’s power positive terminal to measure current; during sleep the current should drop to the µA level (roughly below 10µA), jumping back to the mA level the instant it wakes.
✅ Expected result:
enter sleepappears, auto-wake after 10 seconds printstest:1(value incrementing) — verified. If onlytest:0shows butenter sleepnever appears, sleep wasn’t entered — see the FAQ at the end.
API Summary for This Tutorial
bl_gpio_enable_input(pin, pullup, pulldown)
Configures the pin as digital input mode to read button/sensor high-low levels (detecting the button press to enter sleep in this tutorial).
Parameters:
pin: pin number, values:0~22(GPIO0~GPIO22); the button uses4(ENTER_SLEEP_PIN) in this tutorialpullup: enable internal pull-up or not, values:1enable /0disable (the example passes0; the button needs an external pull-up)pulldown: enable internal pull-down or not, values:1enable /0disable
Return: 0 on success; negative error code on failure
bl_gpio_input_get_value(pin)
Reads the pin's current level state.
Parameters:
pin: pin number, values:0~22
Return: level value: 1 high / 0 low (returns 0 on read failure)
hal_hbn_init(pinbuf, pinbuf_size)
Configures the deep-sleep wake pins and their count; call once before entering sleep.
Parameters:
pinbuf: array pointer of wake pin numbers (only GPIO7 / GPIO8 supported),&weakup_pin(value7) in this tutorialpinbuf_size: array length (wake pin count), values:0~2
Return: 0 on success; negative error code on failure
hal_hbn_enter(time)
Puts the chip into HBN deep sleep, power down to the µA level; CPU stops, log output stops, and after wake the program restarts from the beginning of main.
Parameters:
time: sleep duration (milliseconds), values:0means wake only by pin (no timed wake) / non-0means RTC auto-wake at the set time;10000(10 seconds) in this tutorial
Return: never returns (sleeps on call; the program restarts after wake)
vTaskDelay(ms)
Suspends the current task for the given milliseconds, yielding CPU to other tasks meanwhile.
Parameters:
ms: delay in milliseconds, values: any non-negative integer (internally converted to system ticks viapdMS_TO_TICKS)
Return: none
Full Code
Below is the complete deep_sleep/main.c source, identical to the official example (applications/system/deep_sleep/deep_sleep/main.c):
📜 Click to expand the full deep_sleep/main.c code
#include <stdio.h>
#include <string.h>
#include <FreeRTOS.h>
#include <task.h>
#include <blog.h>
#include "bl_sys.h"
#include <stdint.h>
#include <string.h>
#include "bl_sys.h"
#include "FreeRTOS.h"
#include "task.h"
#include "hosal_rng.h"
#include "hal_hbn.h"
#include <bl_gpio.h>
#define ENTER_SLEEP_PIN 4
#define WEAKUP_PIN 7
#define test (*((volatile uint8_t *)0x40010000)) // Deep sleep memory (Retention RAM), size : 4KB
void main(void)
{
uint32_t sleep_time_ms = 10000; // deep sleep time, If you do not need to periodically wake up, set sleep_time_ms=0
uint8_t weakup_pin;
bl_gpio_enable_input(ENTER_SLEEP_PIN, 0, 0);
printf("test:%d\r\n", test);
vTaskDelay(pdMS_TO_TICKS(100));
weakup_pin = WEAKUP_PIN;
for (;;)
{
if (!bl_gpio_input_get_value(ENTER_SLEEP_PIN))
{
printf("enter sleep\r\n");
test++;
vTaskDelay(pdMS_TO_TICKS(100));
hal_hbn_init(&weakup_pin, 1);
hal_hbn_enter((uint32_t)sleep_time_ms);
}
vTaskDelay(pdMS_TO_TICKS(5));
}
}FAQ & Troubleshooting
⚠️ Pressing the button does nothing (no sleep)
Cause: wrong button wiring, or no internal pull-up on IO4 causing level jitter
Fix: confirm one end of the button connects to IO4 and the other to GND; the button needs an external 10kΩ pull-up to 3V3 (official bl_gpio_enable_input(4, 0, 0) doesn't enable the internal pull-up)
⚠️ Timed wake doesn't work (sleeps forever)
Cause: with sleep_time_ms = 0 there's no timed wake
Fix: pass a non-0 millisecond value for auto-wake; keep 0 for pin-only wake (IO7 with a button, wake by press)
⚠️ test value cleared after wake
Cause: a POR reset happened during sleep (e.g. the external RESET pin pulled low, or power dropped) instead of a normal wake
Fix: confirm the wake is triggered by RTC timing or IO7; don't press the board's RST key during testing (RST clears Retention RAM)
⚠️ Can't flash firmware after sleeping
Cause: the chip is in deep sleep and download mode wasn't entered
Fix: press and hold EN during flashing (or re-power and flash immediately), release after download mode is established
⚠️ Serial port won't open / /dev/ttyUSB0 not found
Cause: USB-to-serial driver not installed, port occupied, or (on Linux) no access permission
Fix: on Linux confirm the device is recognized with lsusb, run sudo chmod 666 /dev/ttyUSB0 or add your user to the dialout group and retry; on Windows check the COM port in Device Manager and install the CH340/CP210x driver
⚠️ cd reports No such file or directory / no Makefile found
Cause: make ran outside the example project directory, or the SDK install path differs from the tutorial
Fix: cd ~/Ai-Thinker-WB2/applications/system/deep_sleep first, then run make; if ~/Ai-Thinker-WB2 doesn't exist, find the SDK with find ~ -name "Ai-Thinker-WB2"
Self-Check
After pressing IO4, enter sleep prints, auto-wake after 10 seconds with the test value incrementing — deep sleep is verified.

