在工业 HMI、便携检测等场景中,“小屏大作”已成为刚需。传统方案往往存在性能不足或扩展复杂的问题,而飞凌嵌入式 OK3568-C 开发板(搭载 RK3568 四核 A55 2.0GHz 处理器)凭借原生 3 路 SPI、84 路 GPIO 及开源 Linux 5.10 SDK,让“点亮一块 SPI 屏幕”如同“喝杯咖啡般轻松便捷”。本文以 1.8 英寸 ST7735S 彩屏为例,手把手带您从 0 到 1 完成适配,全程仅需 15 分钟。

图:飞凌嵌入式RK3568核心板
1. 硬件准备
2. 引脚连接
3. 设备树配置
4. 驱动开发
5. 编译测试
处理器性能
RK3568 四核 Cortex-A55 架构,搭配 Mali-G52-2EE GPU,1TOPS NPU,主频高达 2.0GHz
显示接口
支持 RGB、LVDS、MIPI DSI、HDMI、eDP,并可扩展软件 SPI/QSPI 屏幕
外设接口
3 路 SPI(最高速率 50MHz)、6 路 UART、2 路 CAN、2 路千兆以太网、PCIe 3.0
系统支持
Linux4.19/5.10、Android11、Ubuntu20.04/22.04、Debian11、OpenHarmony4.1等
可靠性认证
通过 CE/FCC/ROHS 认证,工业级宽温设计(-40℃~+85℃)

