1. 环境准备:从零搭建开发环境
第一次接触SPI屏幕驱动开发时,最让人头疼的就是环境搭建。我当初用树莓派调试ST7789屏幕时,花了整整两天才把环境配好。现在回想起来,其实只要抓住几个关键点就能事半功倍。
首先需要确认你的开发板支持主线Linux内核。常见的主流开发板如树莓派、香橙派、NanoPi等都可以,我这次用的是树莓派4B做演示。操作系统建议选择最新的Raspbian或Ubuntu Server版本,记得提前运行sudo apt update && sudo apt upgrade更新系统。
内核编译工具链的安装有个小技巧:不要直接安装默认版本。我推荐用sudo apt install build-essential libncurses-dev flex bison libssl-dev这条命令,它会安装最新稳定的编译工具。曾经有次因为漏装libssl-dev,导致内核模块签名失败,排查了半天才发现问题。
SPI接口的硬件连接要特别注意电平匹配。很多3.3V的屏幕直接接5V开发板会烧毁,我就因此损失过两块屏幕。安全做法是:
- 确认屏幕工作电压(通常丝印有标注)
- 使用逻辑电平转换器(如TXB0108)
- 至少连接GND、SCK、MOSI、DC、RST这五根线
验证硬件连接有个简单方法:先不接屏幕电源,只接SPI线,运行ls /dev/spidev*。如果能看到类似/dev/spidev0.0的设备节点,说明SPI控制器已就绪。这个技巧帮我省去了很多不必要的硬件调试时间。
2. 内核配置:开启FBTFT支持
主线Linux内核其实已经内置了FBTFT框架,只是默认没有开启。配置内核时我习惯用make menuconfig命令,比直接修改.config文件更直观。具体路径在:
Device Drivers -> Staging drivers -> Support for small TFT LCD display modules -> <M> FB driver for the ST7789V LCD controller有个容易踩的坑是依赖项选择。除了主驱动模块,一定要记得勾选:
- SPI support
- FB_SSD1307 support
- Sysfs filesystem support
- Debug FS support
我曾经因为漏选Debug FS支持,导致无法查看调试信息,走了不少弯路。配置完成后建议保存配置文件,我通常命名为fbtft_config,方便下次直接make oldconfig。
编译内核模块时可以用make -j$(nproc) modules加速编译过程。完成后关键的文件是:
- drivers/staging/fbtft/fbtft.ko
- drivers/staging/fbtft/fb_st7789v.ko
- drivers/staging/fbtft/fbtft_device.ko
这些模块文件需要拷贝到开发板的/lib/modules/$(uname -r)/kernel/drivers/staging/fbtft/目录。这里有个实用技巧:用make modules_install INSTALL_MOD_PATH=/path/to/rootfs可以直接安装到目标文件系统。
3. 设备树配置:硬件接口定义
现代Linux内核推荐使用设备树描述硬件。对于SPI屏幕,我们需要在设备树中明确定义:
&spi0 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&spi0_pins>; cs-gpios = <&gpio 8 1>; display@0 { compatible = "sitronix,st7789v"; reg = <0>; spi-max-frequency = <32000000>; rotate = <90>; fps = <60>; buswidth = <8>; dc-gpios = <&gpio 24 0>; reset-gpios = <&gpio 25 0>; debug = <0>; }; };这个配置有几个关键参数需要注意:
- spi-max-frequency:根据屏幕规格设置,ST7789V最高支持80MHz
- rotate:屏幕旋转角度(0/90/180/270)
- fps:帧率,太高可能导致闪屏
设备树编译后生成.dtbo文件,需要放到/boot/overlays/目录。加载时用dtoverlay st7789v命令即可。我建议先用dtc -I dtb -O dts -o /boot/overlays/st7789v.dts /boot/overlays/st7789v.dtbo反编译确认配置是否正确。
4. 驱动加载与调试
一切就绪后,按顺序加载内核模块:
sudo modprobe fbtft sudo modprobe fb_st7789v sudo modprobe fbtft_device name=st7789v busnum=0 cs=0 gpios=dc:24,reset:25 speed=32000000验证屏幕是否正常工作:
# 查看framebuffer设备 ls /dev/fb* # 测试显示 sudo apt install fbi sudo fbi -d /dev/fb1 -T 1 -noverbose -a test.png调试时如果遇到问题,可以开启详细日志:
echo 7 > /sys/module/fbtft/parameters/debug dmesg | grep fbtft常见问题解决方案:
- 屏幕白屏但背光亮:检查SPI时钟极性设置,尝试修改
mode = SPI_MODE_0为其他模式 - 显示错位:调整
rotate参数或检查set_addr_win函数实现 - 闪屏:降低SPI频率或增加
fps值
5. 进阶优化:提升显示性能
基础功能调通后,可以通过以下方式优化显示效果:
双缓冲技术: 修改内核配置开启CONFIG_FB_FBTFT_DOUBLE_BUFFER,能有效减少闪屏。需要在内核配置中添加:
CONFIG_FB_FBTFT_DOUBLE_BUFFER=y自定义Gamma校正: ST7789V的Gamma参数可以通过修改驱动代码调整:
static const s16 default_gamma[] = { 0x1F, 0x1A, 0x18, 0x0A, 0x0F, 0x06, 0x45, 0x87, 0x32, 0x0A, 0x07, 0x02, 0x07, 0x05, 0x00 };硬件加速: 对于支持DMA的板子,可以启用SPI DMA传输:
&spi0 { dmas = <&dma 8>, <&dma 9>; dma-names = "tx", "rx"; };实际测试中,启用DMA后刷新率能从30fps提升到60fps。但要注意DMA缓冲区大小限制,过大可能导致传输失败。
6. 应用开发:显示内容控制
驱动正常后,可以通过多种方式控制显示内容:
FrameBuffer直接操作:
int fd = open("/dev/fb1", O_RDWR); struct fb_var_screeninfo vinfo; ioctl(fd, FBIOGET_VSCREENINFO, &vinfo); char *buffer = mmap(NULL, vinfo.yres_virtual * vinfo.xres_virtual * 2, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); // 绘制红色矩形 for (int y = 0; y < 100; y++) { for (int x = 0; x < 100; x++) { int pos = (y + 50) * vinfo.xres_virtual + (x + 50); *((unsigned short*)(buffer + pos * 2)) = 0xF800; } }使用Python库:
import pygame pygame.init() screen = pygame.display.set_mode((240, 240)) screen.fill((255, 0, 0)) pygame.display.flip()系统级集成: 可以将副屏设置为X11的扩展显示器:
FRAMEBUFFER=/dev/fb1 startx或者在Weston等Wayland合成器中配置为额外输出。我在智能家居项目中就用这种方式实现了控制面板的副屏显示。
7. 常见问题深度排查
SPI通信失败:
- 用逻辑分析仪抓取SPI波形,确认时钟极性和相位
- 检查
/sys/class/spi_master/spi0/下的设备参数 - 尝试降低SPI频率至1MHz测试基本通信
显示色彩异常:
- 确认
buswidth参数与屏幕实际接口匹配 - 检查RGB/BGR配置,有些屏幕需要设置
.bgr = true - 重新校准Gamma值,参考屏幕规格书中的推荐值
性能瓶颈分析:
# 监控SPI总线负载 cat /sys/kernel/debug/spi/spi0.0/statistics # 查看CPU占用 top -p $(pgrep -d ',' fbtft)遇到特别棘手的问题时,我会用strace跟踪系统调用:
strace -o log.txt modprobe fb_st7789v8. 项目实战:天气信息显示屏
最后分享一个实际项目案例。我用ST7789V屏幕制作了一个桌面天气站,主要实现以下功能:
硬件组成:
- 树莓派Zero W
- ST7789V 1.3寸IPS屏幕
- BME280环境传感器
软件架构:
while True: temp, humidity, pressure = read_bme280() weather = requests.get('https://api.weather.com') # 双缓冲绘图 with framebuffer1: draw_weather(weather) draw_sensor_data(temp, humidity) # 定时刷新 time.sleep(300)性能优化技巧:
- 使用
pygame.surfarray加速图像处理 - 将静态内容预渲染为位图
- 采用差异更新策略,只刷新变化区域
这个项目完整代码已开源,包含详细的FBTFT配置说明。通过这个实战案例,你会发现SPI屏幕开发其实就像搭积木,只要掌握基本原理,就能创造出各种有趣的应用。