Luckfox RV1103 + GC9A01 SPI LCD + Camera 实时预览:完整调试记录(2))
Luckfox RV1103 + GC9A01 SPI LCD + Camera 实时预览:完整调试记录
记录日期:2026-11-14
硬件:Luckfox Pico Plus Mini / RV1103,GC9A01 240×240 SPI 圆屏,板载/连接的 MIPI 摄像头
软件:Luckfox SDK,Linux 5.10 系列(此前现场为 5.10.160),Buildroot/uClibc,FBTFT,V4L2,RKISP
实际结果:/dev/fb0已成功注册,纯红画面成功;摄像头实时显示成功,用户观察约 20 FPS;启动 RKAIQ 3A 服务后偏暗问题有所改善。
真实性标注:本文区分【现场确认】【源码确认】【建议/待测】。未提供的真实 DTS 文件、完整内核原始版本、示波器实测 SCLK 不会被虚构。
0. 项目目标、范围与成果
目标是将 RV1103 的 MIPI Camera 采集到的图像直接显示在 1.1 英寸 GC9A01 240×240 圆形 SPI LCD 上,尽量少改代码,优先验证从 Sensor 到屏幕的整条链路。LCD 最初按 ST7789V 的 FBTFT 框架调试;后来临时将 fb_st7789v.c 的初始化寄存器序列替换为 GC9A01 序列,但保留 fb_st7789v 驱动名和 sitronix,st7789v compatible,便于快速验证。这是实验方案,不是正式产品应采用的驱动命名和设备树兼容性设计。
阶段性成果:
- 【现场确认】SPI0 被内核枚举;
spi0.0最终绑定fb_st7789v,并出现/dev/fb0。 - 【现场确认】GC9A01 能够显示红色;DTS 声明 GPIO1_D0 背光、驱动初始化后点亮背光。
- 【现场确认】V4L2 枚举到 RKISP mainpath
/dev/video11,NV12 格式可用。 - 【现场确认】
camera_fb.c运行后摄像头画面能显示到 GC9A01。 - 【现场确认】用户观察约 20 FPS,图像偏暗;启动
rkaiq_3A_server后画面改善。 - 【待测】30/40/50 MHz SPI 频率、实际屏幕刷新 FPS、SPI DMA/驱动传输效率、持续运行稳定性。
1. 系统数据通路
MIPI Camera Sensor
│ MIPI CSI-2,Bayer RAW(取决于 Sensor)
▼
Rockchip RKCIF / RKISP
│ ISP 处理:曝光/白平衡等由 RKAIQ 3A 服务协调
▼
/dev/video11 (rkisp_mainpath)
│ V4L2 VIDEO_CAPTURE_MPLANE
│ 单个内存平面的 NV12,典型请求 640×480
▼
camera_fb.c
│ VIDIOC_REQBUFS → QUERYBUF → mmap → QBUF
│ STREAMON → select → DQBUF → QBUF
│ NV12 → RGB565;中心裁切/最近邻缩放
▼
/dev/fb0 (mmap)
│ 应用逐像素写 framebuffer
▼
Linux FBTFT deferred I/O / SPI 总线写入
▼
SPI0 → GC9A01 240×240 RGB565 圆屏
重要区分:应用中的 row[x] = px 仅写 framebuffer 的一个 16-bit 像素,不等于立即发送一个 SPI 事务。内核 FBTFT 负责批量刷新。camera_fb.c 统计的是采集并处理的帧率,不保证等于实际 LCD 刷新率。
2. 硬件接线
2.1 已确认的 SPI 屏幕引脚
| GC9A01 模块信号 | RV1103 GPIO | 说明 |
|---|---|---|
| CS | GPIO1_C0 | SPI0 硬件片选 CS0 |
| SCL / SCK | GPIO1_C1 | SPI0 时钟 |
| SDA / DIN / MOSI | GPIO1_C2 | SPI0 主机输出 |
| RES / RST | GPIO1_C4 | GPIO 复位,低有效 |
| DC / A0 | GPIO1_C5 | GPIO 命令/数据选择 |
| BL / LED | GPIO1_D0 | GPIO 背光控制,高有效 |
| VCC | 按模块规格 | 不要未经核实把 5 V 接到 3.3 V 逻辑模块 |
| GND | GND | 必须共地 |
注意:这是 RV1103 的 GPIO 命名,不是 Luckfox 排针的物理脚号。实际接线必须按所用板卡的排针图核对。SPI0 的 C0/C1/C2 需要 pinmux 为 SPI 功能;C4/C5/D0 为 GPIO。背光 GPIO 如果直接驱动 LED,必须确认模块已有合适的限流/驱动电路,不能假定 SoC GPIO 可直接承担任意背光电流。
2.2 摄像头连接
摄像头走 RV1103 的 MIPI CSI 接口,不经过 SPI LCD 的这些引脚。具体 Sensor 型号、FPC 针脚、电源轨及复位脚在本次对话中未提供,故不虚构。系统已枚举 RKCIF/RKISP 节点且用户已成功显示画面,说明当前摄像头链路至少具备可用的视频采集能力。
3. 内核配置和最初排查
最初系统已具备如下配置或驱动能力:
CONFIG_FB=y
CONFIG_FB_TFT=y
CONFIG_FB_TFT_ST7789V=y
系统可看到 /sys/bus/spi/drivers/fb_st7789v,但早期 /dev/fb0 不存在。这说明驱动编译进内核不代表已经匹配到 SPI 设备并完成 Probe。
3.1 检查 SPI 控制器
ls -l /sys/class/spi_master/
ls -l /sys/bus/spi/devices/
ls -l /sys/bus/spi/drivers/
【现场历史输出】系统可看到 spi0 和 spi2;其中 spi2.0 是 spi-nand,负责存储。绝对不要为了屏幕测试去 unbind SPI2 的 NAND 设备,否则可能破坏运行时存储访问。
3.2 解决 SPI0 CS0 节点冲突
早期 spi0.0 绑定到了 spidev(compatible rockchip,spidev),而屏幕设备节点也想使用 reg = <0>。一个 SPI 控制器的同一个 CS 只能绑定一个设备实例,不能让 spidev@0 和 fbtft@0 同时启用。
操作原则:
- 在实际板级 DTS/DTSI 中启用
&spi0; - 禁用与 CS0 冲突的
spidev@0; - 在
&spi0下启用fbtft@0,reg = <0>; - 保留 SPI0 引脚复用;
- 编译烧录并观察 dmesg。
检查绑定:
readlink /sys/bus/spi/devices/spi0.0/driver
dmesg | grep -Ei 'spi0|st7789|fbtft|graphics fb'
ls -l /dev/fb*
cat /proc/fb
【现场确认】曾看到如下成功日志:
[0.160688] fb_st7789v spi0.0: fbtft_property_value: buswidth = 8
[0.160706] fb_st7789v spi0.0: fbtft_property_value: debug = 7
[0.160718] fb_st7789v spi0.0: fbtft_property_value: fps = 30
[0.487839] graphics fb0: fb_st7789v frame buffer, 240x320, 150 KiB video memory, 4 KiB buffer memory, fps=33, spi0.0 at 20 MHz
这里 240x320 是改为 GC9A01 240×240 之前的 ST7789 配置日志,不能当作最终 GC9A01 的日志。它证明 FBTFT / SPI0 / framebuffer 绑定链路当时已打通。
4. GC9A01 内核驱动改造
4.1 为什么临时复用 ST7789 驱动
GC9A01 与 ST7789 都使用 SPI 发送命令和像素数据,但初始化寄存器序列不同。FBTFT 已经提供 SPI 发送、GPIO DC/RESET、framebuffer 注册及刷新机制,因此测试阶段只替换初始化序列即可。
实际最终文件:本工程 fb_st7789v.c。它不是伪代码,而是对话中提供的实际最终版本的副本。
保持:
#define DRVNAME "fb_st7789v"
FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7789v", &display);
变更:
- 将
init_display()换成已在 ESP32 上验证过的 GC9A01 寄存器初始化序列; display.width = 240,display.height = 240;- 保留
set_var()的 MADCTL 旋转设置及blank(); - 删除原 ST7789 专属的 gamma 写入逻辑;
- 通过
devm_gpiod_get_optional()获取 DTS 背光 GPIO; 0x11Sleep Out 后等待 120 ms,再0x29Display On,随后打开背光。
4.2 初始化关键命令
par->fbtftops.reset(par);
mdelay(150);
/* 大量 GC9A01 厂商寄存器配置,完整内容见 fb_st7789v.c */
write_reg(par, 0x36, 0x08); /* MADCTL 初始值 */
write_reg(par, 0x3A, 0x05); /* RGB565 */
write_reg(par, 0x21); /* Display inversion ON */
write_reg(par, 0x11); /* Sleep Out */
mdelay(120);
write_reg(par, 0x29); /* Display On */
mdelay(20);
请勿把以上摘要替代完整寄存器表。0xEF、0xEB、0x62、0x63 等厂商命令完整保留在源码中,来自之前用户已验证的 ESP32 GC9A01 驱动初始化。
注意颜色:init_display() 写入 0x36, 0x08,而 set_var() 可能依据 bgr、rotate 再次写 MADCTL。若出现红蓝交换或旋转异常,应检查 DTS bgr、rotate 和 FBTFT 实际调用顺序,而不是随意调整 RGB565 数据。
4.3 背光 GPIO 的最终代码
#include <linux/gpio/consumer.h>
#include <linux/err.h>
static int init_display(struct fbtft_par *par)
{
struct gpio_desc *backlight;
backlight = devm_gpiod_get_optional(&par->spi->dev,
"backlight", GPIOD_OUT_LOW);
if (IS_ERR(backlight))
return PTR_ERR(backlight);
/* GC9A01 初始化 ... */
write_reg(par, 0x29);
mdelay(20);
if (backlight)
gpiod_set_value_cansleep(backlight, 1);
return 0;
}
【现场确认】用户反馈“的确可以显示红色”,说明当前临时驱动及背光方案在现场有效。
补充限制:这版背光仅在初始化后打开,没有实现 blank/unbind/suspend 时关闭背光;正式驱动应把背光资源存放在私有上下文,或使用标准 backlight 子系统,避免在重复初始化场景下再次申请同一个 GPIO。
4.4 本工程的 Patch 文件含义
0002-add-dts-backlight-control.patch 是从本次已有的 GC9A01 无背光测试版本到GC9A01 最终背光版本的真实统一差异补丁,可用于理解增加了哪些代码。
它不是对 Luckfox 原版 ST7789 驱动的完整 patch:因为本次对话没有完整保留用户 SDK 中那份原始 fb_st7789v.c 的精确版本。若要复现,直接使用本工程完整 fb_st7789v.c 替换 SDK 对应文件,或在自己 SDK 中用 git diff 生成准确的正式补丁。
5. DTS 配置
本工程包含 gc9a01-spi0-overlay-example.dts 作为板级 DTS 片段示例,不是独立可编译的完整 DTB。实际应合并进所用 Luckfox 板卡的 DTS/DTSI,并保留原有 SPI0 pinctrl。
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/rockchip.h>
&spi0 {
status = "okay";
fbtft@0 {
compatible = "sitronix,st7789v";
reg = <0>;
spi-max-frequency = <20000000>;
buswidth = <8>;
fps = <30>;
debug = <7>;
width = <240>;
height = <240>;
rotate = <0>;
bgr = <0>;
reset-gpios = <&gpio1 RK_PC4 GPIO_ACTIVE_LOW>;
dc-gpios = <&gpio1 RK_PC5 GPIO_ACTIVE_HIGH>;
backlight-gpios = <&gpio1 RK_PD0 GPIO_ACTIVE_HIGH>;
status = "okay";
};
};
DTS 的 GPIO_ACTIVE_HIGH 说明对背光而言逻辑 1 是物理高电平。驱动使用 GPIOD_OUT_LOW 初始化关闭,再用 gpiod_set_value_cansleep(..., 1) 打开。
不要同时配置 GPIO1_D0 的 gpio-hog 和 backlight-gpios,否则可能导致 GPIO 所有权冲突。
reset-gpios、dc-gpios 的实际有效电平和节点名称应优先沿用现场已工作的 DTS;上面仅为记录示例,不能证明与你 SDK 的具体 GPIO 解析路径完全一致。
5.1 SPI 频率验证
当前现场成功配置是 20 MHz。可分阶段尝试:
spi-max-frequency = <30000000>;
/* 稳定后改为 40000000,再考虑 50000000 */
RV1103 SPI Master 的 50 MHz 上限曾在前面对话引用 Rockchip/Luckfox 资料,但本次现场尚未测到 50 MHz。不要把 50 MHz 当作已经验证稳定的 GC9A01 模块频率。
检查 DT 请求值:
hexdump -C /sys/bus/spi/devices/spi0.0/of_node/spi-max-frequency
20 MHz = 01 31 2d 00;50 MHz = 02 fa f0 80,均为 DT 大端 32 位值。该属性是请求值,不是示波器测得的 SCLK。实际频率须在 GPIO1_C1 测量。
6. 编译和烧录 LCD 驱动
在 Luckfox SDK 根目录下先定位源码:
find sysdrv/source/kernel -name fb_st7789v.c
通常为:
sysdrv/source/kernel/drivers/staging/fbtft/fb_st7789v.c
操作示例:
cp sysdrv/source/kernel/drivers/staging/fbtft/fb_st7789v.c \
/tmp/fb_st7789v.c.original
cp fb_st7789v.c \
sysdrv/source/kernel/drivers/staging/fbtft/fb_st7789v.c
./build.sh kernel
./build.sh firmware
构建命令可能随 SDK 版本不同而调整。烧录方式使用你现有已经成功的固件部署流程,不在这里虚构分区或刷写地址。
重启验证:
dmesg | grep -Ei 'st7789|gc9a01|spi0|graphics fb|backlight'
ls -l /dev/fb0
cat /proc/fb
预期分辨率应为 240x240,RGB565 framebuffer 容量按像素计算为 115200 字节(约 112.5 KiB);实际内存分配、缓冲长度可能有额外开销。
6.1 简单刷红色测试
对 16-bit RGB565,纯红色像素值是 0xF800。在小端 ARM CPU 内存中连续字节为 00 f8。可在板上使用已有刷屏程序,或用下面的 Python 伪测试(仅当板上安装 Python):
with open('/dev/fb0', 'wb', buffering=0) as f:
f.write(b'\x00\xf8' * (240 * 240))
注意:这段简易测试假设 framebuffer 的实际颜色位域为 RGB565、行跨度 480 字节,且 write() 方式被 fbdev 支持;不满足时应以 FBIOGET_*SCREENINFO 查询结果为准。现场已确认红色显示成功。
7. V4L2 摄像头设备枚举
【现场输出】:
rkisp-statistics (platform: rkisp):
/dev/video19
/dev/video20
rkcif-mipi-lvds (platform:rkcif):
/dev/media0
rkcif (platform:rkcif-mipi-lvds):
/dev/video0 ... /dev/video10
rkisp_mainpath (platform:rkisp-vir0):
/dev/video11 ... /dev/video18
/dev/media1
经 v4l2-ctl --info:
/dev/video0~/dev/video10:rkcif,Video Capture Multiplanar、Streaming;/dev/video11:rkisp_mainpath,多平面采集,优先作为预览输出;/dev/video12:rkisp_selfpath,备用;/dev/video13:bypasspath;/dev/video17、/dev/video18:rawrd 输入,不适合直接预览;/dev/video19:ISP 统计;/dev/video20:ISP 参数输入。
实际命令:
v4l2-ctl --list-devices
v4l2-ctl -d /dev/video11 --list-formats-ext
v4l2-ctl -d /dev/video12 --list-formats-ext
v4l2-ctl -d /dev/video11 --get-fmt-video
7.1 ISP mainpath 支持的格式
【现场确认】/dev/video11 列出:
UYVY, NV16, NV61, NV21, NV12, NM21, NM12
尺寸范围:32x32 到 2304x1296,步进 8x8。
/dev/video12 除上述格式外,还提供 GREY、XR24、RGBP(RGB565)。这说明未来可以考虑从 selfpath 直接输出 RGB565,以减少软件 YUV 转换,但尚未在本次项目实测 selfpath RGBP 是否能正常采集、颜色/尺寸是否匹配。
7.2 当前格式的关键输出
【现场原始输出】:
Format Video Capture Multiplanar:
Width/Height : 2304/1296
Pixel Format : 'NV12' (Y/CbCr 4:2:0)
Number of planes : 1
Quantization : Full Range
Plane 0:
Bytes per Line : 2304
Size Image : 1119744
关键知识点:VIDEO_CAPTURE_MPLANE 表示 V4L2 API 使用多平面接口,但当前 NV12 的 num_planes = 1,Y 和 UV 在同一内存缓冲区内;程序必须正确设置 struct v4l2_plane,但只需映射这一块缓冲区。
7.3 采集验证命令
v4l2-ctl -d /dev/video11 \
--stream-mmap \
--stream-count=30 \
--stream-to=/tmp/camera.nv12
ls -lh /tmp/camera.nv12
扩展名 .nv12 只是文件名,实际格式仍以协商结果为准。若 STREAMON 超时,应检查 media pipeline、sensor 及 RKAIQ,而不是直接判断 LCD 故障。
8. 用户态 camera_fb.c 完整设计
本工程 camera_fb.c 是此前实际生成的最终版本(非重写示例),约 9 KB,标准 C + Linux UAPI,无 OpenCV/FFmpeg/LVGL 依赖。
8.1 参数与设备打开
./camera_fb /dev/video11 /dev/fb0 640 480
argv[1] 摄像头节点;argv[2] framebuffer;argv[3]/argv[4] 请求采集宽高。默认值就是上述参数。
vfd = open(camera, O_RDWR | O_NONBLOCK);
ioctl(vfd, VIDIOC_QUERYCAP, &cap);
查询并要求 V4L2_CAP_VIDEO_CAPTURE_MPLANE 和 V4L2_CAP_STREAMING。
8.2 格式协商
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
fmt.fmt.pix_mp.width = requested_w;
fmt.fmt.pix_mp.height = requested_h;
fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
ioctl(vfd, VIDIOC_S_FMT, &fmt);
后续以驱动返回的 width、height、bytesperline、quantization 为准。代码拒绝不符合单内存平面 NV12条件的返回值,避免误把 NV21/NM12 等格式按 NV12 解析。
8.3 framebuffer 查询与 mmap
ioctl(ffd, FBIOGET_FSCREENINFO, &fix);
ioctl(ffd, FBIOGET_VSCREENINFO, &var);
fb = mmap(NULL, fix.smem_len, PROT_READ | PROT_WRITE,
MAP_SHARED, ffd, 0);
检查 var.bits_per_pixel == 16、RGB565 通道长度 5/6/5。fix.line_length 是实际每行字节数,不能一概假定等于 240*2。
8.4 V4L2 缓冲区
VIDIOC_REQBUFS (4 buffers)
→ VIDIOC_QUERYBUF
→ mmap
→ VIDIOC_QBUF
→ VIDIOC_STREAMON
主循环:
select()
→ VIDIOC_DQBUF
→ 从 NV12 采样、中心裁切、缩放、转换为 RGB565
→ 写 framebuffer
→ VIDIOC_QBUF
退出时:
VIDIOC_STREAMOFF → munmap V4L2 buffers → munmap fb → close
8.5 NV12 的内存布局
单内存平面 NV12:
Y plane: stride × height
UV plane: stride × (height / 2)
每个像素一个 Y;每个 2×2 像素共享一对 U、V。
int Y = yp[y * stride + x];
int U = uv[(y/2) * stride + (x & ~1)] - 128;
int V = uv[(y/2) * stride + (x & ~1) + 1] - 128;
当前 nv12_pixel() 一次转换一个输出像素,返回一个 uint16_t RGB565;每帧 240×240 共调用 57600 次。它不是一次转换一整行,也不是直接发送 SPI。
源码按 V4L2 的 full-range / limited-range 标记选用不同 YUV→RGB 公式,再压缩为 RGB565。
8.6 裁切和缩放
对于请求 640×480,先从中间裁出 480×480,再用最近邻缩放到 240×240。这样不把 4:3 图像拉伸变形,但左右边缘会被裁掉。
int crop = width < height ? width : height;
int cropx = (width - crop) / 2;
int cropy = (height - crop) / 2;
for (unsigned y = 0; y < out_h; y++) {
int sy = cropy + (uint64_t)y * crop / out_h;
for (unsigned x = 0; x < out_w; x++) {
int sx = cropx + (uint64_t)x * crop / out_w;
uint16_t px = nv12_pixel(src, sx, sy, stride, height, full_range);
row[x] = px; /* 简化表示:原代码会检查 RGB/BGR 位域 */
}
}
row[x] = px 一次写一个 16-bit 像素;写满 240 个像素是一行(480 字节);240 行是一帧(115200 字节)。
8.7 当前版本的已知边界
- 只支持单内存平面的 NV12,不能直接处理 NV21、UYVY、RGBP;
- 最近邻缩放,优先低 CPU 开销而非最佳画质;
- 无 RGA 硬件加速;
- 直接写 framebuffer,不保证与 FBTFT 异步刷新同步,可能有撕裂;
- 现有程序使用
full_range判断,某些驱动的颜色范围标记可能不可靠; - 使用简单中心裁切,不处理圆屏四角之外的复杂 UI;
- 缺少每个环节的单独耗时统计;
- 源码假设 NV12 UV 起始地址为
stride * height,在当前典型布局成立;如果驱动存在额外平面对齐/偏移,需要按实际驱动布局修正。
9. Makefile 和交叉编译
参考用户指定的 Luckfox 官方 WebBee 交叉编译教程,针对 RV1103 Buildroot/uClibc,使用 SDK 中的 arm-rockchip830-linux-uclibcgnueabihf- 工具链。如果你的系统是 Ubuntu/glibc rootfs,则不能机械套用这一工具链。
本工程 Makefile 原文:
# Luckfox RV1103 Buildroot (uClibc) cross compilation
SDK_ROOT ?= $(HOME)/luckfox-pico
TOOLCHAIN_BIN ?= $(SDK_ROOT)/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin
CROSS_COMPILE ?= $(TOOLCHAIN_BIN)/arm-rockchip830-linux-uclibcgnueabihf-
CC := $(CROSS_COMPILE)gcc
TARGET := camera_fb
SRCS := camera_fb.c
CFLAGS := -O2 -std=gnu11 -Wall -Wextra
LDFLAGS :=
LDLIBS :=
.PHONY: all clean check-toolchain
all: $(TARGET)
check-toolchain:
@test -x "$(CC)" || { echo "ERROR: compiler not found: $(CC)"; echo "Set SDK_ROOT or TOOLCHAIN_BIN to your SDK path"; exit 1; }
$(TARGET): $(SRCS) | check-toolchain
$(CC) $(CFLAGS) $(SRCS) -o $@ $(LDFLAGS) $(LDLIBS)
clean:
rm -f $(TARGET)
编译:
make SDK_ROOT=$HOME/luckfox-pico
file camera_fb
如工具链路径不同:
find ~/luckfox-pico -type f -name '*rockchip830*gcc'
make TOOLCHAIN_BIN=/actual/path/to/bin
上传:
scp camera_fb root@<开发板IP>:/oem/
板上执行:
chmod +x /oem/camera_fb
/oem/camera_fb /dev/video11 /dev/fb0 640 480
本记录中的 Makefile 路径是此前工程的默认路径,不是对用户 SDK 目录结构的现场验证。可按实际安装位置覆盖变量。
10. 图像偏暗问题及 RKAIQ
【现场现象】Camera→LCD 图像能显示,但明显偏暗。
可能原因有:自动曝光 AE 未运行、Sensor 初始曝光时间过短、增益偏低、IQ 文件与 Sensor 不匹配、颜色范围转换错误、LCD 本身亮度不足等。不能仅凭“偏暗”就认定 ISP 有问题。
10.1 启动 RKAIQ 3A 服务
先检查:
ps | grep -E 'rkaiq|rkisp|rkipc'
which rkaiq_3A_server
ls /oem/usr/share/iqfiles/
若服务存在且没有其他进程控制 ISP:
rkaiq_3A_server &
sleep 3
/oem/camera_fb /dev/video11 /dev/fb0 640 480
【现场确认】用户反馈“确实好了一些,凑合可以看了”。这表明启动 RKAIQ 3A 对画面亮度有正面作用,但不代表曝光/ISP 参数已经完全正确。
10.2 软件提亮(备选,未现场应用)
若临时需要更亮,可在 nv12_pixel() 读取 Y 后加入:
Y = Y * 3 / 2 + 10;
if (Y > 255) Y = 255;
这是建议性补丁,不包含在本工程最终 camera_fb.c 中。它会放大噪声、造成高光饱和,不能替代正确曝光。
10.3 建议后续检查
- RKAIQ 启动日志是否识别正确 Sensor 和 IQ 文件;
- AE 是否在运行,曝光时间/模拟增益是否随环境变化;
- NV12 full/limited range 是否正确;
- 摄像头直接抓取原始 NV12 后在 PC 上查看,与 LCD 画面对比;
- 背光电压和模块供电是否正常。
11. 帧率与 SPI 带宽分析
【现场观察】预览约 20 FPS。当前已确认成功的 SPI 频率是 20 MHz。
240×240 RGB565 的纯像素数据:
240 × 240 × 2 = 115200 byte/frame
240 × 240 × 16 = 921600 bit/frame
在 20 MHz SPI 下,理论纯传输时间:
921600 / 20000000 = 0.04608 s = 46.08 ms
理论上限:
1 / 0.04608 ≈ 21.70 FPS
| SPI SCLK | 理论整屏数据传输时间 | 理论上限 FPS |
|---|---|---|
| 10 MHz | 92.16 ms | 10.85 |
| 20 MHz | 46.08 ms | 21.70 |
| 30 MHz | 30.72 ms | 32.55 |
| 40 MHz | 23.04 ms | 43.40 |
| 50 MHz | 18.43 ms | 54.25 |
这是理想的单线 SPI 8-bit 传输模型,未包含命令开销、CS 间隙、内核调度、刷新策略、摄像头采集/CPU 转换和驱动额外开销。表中数字不是实测。
重要纠正:camera_fb.c 打印的 preview FPS 是采集/处理循环速率;即使它约 20 FPS,也不能单独证明 LCD 的实际物理刷新就是 20 FPS。需要在 FBTFT 刷新函数或 SPI 逻辑分析仪处测量。
11.1 SPI 提速测试计划
建议按 20→30→40→50 MHz 逐级测试,每一级记录:
- LCD 是否花屏、颜色错误、间歇黑屏;
camera_fb.c的 preview FPS;- 内核 FBTFT 的实际刷新次数/耗时;
- SPI0 SCLK 实测频率;
- 连续运行 10~30 分钟稳定性。
11.2 fps DTS 参数的影响
此前日志有 fps=33,DTS 片段示例中是 fps=<30>。这些值可能限制 FBTFT 刷新调度;要注意它们不是摄像头帧率,也不是实际 SPI 传输能力。SPI 提速后如果 FPS 不变,检查 FBTFT deferred I/O 周期及是否真正刷新了每帧。
12. 常见故障及排查顺序
| 症状 | 优先检查 | 判断方法 |
|---|---|---|
没有 /dev/fb0 | 驱动是否启用、SPI0 设备绑定、compatible、spidev 冲突 | dmesg、readlink .../driver |
/dev/fb0 有但屏幕不亮 | 背光 GPIO、RESET/DC 极性、SPI pinmux、初始化表 | GPIO 电平、SCLK 波形 |
| 显示纯色正常但相机无图 | V4L2 节点、格式、media pipeline、STREAMON | v4l2-ctl |
| 图像颜色异常 | MADCTL BGR、FB RGB bitfields、NV12 色彩范围 | 红/绿/蓝测试图 |
| 图像旋转/镜像 | DTS rotate、MADCTL、Sensor 方向 | 图案方向对照 |
| 图像过暗 | RKAIQ 3A、Sensor 曝光、IQ 文件、YUV range | 启动 3A 前后对比 |
| FPS 接近 20 | SPI 20 MHz 带宽、FBTFT 刷新周期 | SCLK、内核刷新计数 |
| 提高 SPI 后花屏 | LCD 模块频率上限、线长、时序、电源完整性 | 逐级降频复测 |
| 编译器找不到 | SDK_ROOT/TOOLCHAIN_BIN 不匹配 | find ... '*rockchip830*gcc' |
| 可执行文件无法运行 | libc/ABI/动态链接器不匹配 | file、readelf -l |
13. 推荐的正式产品化方向
当前验证方案已经完成目标。后续如产品化:
- 单独建立
fb_gc9a01.c驱动,使用真实compatible,不再冒用 ST7789; - 用标准 backlight 子系统实现亮度控制、休眠/唤醒;
- 优化 FBTFT SPI 刷新与 DMA,测真实 LCD 刷新 FPS;
- 调整 RKAIQ AE/AWB/IQ 参数,解决暗画面;
- 对比
/dev/video12直接 RGB565 输出与/dev/video11NV12 转换; - 如果 SoC/SDK 的 RGA 能稳定使用,再考虑硬件缩放和色彩转换;
- 加入摄像头断流恢复、SPI 异常处理、进程守护、开机启动;
- 在显示预览稳定后再引入 LVGL 叠加文字/图形。
14. 文件清单及用途
RV1103_GC9A01_Camera_Debug/
├── DEBUG_REPORT.md # 本完整调试报告
├── fb_st7789v.c # 最终 GC9A01 + 背光完整驱动
├── fb_st7789v_gc9a01_without_backlight.c # 背光修改前的 GC9A01 版本
├── 0002-add-dts-backlight-control.patch # 两版 GC9A01 驱动的真实 diff
├── gc9a01-spi0-overlay-example.dts # 板级 DTS 示例片段
├── camera_fb.c # 最终用户态 Camera→FB 程序
└── Makefile # Buildroot/uClibc 交叉编译
复现建议顺序
- 核对 GPIO 接线、供电、SPI0 pinmux;
- 合并 DTS、禁用冲突 spidev;
- 用完整
fb_st7789v.c替换 SDK 原驱动,重新编译内核; - 确认
/dev/fb0、240×240、纯色正常; - 枚举
/dev/video11、确认 NV12; - 使用 Makefile 交叉编译
camera_fb.c; - 运行
camera_fb并确认实时画面; - 启动 RKAIQ 3A 改善曝光;
- 记录实际 FPS,最后逐级测试 SPI 提速。
15. 本次现场结果与待完成项
已完成并现场确认:
- FBTFT 成功绑定 SPI0;
- GC9A01 红色画面显示成功;
- DTS 背光 GPIO 与驱动打开背光方案有效;
/dev/video11提供 NV12,camera_fb.c实时预览成功;- 约 20 FPS 的用户侧观测;
- RKAIQ 3A 启动后画面变亮。
尚未现场确认:
- SPI 30/40/50 MHz 稳定性与真实 SCLK;
- GC9A01 实际刷新帧率及刷新函数耗时;
- RKAIQ 完整曝光参数及 Sensor IQ 匹配情况;
/dev/video12直接 RGB565 的性能;- 长时间运行、休眠/唤醒、开机自动启动。
结论:项目已成功实现 RV1103 的 MIPI Camera → RKISP → V4L2 → 用户态 NV12/RGB565 转换 → Linux framebuffer → SPI0 → GC9A01 的实时显示链路。当前采用 FBTFT + 用户态 CPU 转换的简单方案,足以作为后续 LVGL、图像处理和 SPI 显示性能优化的基础。
diff --git a/sysdrv/source/kernel/arch/arm/boot/dts/rv1103-luckfox-pico-ipc.dtsi b/sysdrv/source/kernel/arch/arm/boot/dts/rv1103-luckfox-pico-ipc.dtsi
index d7b50e115..38ab19fc4 100755
--- a/sysdrv/source/kernel/arch/arm/boot/dts/rv1103-luckfox-pico-ipc.dtsi
+++ b/sysdrv/source/kernel/arch/arm/boot/dts/rv1103-luckfox-pico-ipc.dtsi
@@ -316,21 +316,24 @@ &spi0 {
#address-cells = <1>;
#size-cells = <0>;
- spidev@0 {
- compatible = "rockchip,spidev";
- spi-max-frequency = <50000000>;
- reg = <0>;
- };
fbtft@0 {
compatible = "sitronix,st7789v";
reg = <0>;
- spi-max-frequency = <20000000>;
+ spi-max-frequency = <60000000>;
fps = <30>;
buswidth = <8>;
debug = <0x7>;
- led-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>;//BL
- dc-gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_HIGH>;//DC
- reset-gpios = <&gpio1 RK_PC3 GPIO_ACTIVE_LOW>;//RES
+
+ width = <240>;
+ height = <240>;
+
+ rotate = <0>;
+ bgr = <0>;
+ reset-gpios = <&gpio1 RK_PC4 GPIO_ACTIVE_LOW>;
+ dc-gpios = <&gpio1 RK_PC5 GPIO_ACTIVE_HIGH>;
+
+ /* GPIO1_D0:背光,高电平有效 */
+ backlight-gpios = <&gpio1 RK_PD0 GPIO_ACTIVE_HIGH>;
};
};
// I2C
diff --git a/sysdrv/source/kernel/arch/arm/boot/dts/rv1103g-luckfox-pico-mini.dts b/sysdrv/source/kernel/arch/arm/boot/dts/rv1103g-luckfox-pico-mini.dts
index 85ce5b81d..4043196e1 100755
--- a/sysdrv/source/kernel/arch/arm/boot/dts/rv1103g-luckfox-pico-mini.dts
+++ b/sysdrv/source/kernel/arch/arm/boot/dts/rv1103g-luckfox-pico-mini.dts
@@ -60,10 +60,7 @@ &usbdrd_dwc3 {
/**********SPI**********/
/* SPI0_M0 */
&spi0 {
- status = "disabled";
- spidev@0 {
- spi-max-frequency = <50000000>;
- };
+ status = "okay";
};
/**********I2C**********/
diff --git a/sysdrv/source/kernel/arch/arm/configs/luckfox_rv1106_linux_defconfig b/sysdrv/source/kernel/arch/arm/configs/luckfox_rv1106_linux_defconfig
index 203ce2997..e7b1f10a2 100755
--- a/sysdrv/source/kernel/arch/arm/configs/luckfox_rv1106_linux_defconfig
+++ b/sysdrv/source/kernel/arch/arm/configs/luckfox_rv1106_linux_defconfig
@@ -6,7 +6,6 @@ CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=14
CONFIG_CGROUPS=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
diff --git a/sysdrv/source/kernel/drivers/staging/fbtft/fb_st7789v.c b/sysdrv/source/kernel/drivers/staging/fbtft/fb_st7789v.c
index 0a2dbed9f..19795b9f2 100644
--- a/sysdrv/source/kernel/drivers/staging/fbtft/fb_st7789v.c
+++ b/sysdrv/source/kernel/drivers/staging/fbtft/fb_st7789v.c
@@ -1,270 +1,141 @@
-// SPDX-License-Identifier: GPL-2.0+
/*
- * FB driver for the ST7789V LCD Controller
- *
- * Copyright (C) 2015 Dennis Menschel
+ * GC9A01 test implementation inside the original fb_st7789v driver.
+ * Deliberately keep the driver name and OF compatible unchanged.
+ * Initialization register values ported from the user's working ESP32 GC9A01 sequence.
*/
-
-#include <linux/bitops.h>
+#include <linux/errno.h>
#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/gpio/consumer.h>
+#include <linux/err.h>
#include <video/mipi_display.h>
-
#include "fbtft.h"
#define DRVNAME "fb_st7789v"
+#define MADCTL_BGR BIT(3)
+#define MADCTL_MV BIT(5)
+#define MADCTL_MX BIT(6)
+#define MADCTL_MY BIT(7)
-#define DEFAULT_GAMMA \
- "70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25\n" \
- "70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25"
-
-#define HSD20_IPS_GAMMA \
- "D0 05 0A 09 08 05 2E 44 45 0F 17 16 2B 33\n" \
- "D0 05 0A 09 08 05 2E 43 45 0F 16 16 2B 33"
-
-#define HSD20_IPS 1
-
-/**
- * enum st7789v_command - ST7789V display controller commands
- *
- * @PORCTRL: porch setting
- * @GCTRL: gate control
- * @VCOMS: VCOM setting
- * @VDVVRHEN: VDV and VRH command enable
- * @VRHS: VRH set
- * @VDVS: VDV set
- * @VCMOFSET: VCOM offset set
- * @PWCTRL1: power control 1
- * @PVGAMCTRL: positive voltage gamma control
- * @NVGAMCTRL: negative voltage gamma control
- *
- * The command names are the same as those found in the datasheet to ease
- * looking up their semantics and usage.
- *
- * Note that the ST7789V display controller offers quite a few more commands
- * which have been omitted from this list as they are not used at the moment.
- * Furthermore, commands that are compliant with the MIPI DCS have been left
- * out as well to avoid duplicate entries.
- */
-enum st7789v_command {
- PORCTRL = 0xB2,
- GCTRL = 0xB7,
- VCOMS = 0xBB,
- VDVVRHEN = 0xC2,
- VRHS = 0xC3,
- VDVS = 0xC4,
- VCMOFSET = 0xC5,
- PWCTRL1 = 0xD0,
- PVGAMCTRL = 0xE0,
- NVGAMCTRL = 0xE1,
-};
-
-#define MADCTL_BGR BIT(3) /* bitmask for RGB/BGR order */
-#define MADCTL_MV BIT(5) /* bitmask for page/column order */
-#define MADCTL_MX BIT(6) /* bitmask for column address order */
-#define MADCTL_MY BIT(7) /* bitmask for page address order */
-
-/**
- * init_display() - initialize the display controller
- *
- * @par: FBTFT parameter object
- *
- * Most of the commands in this init function set their parameters to the
- * same default values which are already in place after the display has been
- * powered up. (The main exception to this rule is the pixel format which
- * would default to 18 instead of 16 bit per pixel.)
- * Nonetheless, this sequence can be used as a template for concrete
- * displays which usually need some adjustments.
- *
- * Return: 0 on success, < 0 if error occurred.
- */
static int init_display(struct fbtft_par *par)
{
- par->fbtftops.reset(par);
-
- /* turn off sleep mode */
- write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE);
- mdelay(120);
-
- /* set pixel format to RGB-565 */
- write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT);
- if (HSD20_IPS)
- write_reg(par, PORCTRL, 0x05, 0x05, 0x00, 0x33, 0x33);
-
- else
- write_reg(par, PORCTRL, 0x08, 0x08, 0x00, 0x22, 0x22);
-
- /*
- * VGH = 13.26V
- * VGL = -10.43V
- */
- if (HSD20_IPS)
- write_reg(par, GCTRL, 0x75);
- else
- write_reg(par, GCTRL, 0x35);
-
- /*
- * VDV and VRH register values come from command write
- * (instead of NVM)
- */
- write_reg(par, VDVVRHEN, 0x01, 0xFF);
-
- /*
- * VAP = 4.1V + (VCOM + VCOM offset + 0.5 * VDV)
- * VAN = -4.1V + (VCOM + VCOM offset + 0.5 * VDV)
- */
- if (HSD20_IPS)
- write_reg(par, VRHS, 0x13);
- else
- write_reg(par, VRHS, 0x0B);
-
- /* VDV = 0V */
- write_reg(par, VDVS, 0x20);
-
- /* VCOM = 0.9V */
- if (HSD20_IPS)
- write_reg(par, VCOMS, 0x22);
- else
- write_reg(par, VCOMS, 0x20);
-
- /* VCOM offset = 0V */
- write_reg(par, VCMOFSET, 0x20);
-
- /*
- * AVDD = 6.8V
- * AVCL = -4.8V
- * VDS = 2.3V
- */
- write_reg(par, PWCTRL1, 0xA4, 0xA1);
-
- write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
-
- if (HSD20_IPS)
- write_reg(par, MIPI_DCS_ENTER_INVERT_MODE);
-
- return 0;
+ struct gpio_desc *backlight;
+
+ /* DTS: backlight-gpios = <&gpio1 RK_PD0 GPIO_ACTIVE_HIGH>; */
+ backlight = devm_gpiod_get_optional(&par->spi->dev,
+ "backlight", GPIOD_OUT_LOW);
+ if (IS_ERR(backlight)) {
+ dev_err(&par->spi->dev,
+ "failed to request backlight GPIO: %ld\n",
+ PTR_ERR(backlight));
+ return PTR_ERR(backlight);
+ }
+
+ par->fbtftops.reset(par);
+ mdelay(150);
+
+ write_reg(par, 0xEF);
+ write_reg(par, 0xEB, 0x14);
+ write_reg(par, 0xFE);
+ write_reg(par, 0xEF);
+ write_reg(par, 0xEB, 0x14);
+ write_reg(par, 0x84, 0x40);
+ write_reg(par, 0x85, 0xFF);
+ write_reg(par, 0x86, 0xFF);
+ write_reg(par, 0x87, 0xFF);
+ write_reg(par, 0x88, 0x0A);
+ write_reg(par, 0x89, 0x21);
+ write_reg(par, 0x8A, 0x00);
+ write_reg(par, 0x8B, 0x80);
+ write_reg(par, 0x8C, 0x01);
+ write_reg(par, 0x8D, 0x01);
+ write_reg(par, 0x8E, 0xFF);
+ write_reg(par, 0x8F, 0xFF);
+ write_reg(par, 0xB6, 0x00, 0x20);
+ write_reg(par, 0x3A, 0x05);
+ write_reg(par, 0x90, 0x08, 0x08, 0x08, 0x08);
+ write_reg(par, 0xBD, 0x06);
+ write_reg(par, 0xBC, 0x00);
+ write_reg(par, 0xFF, 0x60, 0x01, 0x04);
+ write_reg(par, 0xC3, 0x13);
+ write_reg(par, 0xC4, 0x13);
+ write_reg(par, 0xC9, 0x22);
+ write_reg(par, 0xBE, 0x11);
+ write_reg(par, 0xE1, 0x10, 0x0E);
+ write_reg(par, 0xDF, 0x21, 0x0C, 0x02);
+ write_reg(par, 0xED, 0x1B, 0x0B);
+ write_reg(par, 0xAE, 0x77, 0x00, 0x00);
+ write_reg(par, 0xCD, 0x63);
+ write_reg(par, 0xE8, 0x34, 0x02, 0x00);
+ write_reg(par, 0x62, 0x18, 0x0D, 0x71, 0xED, 0x70, 0x70, 0x18, 0x0F, 0x71, 0xEF, 0x70, 0x70);
+ write_reg(par, 0x63, 0x18, 0x11, 0x71, 0xF1, 0x70, 0x70, 0x18, 0x13, 0x71, 0xF3, 0x70, 0x70);
+ write_reg(par, 0x64, 0x28, 0x29, 0xF1, 0x01, 0xF1, 0x00);
+ write_reg(par, 0x66, 0x3C, 0x00, 0xCD, 0x67, 0x45, 0x45, 0x10, 0x00, 0x00, 0x00);
+ write_reg(par, 0x67, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x54, 0x10, 0x32, 0x98);
+ write_reg(par, 0x74, 0x10, 0x85, 0x80, 0x00, 0x00, 0x4E, 0x00);
+ write_reg(par, 0x98, 0x3E, 0x07);
+ write_reg(par, 0x35, 0x00);
+ write_reg(par, 0x36, 0x08);
+ write_reg(par, 0x3A, 0x05);
+ write_reg(par, 0x21);
+ write_reg(par, 0x11);
+ mdelay(120);
+ write_reg(par, 0x29); /* Display ON */
+ mdelay(20);
+
+ /* Enable panel backlight after GC9A01 is initialized. */
+ if (backlight) {
+ gpiod_set_value_cansleep(backlight, 1);
+ dev_info(&par->spi->dev, "GC9A01 backlight enabled\n");
+ } else {
+ dev_warn(&par->spi->dev,
+ "no backlight-gpios in DT; skip backlight control\n");
+ }
+ return 0;
}
-/**
- * set_var() - apply LCD properties like rotation and BGR mode
- *
- * @par: FBTFT parameter object
- *
- * Return: 0 on success, < 0 if error occurred.
- */
static int set_var(struct fbtft_par *par)
{
- u8 madctl_par = 0;
-
- if (par->bgr)
- madctl_par |= MADCTL_BGR;
- switch (par->info->var.rotate) {
- case 0:
- break;
- case 90:
- madctl_par |= (MADCTL_MV | MADCTL_MY);
- break;
- case 180:
- madctl_par |= (MADCTL_MX | MADCTL_MY);
- break;
- case 270:
- madctl_par |= (MADCTL_MV | MADCTL_MX);
- break;
- default:
- return -EINVAL;
- }
- write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, madctl_par);
- return 0;
-}
-
-/**
- * set_gamma() - set gamma curves
- *
- * @par: FBTFT parameter object
- * @curves: gamma curves
- *
- * Before the gamma curves are applied, they are preprocessed with a bitmask
- * to ensure syntactically correct input for the display controller.
- * This implies that the curves input parameter might be changed by this
- * function and that illegal gamma values are auto-corrected and not
- * reported as errors.
- *
- * Return: 0 on success, < 0 if error occurred.
- */
-static int set_gamma(struct fbtft_par *par, u32 *curves)
-{
- int i;
- int j;
- int c; /* curve index offset */
-
- /*
- * Bitmasks for gamma curve command parameters.
- * The masks are the same for both positive and negative voltage
- * gamma curves.
- */
- static const u8 gamma_par_mask[] = {
- 0xFF, /* V63[3:0], V0[3:0]*/
- 0x3F, /* V1[5:0] */
- 0x3F, /* V2[5:0] */
- 0x1F, /* V4[4:0] */
- 0x1F, /* V6[4:0] */
- 0x3F, /* J0[1:0], V13[3:0] */
- 0x7F, /* V20[6:0] */
- 0x77, /* V36[2:0], V27[2:0] */
- 0x7F, /* V43[6:0] */
- 0x3F, /* J1[1:0], V50[3:0] */
- 0x1F, /* V57[4:0] */
- 0x1F, /* V59[4:0] */
- 0x3F, /* V61[5:0] */
- 0x3F, /* V62[5:0] */
- };
-
- for (i = 0; i < par->gamma.num_curves; i++) {
- c = i * par->gamma.num_values;
- for (j = 0; j < par->gamma.num_values; j++)
- curves[c + j] &= gamma_par_mask[j];
- write_reg(par, PVGAMCTRL + i,
- curves[c + 0], curves[c + 1], curves[c + 2],
- curves[c + 3], curves[c + 4], curves[c + 5],
- curves[c + 6], curves[c + 7], curves[c + 8],
- curves[c + 9], curves[c + 10], curves[c + 11],
- curves[c + 12], curves[c + 13]);
- }
- return 0;
+ u8 madctl = 0;
+
+ if (par->bgr)
+ madctl |= MADCTL_BGR;
+
+ switch (par->info->var.rotate) {
+ case 0:
+ break;
+ case 90:
+ madctl |= MADCTL_MV | MADCTL_MY;
+ break;
+ case 180:
+ madctl |= MADCTL_MX | MADCTL_MY;
+ break;
+ case 270:
+ madctl |= MADCTL_MV | MADCTL_MX;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, madctl);
+ return 0;
}
-/**
- * blank() - blank the display
- *
- * @par: FBTFT parameter object
- * @on: whether to enable or disable blanking the display
- *
- * Return: 0 on success, < 0 if error occurred.
- */
static int blank(struct fbtft_par *par, bool on)
{
- if (on)
- write_reg(par, MIPI_DCS_SET_DISPLAY_OFF);
- else
- write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
- return 0;
+ write_reg(par, on ? MIPI_DCS_SET_DISPLAY_OFF :
+ MIPI_DCS_SET_DISPLAY_ON);
+ return 0;
}
static struct fbtft_display display = {
- .regwidth = 8,
- .width = 240,
- .height = 320,
- .gamma_num = 2,
- .gamma_len = 14,
- .gamma = HSD20_IPS_GAMMA,
- .fbtftops = {
- .init_display = init_display,
- .set_var = set_var,
- .set_gamma = set_gamma,
- .blank = blank,
- },
+ .regwidth = 8,
+ .width = 240,
+ .height = 240,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_var = set_var,
+ .blank = blank,
+ },
};
FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7789v", &display);
@@ -274,6 +145,6 @@ MODULE_ALIAS("platform:" DRVNAME);
MODULE_ALIAS("spi:st7789v");
MODULE_ALIAS("platform:st7789v");
-MODULE_DESCRIPTION("FB driver for the ST7789V LCD Controller");
+MODULE_DESCRIPTION("FB driver for ST7789V (GC9A01 init test)");
MODULE_AUTHOR("Dennis Menschel");
MODULE_LICENSE("GPL");
更多推荐


所有评论(0)