图1:1.8英寸ST7735S RGB TFT LCD屏幕接口引脚定义
屏幕引脚与 OK3568 的连接关系需严格对应,确保 SPI 通信与 GPIO 控制正常,连接表如下:
屏幕引脚 | 连接目标(OK3568) | 功能说明 | 注意事项 |
|---|---|---|---|
VCC | 3.3V 电源 | 为屏幕提供工作电压 | 必须接3.3V,不可接5V,避免烧毁屏幕 |
GND | GND | 电源共地,确保电压稳定性 | 必须可靠接地,否则可能出现显示异常 |
BL | 3.3V 电源 | 屏幕背光控制 | 软件未配置时直接接3.3V实现背光常亮 |
CS | spi0_cs0 | SPI0 片选0引脚 | 低电平时选中当前SPI从设备 |
DC | GPIO3_A2 | 数据/命令控制引脚 | 高电平传输数据,低电平传输命令 |
RES | GPIO3_B3 | 屏幕复位引脚 | 上电后需拉低复位,复位完成后拉高 |
SCL | spi0_clk | SPI0 时钟引脚 | 提供SPI同步通信时钟,最高50MHz |
SDA | spi0_mosi | SPI0 主发从收引脚 | 传输SPI命令与显示数据 |
重要操作提醒:
设备树用于向内核描述 SPI0 与屏幕的硬件资源,需在 OK3568 设备树中添加以下配置:
&spi0 {
pinctrl-names = "default", "high_speed";
pinctrl-0 = <&spi0m1_cs0 &spi0m1_pins>;
pinctrl-1 = <&spi0m1_cs0 &spi0m1_pins_hs>;
status = "okay";
spi@0 {
compatible = "sitronix,st7735r";
reg = <0>;
dc-gpios = <&gpio3 RK_PA2 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_HIGH>;
spi-max-frequency = <50000000>;
rotation = <0>;
};
}
配置关键说明:
需开启内核 Framebuffer 相关配置,并添加 ST7735S 驱动代码,实现屏幕初始化与显示控制。推荐使用内核自带的 FB_TFT 框架,无需从零开发驱动。
通过make menuconfig进入内核配置界面,开启以下选项(路径:Device Drivers → Graphics support → Frame buffer Devices):
配置注意事项:
以下是基于 Framebuffer 框架的 ST7735S 完整驱动代码,可直接放入内核源码目录drivers/video/fbdev/fbtft/下,或使用内核自带驱动(Linux 5.10 已内置该驱动):
// SPDX-License-Identifier: GPL-2.0+
/*
* FB driver for the ST7735R LCD Controller
*
* Copyright (C) 2013 Noralf Tronnes
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <video/mipi_display.h>
#include "fbtft.h"
#define DRVNAME "fb_st7735r"
#define DEFAULT_GAMMA "0F 1A 0F 18 2F 28 20 22 1F 1B 23 37 00 07 02 10\n" \
"0F 1B 0F 17 33 2C 29 2E 30 30 39 3F 00 07 03 10"
static const s16 default_init_sequence[] = {
-1, MIPI_DCS_SOFT_RESET, // 发送软复位命令
-2, 10, // 延迟 10 毫秒
-1, MIPI_DCS_EXIT_SLEEP_MODE, // 退出睡眠模式
-2, 120, // 延迟 120 毫秒
-1, 0x11, // 发送命令 0x11
-2, 120, // 延迟 120 毫秒
-1, 0xB1, 0x01, 0x2C, 0x2D, // 设置帧率控制参数
-1, 0xB2, 0x01, 0x2C, 0x2D, // 设置空闲模式帧率控制参数
-1, 0xB3, 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D, // 设置部分模式帧率控制
-1, 0xB4, 0x07, // 设置反转模式为“无反转”
-1, 0xC0, 0xA2, 0x02, 0x84, // 设置电源控制参数
-1, 0xC1, 0xC5, // 设置 VGH25、VGSEL 等电源控制参数
-1, 0xC2, 0x0A, 0x00, // 设置电源控制参数
-1, 0xC3, 0x8A, 0x2A, // 设置电源控制参数
-1, 0xC4, 0x8A, 0xEE, // 设置电源控制参数
-1, 0xC5, 0x0E, // 设置电源控制参数
-1, 0x36, 0xC0, // 设置显示方向
-1, 0xE0, 0x0F, 0x1A, 0x0F, 0x18, 0x2F, 0x28, 0x20, 0x22, 0x1F, 0x1B, 0x23, 0x37, 0x00, 0x07, 0x02, 0x10, // 设置 Gamma 调整
-1, 0xE1, 0x0F, 0x1B, 0x0F, 0x17, 0x33, 0x2C, 0x29, 0x2E, 0x30, 0x30, 0x39, 0x3F, 0x00, 0x07, 0x03, 0x10, // 设置 Gamma 调整
-1, 0x2A, 0x00, 0x02, 0x00, 0x82, // 设置列地址范围
-1, 0x2B, 0x00, 0x03, 0x00, 0x83, // 设置行地址范围
-1, 0xF0, 0x01, // 设置一些特殊参数
-1, 0xF6, 0x00, // 设置一些特殊参数
-1, 0x2A, 0x00, 0x02, 0x00, 0x82, // 设置列地址范围
-1, 0x2B, 0x00, 0x01, 0x00, 0xa1, // 设置行地址范围
-1, 0x3A, 0x05, // 设置像素格式
-1, 0x29, // 打开显示
-3 // 结束标记
};
static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
{
printk("set_addr_win:%d,%d,%d,%d\r\n",xs,ys,xe,ye);
xs=2;xe=127+2;ys=1;ye=159+1;
write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS,
xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF);
write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS,
ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF);
write_reg(par, MIPI_DCS_WRITE_MEMORY_START);
}
#define MY BIT(7)
#define MX BIT(6)
#define MV BIT(5)
static int set_var(struct fbtft_par *par)
{
/* MADCTL - Memory data access control
* RGB/BGR:
* 1. Mode selection pin SRGB
* RGB H/W pin for color filter setting: 0=RGB, 1=BGR
* 2. MADCTL RGB bit
* RGB-BGR ORDER color filter panel: 0=RGB, 1=BGR
*/
switch (par->info->var.rotate) {
case 0:
write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
MX | MY | (par->bgr << 3));
break;
case 270:
write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
MY | MV | (par->bgr << 3));
break;
case 180:
write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
par->bgr << 3);
break;
case 90:
write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
MX | MV | (par->bgr << 3));
break;
}
return 0;
}
/*
* Gamma string format:
* VRF0P VOS0P PK0P PK1P PK2P PK3P PK4P PK5P PK6P PK7P PK8P PK9P SELV0P SELV1P SELV62P SELV63P
* VRF0N VOS0N PK0N PK1N PK2N PK3N PK4N PK5N PK6N PK7N PK8N PK9N SELV0N SELV1N SELV62N SELV63N
*/
#define CURVE(num, idx) curves[(num) * par->gamma.num_values + (idx)]
static int set_gamma(struct fbtft_par *par, u32 *curves)
{
int i, j;
/* apply mask */
for (i = 0; i < par->gamma.num_curves; i++)
for (j = 0; j < par->gamma.num_values; j++)
CURVE(i, j) &= 0x3f;
for (i = 0; i < par->gamma.num_curves; i++)
write_reg(par, 0xE0 + i,
CURVE(i, 0), CURVE(i, 1),
CURVE(i, 2), CURVE(i, 3),
CURVE(i, 4), CURVE(i, 5),
CURVE(i, 6), CURVE(i, 7),
CURVE(i, 8), CURVE(i, 9),
CURVE(i, 10), CURVE(i, 11),
CURVE(i, 12), CURVE(i, 13),
CURVE(i, 14), CURVE(i, 15));
return 0;
}
#undef CURVE
static struct fbtft_display display = {
.regwidth = 8,
.buswidth = 8,
.width = 128,
.height = 160,
.bpp = 16,
.init_sequence = default_init_sequence,
.gamma_num = 2,
.gamma_len = 16,
.gamma = DEFAULT_GAMMA,
.fbtftops = {
.set_addr_win = set_addr_win,
.set_var = set_var,
.set_gamma = set_gamma,
},
};
FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7735r", &display);
MODULE_ALIAS("spi:" DRVNAME);
MODULE_ALIAS("platform:" DRVNAME);
MODULE_ALIAS("spi:st7735r");
MODULE_ALIAS("platform:st7735r");
MODULE_DESCRIPTION("FB driver for the ST7735R LCD Controller");
MODULE_AUTHOR("Noralf Tronnes");
MODULE_LICENSE("GPL");
驱动代码说明:
用于验证屏幕显示功能,通过操作 Framebuffer 设备填充指定颜色。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <string.h>
#include <stdint.h>
int main(int argc, char *argv[]) {
char *endptr;
uint16_t color = 0xFFFF; // Default color (white)
long int num = strtol(argv[1], &endptr, 10); // Number of rows to fill
// Check if arguments are passed correctly
if (argc < 3) {
printf("Usage: %s <num_rows> <color>\n", argv[0]);
return 1;
}
// Parse color based on argv[2]
if (strcmp(argv[2], "red") == 0) {
color = 0xF800; // Red: 11111 000000 00000
} else if (strcmp(argv[2], "green") == 0) {
color = 0x07E0; // Green: 00000 111111 00000
} else if (strcmp(argv[2], "blue") == 0) {
color = 0x001F; // Blue: 00000 000000 11111
} else if (strcmp(argv[2], "white") == 0) {
color = 0xFFFF; // White: 111111 111111 11111
} else if (strcmp(argv[2], "black") == 0) {
color = 0x0000; // Black: 00000 000000 00000
} else {
printf("Unknown color: %s. Defaulting to white.\n", argv[2]);
}
int fb = open("/dev/fb0", O_RDWR);
if (fb == -1) {
perror("Error opening framebuffer device");
return 1;
}
// 获取屏幕的属性
struct fb_var_screeninfo vinfo;
if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo)) {
perror("Error reading variable information");
close(fb);
return 1;
}
int width = vinfo.xres;
int height = vinfo.yres;
int bpp = vinfo.bits_per_pixel; // 每像素的字节数
printf("Screen resolution: %dx%d\n", width, height);
printf("Color depth: %d bpp\n", bpp);
// 映射帧缓冲内存
size_t framebuffer_size = width * height * 2;
uint16_t *framebuffer = mmap(NULL, framebuffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
if (framebuffer == MAP_FAILED) {
perror("Error mapping framebuffer memory");
close(fb);
return 1;
}
// 填充背景颜色
for (int y = 0; y < num; y++) {
framebuffer[y] = color;
}
// 取消映射并关闭文件
munmap(framebuffer, framebuffer_size);
close(fb);
return 0;
}
完成设备树配置和驱动开发后,需要编译内核、设备树,并烧录到 OK3568 开发板中。
推荐使用 TF 卡烧录或 USB 烧录工具(如 RKDevTool),以下以 TF 卡烧录为例:
烧录注意事项:
系统启动后,可通过以下方法验证屏幕是否正常工作:
使用以下命令测试屏幕显示功能:
问题1:屏幕无显示,背光不亮
问题2:屏幕显示花屏、乱码
问题3:显示颜色异常(如偏色、反色)
问题4:驱动加载失败
排查技巧:遇到问题时,首先查看内核日志(dmesg),根据日志中的错误信息定位问题。重点关注 SPI 总线初始化、GPIO 配置、驱动匹配、命令执行等相关日志。
本文详细介绍了 OK3568 开发板适配 1.8 英寸 ST7735S SPI 屏幕的完整流程,包括硬件连接、设备树配置、内核驱动开发、编译烧录和测试验证等环节。通过本文的教程,您可以快速实现 ST7735S 屏幕的点亮与显示控制。
关键要点总结:
通过本教程的适配方案,您可以在 OK3568 开发板上快速集成 ST7735S 屏幕,为工业控制、便携设备等场景提供低成本的显示解决方案。如需进一步扩展功能(如触摸控制、背光调节等),可在此基础上进行二次开发。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。