bin2bmp Tool

Tool Overview

bin2bmp is a small debugging utility that converts raw framebuffer binary data back into BMP images. Common use cases include:

  • When the screen display is abnormal, directly inspect what LVGL actually wrote into the framebuffer — to decide whether the problem lies in LVGL rendering or the LCD driver / panel itself

  • Capture the current screen content as an image on boards that do not have a dedicated screenshot interface

  • Verify dual-buffer switching, partial refresh, and other display logic

The tool lives under tools/bin2bmp/ in the SDK and consists of three files:

File

Purpose

bmp.py

Core library for BMP generation and pixel format conversion

bin2bmp.py

Offline mode: convert an existing .bin file into a BMP

jlinkbin2bmp.py

Online mode: dump the framebuffer directly from the board via J-Link, then convert to BMP

How It Works

The whole flow is a two-step pipeline: “memory → bin file → BMP image”:

┌────────────┐   J-Link/SWD   ┌────────────┐   bin2bmp    ┌─────────┐
│ Board RAM   │ ────────────▶ │  xxx.bin   │ ──────────▶ │ xxx.bmp │
│ framebuffer │   (savebin)   │ (raw data) │  (decode)    │ (image) │
└────────────┘               └────────────┘              └─────────┘
  • jlinkbin2bmp.py does both steps in one shot: it first invokes JLink.exe’s savebin command to dump a memory range into a .bin file, then calls bmp.py to decode that .bin into a .bmp and opens it automatically.

  • bin2bmp.py only does the second step — useful when you already have a .bin file on hand (a previous dump, or one shared by a colleague).

Supported Pixel Formats

The tool supports the pixel formats commonly found in framebuffers. The format argument must match the project’s actual configuration, otherwise the decoded image will look like scrambled color stripes.

Format

Bit depth

Bytes/pixel

Description

a8

8

1

8-bit alpha, monochrome (default red) + transparency

a4

4

0.5

4-bit alpha, 2 pixels per byte

a2

2

0.25

2-bit alpha, 4 pixels per byte

rgb332

8

1

R3G3B2

rgb565

16

2

R5G6B5

bgr565

16

2

B5G6R5

argb8565

24

3

A8 + R5G6B5

rgb888

24

3

R8G8B8

argb8888

32

4

A8R8G8B8

rgba8888

32

4

R8G8B8A8

yuyv

16

2

YUV 4:2:2 packed (Y0 U Y1 V)

uyvy

16

2

YUV 4:2:2 packed (U Y0 V Y1)

Prerequisites

  1. Python 3: run python xxx.py directly — no third-party packages required (uses only the standard library).

  2. J-Link: when using jlinkbin2bmp.py, install SEGGER J-Link and make sure JLink.exe is on your PATH.

  3. The board is connected to J-Link via SWD and the firmware is running.

Below we walk through a complete example using the example/multimedia/lvgl/watch sample from the SDK (board sf32lb58-lcd_a128r32n1, screen 390×450, RGB888).

Method 2: bin2bmp.py — Offline Conversion

Use bin2bmp.py when you already have a .bin file on hand (saved previously, or received from a colleague):

python bin2bmp.py hcpu_ram.bin rgb565 454 454 2000

Argument breakdown:

#

Meaning

1

Path to the bin file.

2

Pixel format.

3 / 4

Width / height in pixels.

5 (optional)

Offset in hex (e.g. 2000 means start parsing from byte 0x2000 inside the file; default is 0).

The output BMP is named <bin_filename>_offset0x<offset>_<width>x<height>_<format>.bmp and opens with the system’s default image viewer.

FAQ

The decoded image is full of color stripes

  • Wrong pixel format. For example, RGB565 misinterpreted as RGB888 throws off every pixel boundary. Go back to .config and double-check LV_COLOR_DEPTH.

  • Wrong resolution. Either dimension being incorrect produces diagonal stripes. Confirm LCD_HOR_RES_MAX / LCD_VER_RES_MAX in .config.

The whole image is shifted left/right or up/down

  • The address does not point at the true buffer start. Re-read main.map. If you are dumping buf2_2, make sure you accounted for the 64-byte alignment padding that follows buf2_1.

The decoded image is all black / all white / all zeros

  • That particular buffer is not currently in use. For example, a single-buffer configuration (LV_FB_ONE_NOT_SCREEN_SIZE) means buf1_2 does not exist, or one of the dual buffers may just not be the one actively being refreshed.

  • The screen genuinely shows a pure black/white frame (e.g. during boot logo or blanking).

The image is upside down

BMP files store pixels bottom-up, and the tool already handles the flip. If it still looks inverted, the height argument is most likely wrong — check whether you are reading a partial buffer (LV_FB_LINE_NUM) or a full-screen buffer.

Tips and Tricks

  • Capture intermediate animation frames. Run the dump while an animation is playing — buf2_1 and buf2_2 will differ, showing the “currently displayed” and “currently being drawn” frames respectively.

  • Inspect partial refresh regions. Dump buf1_1 (height = LV_FB_LINE_NUM rows) to see the slice LVGL is currently composing.

  • Batch dumps for comparison. jlinkbin2bmp.py always names the file with <address>_<width>x<height>_<format>.bmp, so archives are self-documenting.