Concepts First
- DBI (Type B): a parallel-ish LCD interface (multiple data/clock/control lines) used with small/medium panels.
- Pixel/color format: a screen is made of pixels; each is a
lcd_color_tvalue. A format mismatch causes a garbled image. - DMA refresh: the whole image buffer is handed to DMA to push to the panel, freeing the CPU — ideal for animation/video refresh.
Example Overview
This page is based on the lcd_type_b example in the official Bouffalo SDK (examples/peripherals/dbi/lcd_type_b), which demonstrates a DBI (Type B) LCD:
- Initializes the LCD and registers an async refresh callback (
lcd_async_callback_register); - Clears the screen, draws 16-pixel ASCII strings and red/green/blue border rectangles;
- Refreshes four color blocks in a loop with DMA non-blocking draws (
lcd_draw_picture_nonblocking), logging each flush.
Operation Steps
You need a Type B (DBI) LCD panel. Connect the data/clock/control pins to the board pins per lcd.h/board config (VCC 3.3V, shared GND).
Open a terminal and enter the DBI example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):
cd examples/peripherals/dbi/lcd_type_bRun 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). The screen shows red/green Hello World ! and dbi lcd test. text, red/green/blue border rectangles, then four color blocks refresh in a loop while the serial prints lcd async int come, cnt: N and lcd flush done.
Code Execution Flow
The complete execution flow from startup to running is shown below (loop arrows mean repeated execution):
APIs Used by the Example
lcd_init()
Initializes the LCD controller and DBI interface (resolution from LCD_W/LCD_H in lcd.h).
Parameters: none
Return: 0 on success; negative error code on failure
lcd_async_callback_register(cb)
Registers the async refresh callback, invoked when a DMA flush completes.
Parameters:
cb: callback function
Return: none
lcd_draw_str_ascii16 / lcd_draw_rectangle / lcd_draw_picture_nonblocking(...)
Draws 16-pixel ASCII strings, rectangles, and DMA non-blocking picture regions.
Parameters: coordinates, colors (LCD_COLOR_RGB(r,g,b)), buffers, etc.
Return: 0 on success; negative error code on failure
lcd_draw_is_busy / lcd_clear(...)
Checks whether a refresh is busy and clears the whole screen.
Parameters: color (for clear)
Return: lcd_draw_is_busy returns busy state; others return 0 on success
Complete Code
The complete source below matches the effect described on this page. It is based on the official example (examples/peripherals/dbi/lcd_type_b); the LED pins are adapted to the Ai-M61/62-32S-Kit onboard RGB LED. Collapsed by default, click to expand:
📜 Click to expand lcd_type_b/main.c full code
#include "bflb_mtimer.h"
#include "board.h"
#include "lcd.h"
#define DBG_TAG "MAIN"
#include "log.h"
#define LCD_TEST_W (100)
#define LCD_TEST_H (20)
lcd_color_t lcd_test_buff[LCD_TEST_W * LCD_TEST_H];
lcd_color_t lcd_test_color[] = {
LCD_COLOR_RGB(0xff, 0xff, 0xff),
LCD_COLOR_RGB(0xff, 0x00, 0x00),
LCD_COLOR_RGB(0x00, 0xff, 0x00),
LCD_COLOR_RGB(0x00, 0x00, 0xff),
LCD_COLOR_RGB(0xff, 0xff, 0x00),
LCD_COLOR_RGB(0x00, 0xff, 0xff),
LCD_COLOR_RGB(0xff, 0x00, 0xff),
};
void color_fill_buff(lcd_color_t color)
{
for (int i = 0; i < sizeof(lcd_test_buff) / sizeof(lcd_color_t); i++) {
lcd_test_buff[i] = color;
}
}
void flush_async_callback()
{
static uint32_t cnt;
cnt += 1;
/* lcd async int come */
LOG_I("lcd async int come, cnt: %d\r\n", cnt);
}
int main(void)
{
int color_num = 0;
board_init();
LOG_I("DBI lcd test\r\n");
/* lcd init */
lcd_init();
/* register async callback */
lcd_async_callback_register(flush_async_callback);
/* clean lcd */
lcd_clear(LCD_COLOR_RGB(0x00, 0x00, 0x00));
/* disp font */
lcd_draw_str_ascii16(20, 20, LCD_COLOR_RGB(0xff, 0x00, 0x00), LCD_COLOR_RGB(0x00, 0x00, 0x00), (uint8_t *)"Hello World !", 100);
lcd_draw_str_ascii16(20, 40, LCD_COLOR_RGB(0x00, 0xff, 0x00), LCD_COLOR_RGB(0x00, 0x00, 0x00), (uint8_t *)"dbi lcd test.", 100);
lcd_draw_rectangle(0, 0, LCD_W - 1, LCD_H - 1, LCD_COLOR_RGB(0xff, 0x00, 0x00));
lcd_draw_rectangle(5, 5, LCD_W - 6, LCD_H - 6, LCD_COLOR_RGB(0x00, 0xff, 0x00));
lcd_draw_rectangle(10, 10, LCD_W - 11, LCD_H - 11, LCD_COLOR_RGB(0x00, 0x00, 0xff));
while (1) {
for (int i = 0; i < 4; i++) {
/* fill buff */
uint8_t n = (color_num + i) % (sizeof(lcd_test_color) / sizeof(lcd_color_t));
color_fill_buff(lcd_test_color[n]);
/* draw picture (DMA non-blocking) */
lcd_draw_picture_nonblocking(30, (80 + (LCD_TEST_H + 5) * i), (30 + LCD_TEST_W - 1), (80 + (LCD_TEST_H + 5) * i + LCD_TEST_H - 1), lcd_test_buff);
/* wait flush done */
while (lcd_draw_is_busy()) {
};
LOG_I("lcd flush done\r\n");
if (color_num >= sizeof(lcd_test_color) / sizeof(lcd_color_t)) {
color_num = 0;
}
}
color_num ++ ;
bflb_mtimer_delay_ms(1000);
}
}FAQ
The screen shows nothing
Make sure the panel is DBI/Type B and wired correctly (data/clock/control, backlight, VCC/GND); check that the resolution in lcd.h matches the panel, and that the backlight pin is enabled.
Garbled image or wrong colors
Check that the pixel format/color depth matches (lcd_color_t), and that the panel's driver IC matches the lcd component; adjust the init sequence if needed.
The refresh hangs and stays busy
Async refresh depends on the DMA completion interrupt and callback; confirm lcd_async_callback_register was called and the DMA channel is not occupied by another peripheral.
Have questions?
For any other questions, visit the unified Q&A and discussion board: Ai-Thinker Discussions

