Skip to content

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_t value. 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

1
Prepare the Hardware

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).

2
Enter the Example Directory

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_b
3
Build the Project

Run the build command. The Ai-M62 (BL616) and Ai-M61 (BL618) belong to the same series, so both use bl616:

make CHIP=bl616 BOARD=bl616dk
4
Flash the Firmware

Connect 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/ttyUSB0
5
Run and Verify

Open 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
c
#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

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