全志平台SPI接口LCD驱动移植实战:以GC9300/ST7789为例
1. 全志平台SPI LCD驱动移植概述
第一次在全志平台上调试SPI接口的LCD屏幕时,我对着闪烁的雪花屏发呆了整整两天。后来才发现是时钟相位配置反了——这种看似简单的细节往往就是嵌入式开发的拦路虎。全志系列芯片(如F1C100s、V3s等)在智能硬件领域应用广泛,但其SPI LCD驱动移植过程却藏着不少"坑点"。
SPI接口的LCD屏幕(如GC9300、ST7789)相比并行接口更省引脚,但时序调试也更复杂。移植的核心在于三点:硬件连接要正确、sys_config.fex配置要精准、驱动代码要适配全志的显示框架。以常见的240x320分辨率屏幕为例,GC9300和ST7789虽然指令集相似,但初始化序列和时序参数差异明显,直接套用现成驱动往往会翻车。
适合阅读本文的开发者包括:
- 正在全志平台上调试SPI LCD的嵌入式工程师
- 需要将Arduino/STM32项目迁移到全志平台的开发者
- 想学习Linux显示子系统框架的技术爱好者
2. 硬件连接与信号检测
2.1 引脚定义对照表
全志平台的SPI引脚命名可能让新手困惑。以F1C100s为例,其SPI0接口在原理图上可能标注为SPI0_CLK/SPI0_MOSI,但在实际硬件连接时,必须与LCD屏幕的对应信号严格匹配。以下是典型连接方式:
| LCD引脚 | 全志引脚 | 备注 |
|---|---|---|
| SCL | SPI0_CLK | 需加22Ω电阻防信号过冲 |
| SDA | SPI0_MOSI | 建议走线长度<10cm |
| RESET | PD10 | 硬件复位可省略软件复位代码 |
| DC | PD18 | 数据/命令选择关键信号 |
| CS | SPI0_CS0 | 片选使能后需延迟1us |
实测中发现,ST7789对CS信号的下降沿非常敏感。有次我用杜邦线连接,屏幕偶尔会出现花屏,后来改用硬连线并缩短CS走线长度后问题消失。
2.2 示波器检测要点
拿示波器测波形时,要重点关注三个参数:
- 时钟频率:sys_config.fex中设置的spi_clock可能与实际输出不符。我遇到过设置为50MHz但实际只有12MHz的情况,原因是内核时钟树配置未生效
- 信号质量:特别是长距离走线时,MOSI信号可能出现振铃。建议在信号线上串联22-100Ω电阻
- 时序关系:DC信号必须在SPI时钟有效前至少10ns稳定。用双通道探头同时抓DC和CLK信号,确保满足建立时间要求
3. sys_config.fex配置详解
3.1 关键参数对照
全志平台的显示配置集中在sys_config.fex的[lcd0_para]段。以下是GC9300和ST7789的典型配置差异:
; GC9300配置示例 [lcd0_para] lcd_if = 1 ; 1表示SPI接口 lcd_spi_mode = 3 ; CPOL=1, CPHA=1 lcd_spi_clk_div = 2 ; 时钟分频系数 lcd_dc_pin = port:PD18<1><0><default><default> lcd_pwm_used = 1 ; 背光PWM使能 ; ST7789配置示例 [lcd0_para] lcd_if = 1 lcd_spi_mode = 0 ; CPOL=0, CPHA=0 lcd_spi_clk_div = 3 ; 需要更低时钟频率 lcd_init_data = 0x11,0x36,0x00 ; 自定义初始化序列踩坑记录:有次将ST7789的spi_mode误设为3,屏幕只能显示乱码。后来发现不同厂商对SPI模式的实现有差异,必须严格按datasheet配置。
3.2 时序参数计算
屏幕时序涉及多个关键参数:
- 帧率:60Hz刷新率对应的帧周期为16.67ms
- 行时序:THP + THB + THD + THF = 320 + 10 + 240 + 10 = 580 DCLK
- SPI时钟:当DCLK=10MHz时,传输240x320x16bit数据约需122ms,远超帧周期
这意味着纯SPI传输无法满足实时刷新,需要:
- 使用全志的硬件加速功能
- 采用局部刷新策略
- 降低颜色深度到16bit(RGB565)
4. 驱动代码移植实战
4.1 驱动框架分析
全志平台的显示驱动采用分层架构:
应用层 ↓ FrameBuffer ↓ de_be (显示后端) ↓ lcd (屏驱动层) ↓ SPI控制器移植时需要重点关注:
- lcd.c中的面板初始化函数
- lcd_spi.c中的传输函数
- lcd_panel_cfg.c中的时序参数
4.2 关键代码修改
以ST7789为例,需要重写以下函数:
static void LCD_panel_init(u32 sel) { // 硬件复位 sunxi_lcd_gpio_set_value(sel, 0, 1); mdelay(100); sunxi_lcd_gpio_set_value(sel, 0, 0); mdelay(100); // 发送初始化序列 sunxi_lcd_spi_write_cmd(sel, 0x11); // Sleep Out mdelay(120); sunxi_lcd_spi_write_cmd(sel, 0x3A); // 颜色格式 sunxi_lcd_spi_write_data(sel, 0x55); // RGB565 }常见问题排查:
- 若显示颜色异常:检查颜色格式(RGB565/BGR565)
- 若显示偏移:调整GRAM起始地址寄存器(0x2A/0x2B)
- 若闪屏:检查VSYNC时序和TE信号
5. 调试技巧与性能优化
5.1 常用调试工具
- dmesg日志:关注
[DISP]标签的输出 - fbset命令:查看当前显示参数
- ioctl调试:通过FBIOGET_VSCREENINFO获取可变信息
- 逻辑分析仪:抓取SPI实际通信数据
5.2 性能优化方案
在V3s平台上实测GC9300的刷屏速度:
- 全屏刷新:原始SPI驱动约15fps
- 优化后方案:
- 启用DMA传输:提升至28fps
- 使用8线SPI模式:可达35fps
- 局部刷新策略:针对变化区域更新
关键优化代码:
// 启用DMA传输 spi->master->dma_mapped = 1; spi->master->can_dma = sunxi_spi_can_dma; // 8线SPI模式配置 writel(0x30000000, spi->base_addr + 0x04); // 设置SPI_CTL寄存器6. 不同型号屏幕的适配差异
6.1 GC9300 vs ST7789
两款常用屏的关键区别:
| 特性 | GC9300 | ST7789 |
|---|---|---|
| 初始化序列 | 需发送0xFE命令 | 需要SLPOUT延迟120ms |
| 颜色格式 | 默认BGR | 可配置RGB/BGR |
| 睡眠电流 | 0.5mA | 1.2mA |
| 最大SPI时钟 | 50MHz | 62.5MHz |
6.2 HX8357C特殊处理
这款屏幕需要注意:
- 需要先发送0xB9扩展命令
- 电源上电序列必须严格遵循时序
- 温度补偿参数需根据环境调整
移植示例:
static void HX8357C_init_sequence(u32 sel) { sunxi_lcd_spi_write_cmd(sel, 0xB9); // 扩展命令 sunxi_lcd_spi_write_data(sel, 0xFF); sunxi_lcd_spi_write_data(sel, 0x83); sunxi_lcd_spi_write_data(sel, 0x57); mdelay(150); // 必须的延迟 }7. 实战中的异常处理
遇到白屏时,按以下步骤排查:
- 测量背光电压(通常3.3V-5V)
- 检查复位信号是否正常(用示波器抓取)
- 验证SPI信号是否到达屏幕端
- 确认初始化序列中的延迟是否足够
花屏问题的常见原因:
- 内存对齐问题(确保buf地址32字节对齐)
- 颜色格式不匹配(如驱动配置RGB但屏幕期望BGR)
- SPI时钟相位错误(重新配置lcd_spi_mode)
一个真实案例:某次调试中屏幕显示错位,最终发现是GRAM地址步进值配置错误。修改0x36寄存器的MY/MX/MV参数后显示正常。这类问题最有效的调试方式是:
- 用逻辑分析仪抓取实际SPI通信数据
- 与datasheet中的示例序列逐字节对比
- 在初始化代码中添加关键日志
移植完成后,建议进行72小时老化测试,重点关注:
- 长时间运行后的显示稳定性
- 温度变化对显示效果的影响
- 快速开关机时的屏幕初始化可靠性
