TR2S Display Interface Driver Library
User Guide
API Reference & Porting Guide
Applicable to: TR2S series LCD controllers Supported interfaces: 4-wire SPI / QSPI / 8080-8bit / 8080-16bit Default reference project: STM32F10x (FSMC example / software SPI example)
1. Overview
This driver library targets the TR2S series LCD controllers. It provides a unified display control API (font rendering, geometric shapes, fill, backlight, rotation, version reading, self-test, soft reset, etc.) and abstracts the underlying host interface through function pointers (the LCD_Transmit structure), thereby supporting the following four host interfaces:
- 4-wire SPI (INTERFACE_SPI)
- Quad SPI (INTERFACE_QSPI)
- 8080 8-bit parallel (INTERFACE_8080_8B)
- 8080 16-bit parallel (INTERFACE_8080_16B)
The upper-layer API is completely interface-agnostic: the user only needs to select one interface macro in lcd_init.h and implement the BSP adaptation layer in the corresponding interface source file (the regions marked with /* user_change_begin / and / user_change_end */), and the library can run on any MCU platform. In the default STM32 reference project, the 8080 parallel interfaces are implemented via FSMC; on other platforms they can be replaced with equivalent approaches such as EMIF / GPMC / GPIO bit-banging, depending on the actual situation.
2. Directory Structure and File Descriptions
The directory structure of the driver library is as follows:
Display_interface/
├── lcd_init.h / lcd_init.c
├── lcd_cmd.h / lcd_cmd.c
└── interface/
├── interface.h
├── spi.c / spi.h
├── qspi.c / qspi.h
├── 8080_8b.c / 8080_8b.h
└── 8080_16b.c / 8080_16b.hResponsibilities of each file:
- lcd_init.{h,c}: Main driver initialization flow. Centrally defines the configuration macros (interface selection, WIDTH/HEIGHT resolution, rotation direction, color format), command macros, the LCD_Transmit structure declaration, and the lcd_device_init() entry point.
- lcd_cmd.{h,c}: ★ User API implementation. All tr2s_xxx display control functions (system control, display window, fonts, geometric shapes, generic command sending, etc.) are defined here; this is the file users mainly call into.
- interface/interface.h: Unified header file. Aggregates all interface headers and defines the STM32 reference-platform includes, the BUSY pin, and the WAIT_BUSY_SIGN macro. Application code only needs
#include "interface.h". - interface/spi.{c,h}: 4-wire SPI interface implementation; provides the enable function spi_enable().
- interface/qspi.{c,h}: QSPI interface implementation; provides the enable function qspi_enable(). In the default STM32 reference project, FSMC is used to emulate 4-line QSPI timing; replace it with an equivalent implementation per platform when porting.
- interface/8080_8b.{c,h}: 8080 8-bit parallel interface implementation; provides the enable function _8080_8b_enable().
- interface/8080_16b.{c,h}: 8080 16-bit parallel interface implementation; provides the enable function _8080_16b_enable().
Note: When porting, you only need to modify the BSP adaptation layer between /* user_change_begin / ~ / user_change_end */ in the corresponding interface source file under interface/; lcd_init.{h,c} and lcd_cmd.{h,c} require no changes. The 8080 parallel adaptation layer is implemented on STM32 FSMC in the default reference project and serves only as an example; other platforms may use a dedicated parallel-port controller (EMIF / GPMC / EBI, etc.) or GPIO-emulated 8080 timing as needed.
3. Configuration
All configuration is centralized in lcd_init.h; a macro defined as 1 enables that option:
#define INTERFACE_SPI 0 /* 4-wire SPI */
#define INTERFACE_QSPI 0 /* Quad SPI */
#define INTERFACE_8080_8B 0
#define INTERFACE_8080_16B 1
#define WIDTH 480
#define HEIGHT 480
//#define LCD_DISPLAY_ROTATE_0
#define LCD_DISPLAY_ROTATE_90
//#define LCD_DISPLAY_ROTATE_180
//#define LCD_DISPLAY_ROTATE_270
#define LCD_COLOR_FORMATE_RGB565
//#define LCD_COLOR_FORMATE_RGB888The BUSY pin (used to block-wait on the controller busy signal) can be configured in interface.h:
#define BUSYPINGROUP GPIOC
#define BUSYPIN GPIO_Pin_64. Software Architecture
The library adopts a "layered abstraction + function-pointer injection" design. lcd_device_init() in lcd_init.c selects and calls the corresponding xxx_enable() based on the macros; the latter does two things:
- ① Initializes the BSP (GPIO, parallel-port controller / FSMC / SPI / QSPI and other peripherals), filled in by the user in the user_change region;
- ② Calls xxx_transmit_init() to mount that interface's low-level read/write functions onto the global lcd_transmit structure.
Thereafter, all upper-layer tr2s_xxx APIs call the low level only through lcd_transmit, fully decoupled from the concrete interface:
| LCD_Transmit member | Purpose | Upper-layer call scenarios |
|---|---|---|
| writecmd(cmd) | Write one command | All command sending |
| writedatas(data,len) | Write a block of data | Parameters, pixels, strings |
| writestartsign() | Start a pixel-write stream | Prelude to writing GRAM (includes CMD_WRAM=0x2C) |
| writeendsign() | End a command/data stream | Pull CS high |
| writepix(buf,len) | Write pixel data | lcd_fillcolor screen refresh |
| readcmddatas(cmd,buf,len) | Read command data | Read version/IC info |
| delay(ms) | Millisecond delay | Power-on/reset wait |
| width / height | Current effective display width/height (rotation-aware) | Application layer resolution query |
5. Quick Start
Include the interface header in your application code, call the initialization, and the display APIs are ready to use:
#include "interface.h"
int main(void)
{
lcd_device_init();
u8 ver[9] = {0};
tr2s_lcd_read_version(ver);
tr2s_set_font_initdata(2, 2, 0, WHITE, BLACK);
tr2s_dispchar_usestandardfont_24x24(10, 10, "Hello TR2S");
tr2s_draw_circle_s(240, 240, 80, RED);
tr2s_lcd_fillcolor(0, 0, 100, 100, BLUE);
tr2s_set_pwm(80);
while (1) { }
}6. API Reference
All APIs below are defined in lcd_cmd.{c,h} with the tr2s_ prefix. Unless otherwise stated, color parameters use RGB565 (paired with LCD_COLOR_FORMATE_RGB565) and can directly use the predefined color macros. Each API is presented in its own subsection, in order: function prototype, corresponding command, description, and parameter list.
6.1 Initialization and System Control
lcd_device_init —— Initialization Entry
void lcd_device_init(void)Initialization entry. Selects and calls the corresponding interface's xxx_enable() according to the INTERFACE_xxx macro enabled in lcd_init.h, completing BSP initialization and lcd_transmit function-pointer mounting; then sets the effective width/height per LCD_DISPLAY_ROTATE_x and issues the rotation command when necessary. The application should call this function first.
tr2s_soft_reset —— Software Reset
void tr2s_soft_reset(void)Corresponding command:CMD_SOFT_RESET = 0x5A
Performs a software reset on the LCD controller; internally sends the fixed data value 0x01. After reset, it is recommended to wait for the controller to stabilize before proceeding.
tr2s_set_selftest_mode —— Self-Test Mode
void tr2s_set_selftest_mode(u8 state)Corresponding command:CMD_SELF_TEST = 0x12
Enters or exits the LCD self-test mode (color bars / test pattern).
state:non-zero enters self-test, 0 exits self-test
tr2s_set_rotation_angle —— Set Rotation
void tr2s_set_rotation_angle(u8 angle)Corresponding command:CMD_ROTATION = 0xAD
Sets the display rotation direction. Note: lcd_device_init() already calls this function automatically according to LCD_DISPLAY_ROTATE_x, so the application usually does not need to call it again; use it only when switching direction dynamically at runtime.
angle:0 = 0°, 1 = 90°, 2 = 180°, 3 = 270°
tr2s_set_pwm —— Set Backlight
void tr2s_set_pwm(u8 bl)Corresponding command:CMD_CONTROL_BL = 0x20
Sets the backlight PWM duty cycle.
bl:0 ~ 100, in percent; 0 turns the backlight off
tr2s_lcd_read_version —— Read Version and IC Info
void tr2s_lcd_read_version(u8 *version)Corresponding command:CMD_VERSION = 0x01 / CMD_IC = 0x02
Reads the controller firmware version and driver IC info, and prints them via printf. version[0]'s high 4 bits are the major version and low 4 bits the minor version; version[1..8] is the IC name string (null-terminated with \0).
version:caller-provided buffer, at least 9 bytes
6.2 Display Window and Pixel Writing
tr2s_set_display_window —— Set Active Window
void tr2s_set_display_window(u16 start_x, u16 start_y, u16 end_x, u16 end_y)Corresponding command:CMD_SET_X = 0x2A / CMD_SET_Y = 0x2B
Sets the active display window (column address range + row address range). Pixels subsequently written to GRAM will fall into this rectangular region in order. A call to this function is usually followed by a tr2s_lcd_fillcolor or a custom pixel-write stream.
start_x / start_y:top-left corner coordinates of the windowend_x / end_y:bottom-right corner coordinates of the window
tr2s_lcd_fillcolor —— Fill Region with Solid Color
void tr2s_lcd_fillcolor(u16 x, u16 y, u16 w, u16 h, u32 color)Corresponding command:CMD_WRAM = 0x2C
Fills a rectangular region with a solid color. Internally it first calls tr2s_set_display_window to set the window, then writes pixels continuously via CMD_WRAM(0x2C). The color is packed automatically according to the color-format macro in lcd_init.h: 2 bytes per pixel in RGB565, 3 bytes per pixel in RGB888 + 8080_16b.
x, y:start coordinatesw, h:actually used here as the window's "end coordinates", consistent with tr2s_set_display_window semanticscolor:color value; in RGB565 mode the low 16 bits are effective; macros such as WHITE/RED/BLUE can be used directly
Note: Call it with "start + end" semantics, e.g. to fill the 100×100 region (10,10)~(109,109), write tr2s_lcd_fillcolor(10, 10, 109, 109, BLUE).
6.3 Font Display
Before displaying a string, call tr2s_set_font_initdata to configure font properties. The three built-in font sizes can be mixed; all strings must be null-terminated with \0. A 100-byte temporary buffer is used internally, so a single displayed string should not exceed roughly 95 bytes.
tr2s_set_font_initdata —— Configure Font Properties
void tr2s_set_font_initdata(u16 word_distance, u16 line_distance, u8 displaymode, u16 fontcolor, u16 backgroundcolor)Corresponding command:FONT_PROPERTY_SETTING = 0x75
Configures font rendering parameters; takes effect for all subsequent tr2s_dispchar_* calls.
word_distance:horizontal spacing between characters (pixels)line_distance:vertical spacing between lines (pixels)displaymode:0 = transparent background (glyph only), 1 = opaque background (fills the glyph background with backgroundcolor)fontcolor:font color, RGB565backgroundcolor:glyph background color, RGB565; ignored when displaymode=0
tr2s_dispchar_usestandardfont_16x16 —— 16×16 Font Display
void tr2s_dispchar_usestandardfont_16x16(u16 x, u16 y, const char *word)Corresponding command:DISPLAY_16_16_FONT = 0x81
Displays a string at the specified coordinates using the controller's built-in 16×16 font.
x, y:start coordinates of the string (top-left corner)word:null-terminated string; if NULL, the function returns without drawing
tr2s_dispchar_usestandardfont_24x24 —— 24×24 Font Display
void tr2s_dispchar_usestandardfont_24x24(u16 x, u16 y, const char *word)Corresponding command:DISPLAY_24_24_FONT = 0x82
Displays a string using the controller's built-in 24×24 font. Parameter semantics are the same as the 16×16 version.
x, y:start coordinates of the string (top-left corner)word:null-terminated string; if NULL, the function returns without drawing
tr2s_dispchar_usestandardfont_32x32 —— 32×32 Font Display
void tr2s_dispchar_usestandardfont_32x32(u16 x, u16 y, const char *word)Corresponding command:DISPLAY_32_32_FONT = 0x83
Displays a string using the controller's built-in 32×32 font. Parameter semantics are the same as the 16×16 version.
x, y:start coordinates of the string (top-left corner)word:null-terminated string; if NULL, the function returns without drawing
6.4 Geometric Shape Drawing
tr2s_draw_point_line_s —— Draw a Line
void tr2s_draw_point_line_s(u16 xs, u16 ys, u16 xe, u16 ye, u8 width, u32 color)Corresponding command:DRAW_POINT_LINE = 0xB0
Draws a straight line between two points.
xs, ys:start coordinates of the linexe, ye:end coordinates of the linewidth:line width (pixels); drawn as a thick line when >1color:line color, RGB565
tr2s_draw_circle_s —— Draw a Circle
void tr2s_draw_circle_s(u16 x, u16 y, u16 r, u32 color)Corresponding command:DRAW_CIRCLE = 0xB1
Draws a circle outline (not filled).
x, y:center coordinates of the circler:radius (pixels)color:circle outline color, RGB565
tr2s_draw_rectangles_s —— Draw/Fill a Rectangle
void tr2s_draw_rectangles_s(u16 xs, u16 ys, u16 xe, u16 ye, u32 color)Corresponding command:DRAW_RECTANGLES = 0xB2
Draws/fills a rectangle.
xs, ys:top-left corner coordinates of the rectanglexe, ye:bottom-right corner coordinates of the rectanglecolor:rectangle color, RGB565
6.5 Generic Command Sending
tr2s_sendcmddatas —— Generic Command Sending
void tr2s_sendcmddatas(u8 cmd, u8 *data, u16 datalen)Generic command-sending function: sends the command cmd first, then datalen bytes of data, and finally calls writeendsign() to finish. All upper-layer APIs are implemented internally on top of this function; it can also be used directly when porting or extending.
cmd:command byte; using the command macros in section 6.7 is recommendeddata:pointer to the data bufferdatalen:number of data bytes
6.6 Color Macros (lcd_cmd.h)
The library predefines commonly used RGB565 color macros, which can be passed directly as the color parameter to the APIs above:
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0xBC40
#define BRRED 0xFC07
#define GRAY 0x8430
#define DARKBLUE 0x01CF
#define LIGHTBLUE 0x7D7C
#define GRAYBLUE 0x5458
#define LIGHTGREEN 0x841F
#define LGRAY 0xC6186.7 Low-Level Command Macros (lcd_init.h)
Upper-layer APIs communicate with the controller internally through the following command macros. To send commands directly, use tr2s_sendcmddatas from section 6.5 together with these macros:
| Macro | Value | Meaning |
|---|---|---|
| CMD_VERSION | 0x01 | Read firmware/panel version |
| CMD_IC | 0x02 | Read driver IC info |
| CMD_SELF_TEST | 0x12 | Enter/exit self-test mode |
| CMD_SOFT_RESET | 0x5A | Software reset the panel |
| CMD_SET_X | 0x2A | Set column address range |
| CMD_SET_Y | 0x2B | Set row address range |
| CMD_WRAM | 0x2C | Write pixel data to GRAM |
| CMD_CONTROL_BL | 0x20 | Backlight PWM control |
| CMD_ROTATION | 0xAD | Display rotation angle |
| FONT_PROPERTY_SETTING | 0x75 | Configure font parameters |
| DISPLAY_16_16_FONT | 0x81 | 16×16 font display |
| DISPLAY_24_24_FONT | 0x82 | 24×24 font display |
| DISPLAY_32_32_FONT | 0x83 | 32×32 font display |
| DRAW_POINT_LINE | 0xB0 | Draw a line |
| DRAW_CIRCLE | 0xB1 | Draw a circle |
| DRAW_RECTANGLES | 0xB2 | Draw/fill a rectangle |
7. Platform Porting Guide
The porting effort for this driver library is concentrated in the BSP adaptation layer between /* user_change_begin / and / user_change_end */ in each interface source file. The upper-layer APIs and the LCD_Transmit mounting logic require no changes. The 8080 parallel interfaces and QSPI are implemented on STM32 FSMC in the default reference project and serve only as examples; on other platforms they can be replaced with dedicated parallel-port controllers (EMIF / GPMC / EBI, etc.), hardware QSPI / Quad-SPI controllers, or GPIO-emulated timing, depending on peripheral resources.
7.1 Porting Steps
- Step 1: In lcd_init.h, set the target interface macro to 1 (the others to 0), and adjust WIDTH/HEIGHT, rotation, and color format as needed.
- Step 2: In interface.h, modify or comment out the STM32-related includes and the BUSY pin definition according to the target MCU; if the BUSY pin is not used, commenting out BUSYPINGROUP makes WAIT_BUSY_SIGN empty.
- Step 3: Open the corresponding interface source file (e.g. 8080_16b.c), locate the /* user_change_begin / ~ / user_change_end */ region, and replace all BSP calls inside with equivalents for the target platform.
- Step 4: Implement a millisecond-level delay function and hook it to lcd_transmit.delay.
- Step 5: Call lcd_device_init(), then use tr2s_lcd_read_version() to verify that communication succeeds.
7.2 user_change Adaptation Function List
Each interface source file defines a set of static adaptation functions between /* user_change_begin / and / user_change_end */. When porting, only replace the BSP calls inside these function bodies; the function signatures and names stay unchanged. The function signatures and descriptions are listed below by interface.
7.2.1 interface/spi.c
static void spi_gpio_init(void)Description: Initializes the SPI interface GPIOs and the SPI peripheral (including the CS / RS / BUSY control pins).
static void spi_wait_busy_sign(void)Description: Waits for the LCD controller BUSY signal to be released, ensuring the controller is idle before the next communication.
static void spi_rs_set_value(u8 value)Description: Sets the RS (DC) pin level, used to distinguish commands (0) from data (1).
static void spi_cs_set_value(u8 value)Description: Sets the CS chip-select pin level; 0 selects the controller, 1 releases it.
static void spi_writebytes(u8* byte, u32 bytelen)Description: Continuously writes bytelen bytes of data to the SPI bus.
static void spi_readbytes(u8 register_address, u8* data, u32 datalen)Description: Continuously reads datalen bytes from the specified register address into the data buffer.
static void spi_delay(u32 time)Description: Millisecond-level delay, used for power-on/reset wait timing.
7.2.2 interface/qspi.c
static void qspi_gpio_init(void)Description: Initializes the QSPI interface GPIOs and the host interface peripheral. In the default STM32 reference project this is FSMC; replace it with the actual peripheral on other platforms.
static void qspi_wait_busy_sign(void)Description: Waits for the LCD controller BUSY signal to be released.
static void qspi_set_cs_value(u8 value)Description: Sets the CS chip-select pin level.
static void qspi_send_one_line_data(u8 senddata)Description: Splits 1 byte of data bit by bit and sends it one bit at a time in single-line mode, used for QSPI command/address transmission.
static void qspi_send_four_line_data(u8* data, u32 datalen)Description: Splits the data into high/low 4 bits per byte and sends it in 4-line mode, used for QSPI data transmission.
static void qspi_read_bytes(u8* data, u32 datalen)Description: Reads bit by bit in single-line mode and assembles the bits into datalen bytes in the data buffer.
static void qspi_delay(u32 time)Description: Millisecond-level delay.
7.2.3 interface/8080_8b.c
static void _8080_8b_gpio_Init(void)Description: Initializes the 8080 8-bit parallel interface GPIOs and the host parallel-port peripheral. In the default STM32 reference project this is FSMC; replace it with the actual peripheral on other platforms.
static void _8080_8b_set_cs_value(u8 value)Description: Sets the CS chip-select pin level; 0 selects the controller, 1 releases it.
static void _8080_8b_wait_busy_sign(void)Description: Waits for the LCD controller BUSY signal to be released, ensuring the controller is idle.
static void _8080_8b_set_dc_value(u8 value)Description: Sets the DC pin level, distinguishing commands (0) from data (1).
static void _8080_8b_set_rd_value(u8 value)Description: Sets the RD read-enable pin level, used for read-timing control.
static void _8080_8b_write_cmd(u8 cmd)Description: Writes one command byte to the command address through the 8080 parallel port.
static void _8080_8b_write_data(u8* data, u32 datalen)Description: Continuously writes datalen bytes to the data address through the 8080 parallel port.
static void _8080_8b_read_bytes(u8* data, u32 datalen)Description: Continuously reads datalen bytes into the data buffer through the 8080 parallel-port read timing.
static void _8080_8b_delay(u32 time)Description: Millisecond-level delay.
7.2.4 interface/8080_16b.c
static void _8080_16b_gpio_init(void)Description: Initializes the 8080 16-bit parallel interface GPIOs and the host parallel-port peripheral. In the default STM32 reference project this is FSMC; replace it with the actual peripheral on other platforms.
static void _8080_16b_set_cs_value(u8 value)Description: Sets the CS chip-select pin level; 0 selects the controller, 1 releases it.
static void _8080_16b_wait_busy_sign(void)Description: Waits for the LCD controller BUSY signal to be released, ensuring the controller is idle.
static void _8080_16b_set_dc_value(u8 value)Description: Sets the DC pin level, distinguishing commands (0) from data (1).
static void _8080_16b_set_rd_value(u8 value)Description: Sets the RD read-enable pin level, used for read-timing control.
static void _8080_16b_write_cmd(u8 cmd)Description: Writes one command byte to the command address through the 8080 parallel port.
static void _8080_16b_write_data(u8* data, u32 datalen)Description: Packs byte data into 16-bit half-words and continuously writes them to the data address through the 8080 parallel port (odd bytes are padded).
static void _8080_16b_read_bytes(u8* data, u32 datalen)Description: Continuously reads datalen 16-bit half-words into the data buffer through the 8080 parallel-port read timing.
static void _8080_16b_delay(u32 time)Description: Millisecond-level delay.
Note: When porting, only replace the BSP calls inside the function bodies above with target-platform equivalents; the function signatures, static modifiers, and the mounting logic outside the user_change region (xxx_writecmd / xxx_transmit_init, etc.) all stay unchanged. The default reference implementations for the 8080 parallel interfaces and QSPI are based on STM32 FSMC; when migrating to other MCUs, please rewrite the corresponding adaptation layer according to the platform's peripheral resources.
7.3 Porting Example: Porting the 4-wire SPI Interface to a Platform Without the STM32 HAL
Suppose the target platform already provides my_gpio_init(), my_spi_xfer(), and my_delay_ms(); only the user_change region of spi.c needs modification:
/*************************user_change_begin*************************/
static void spi_gpio_init(void)
{
my_gpio_init();
my_spi_init(SPI_MODE_0, 8);
}
static void spi_wait_busy_sign(void) { WAIT_BUSY_SIGN }
static void spi_rs_set_value(u8 v) { my_gpio_write(RS_PIN, v); }
static void spi_cs_set_value(u8 v) { my_gpio_write(CS_PIN, v); }
static void spi_writebytes(u8* b, u32 n)
{
while (n--) my_spi_xfer(*b++);
}
static u8 spi_readbyte(void) { return my_spi_xfer(0xFF); }
static void spi_delay(u32 ms) { my_delay_ms(ms); }
/*************************user_change_end*************************/Note: Keep the functions outside the user_change region — spi_writecmd / spi_senddatas / spi_transmit_init, etc. — as they are; they already implement the protocol interfacing with the upper-layer APIs.
8. Appendix: API Quick Reference
| Category | Function | Brief description |
|---|---|---|
| System | lcd_device_init | Initialization entry |
| System | tr2s_soft_reset | Soft reset |
| System | tr2s_set_selftest_mode | Self-test mode |
| System | tr2s_set_rotation_angle | Set rotation |
| System | tr2s_set_pwm | Set backlight |
| System | tr2s_lcd_read_version | Read version/IC |
| Display | tr2s_set_display_window | Set active window |
| Display | tr2s_lcd_fillcolor | Fill region with color |
| Generic | tr2s_sendcmddatas | Generic command sending |
| Font | tr2s_set_font_initdata | Font properties |
| Font | tr2s_dispchar_usestandardfont_16x16 | 16×16 display |
| Font | tr2s_dispchar_usestandardfont_24x24 | 24×24 display |
| Font | tr2s_dispchar_usestandardfont_32x32 | 32×32 display |
| Graphics | tr2s_draw_point_line_s | Draw a line |
| Graphics | tr2s_draw_circle_s | Draw a circle |
| Graphics | tr2s_draw_rectangles_s | Draw a rectangle |