适用环境:野火启明6M5(R7FA6M5BH3CFC)+ Zephyr(D:\zephyrproject,v4.4)+ 板卡 ebf_qm6m5(BOARD_ROOT=D:/RA/RA6M5)+ 应用 app/lcd_demo。屏通过 PMOD1(J25)直插,SW1 拨到四线 SPI 模式。

1. 最终可用配置(结论速查)
引脚(PMOD1)
| CS | 1 | P301 | GPIO CS(spi_config.cs,注意 cs_is_gpio,见 §3) |
| MOSI | 2 | P203 | SPI0 MOSIA |
| D/CX | 3 | P202 | GPIO 输出(MISO 位,四线模式无回读) |
| SCK | 4 | P204 | SPI0 RSPCKA |
| INT | 7 | P905 | 触摸中断(未用,查询方式) |
| RESET | 8 | P111 | GPIO 输出,低 100ms 复位 |
| 触摸 SCL | 9 | P303 | bit-bang I2C(自研方向切换,见 §5) |
| 触摸 SDA | 10 | P302 | 同上 |
关键参数
SPI0,模式 0,8bit,15MHz(实测 1MHz~15MHz 显示均正常,非信号完整性敏感)
MADCTL = 0x28(MV=1 横屏 + BGR 位,S035 屏为 BGR 序)
COLMOD = 0x55(RGB565),INVON(1-dot 反相,B4=0x01)
初始化序列与 NXP fsl_st7796s.c(GUI Guider 生成)/ Zephyr lcd_par_s035 shield 完全一致;SLPOUT(0x11) 后必须延时 ≥120ms 再 DISPON(0x29)
像素数据高字节先发(DBI 大端;用 Zephyr 原生栈时开 CONFIG_LV_COLOR_16_SWAP=y,见 §4,本次最大的坑)
GT911:I2C 地址 0x14(INT 未受控复位时锁 0x14 而非 0x5D);坐标映射 px=ry, py=319-rx;读出的 7 字节里 data[1] 是触摸 ID,坐标从 data[2] 开始
2. 症状与根因总表
| 背光亮、全白/黑屏,软件日志全正常 | CS 恒高:spi_cs_control 缺 cs_is_gpio=true,CS 从不翻转,屏忽略所有命令 | §3 |
| 红→蓝、绿→红、蓝→绿(通道轮换) | 像素低字节先发上线;S035 四线 SPI 要求高字节先发(BE),原生栈开 CONFIG_LV_COLOR_16_SWAP | §4 |
| 文字"发花"、有彩色杂点,色块正常 | 同上——抗锯齿中间色被字节交换映射成彩色镶边,黑白大色块无感 | §4 |
| LVGL 界面只剩计数器,其余消失 | Zephyr LVGL 胶合层按 chosen 自建了一个空白 display,lv_timer_handler 把它刷到屏上覆盖了 UI | §6 |
| GT911 I2C 完全扫不到 | Zephyr gpio-i2c 在 RA6M5 上不可用(输出模式 PIDR 读回恒 0) | §5 |
| gt911 驱动 bus fault | Zephyr goodix,gt911 驱动在无 reset-gpios 时解引用空指针 | §5 |
3. 黑屏:CS 恒高(cs_is_gpio)
这版 Zephyr(v4.4)的 struct spi_cs_control 新增了 bool cs_is_gpio 字段;spi_context_cs_control() 只有在 config->cs.cs_is_gpio == true 时才翻转 CS GPIO(drivers/spi/spi_context.h、include/zephyr/drivers/spi.h)。设备树路径(SPI_CS_CONTROL_INIT)会自动置位,但手动填充 spi_config 时必须显式写上:
static struct spi_config spi_cfg = {
.frequency = 15000000,
.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8),
.cs = {
.gpio = { .port = port3, .pin = 1, .dt_flags = GPIO_ACTIVE_LOW },
.delay = 0,
.cs_is_gpio = true, /* 缺了它 CS 永远不动,且无报错 */
},
};排查手法(值得复用)
软件正常 ≠ 波形正常。RA SPI 轮询驱动(spi_renesas_ra.c,无 CONFIG_SPI_INTERRUPT 时)只等 SPTEF/SPRF 标志,即使引脚复用没生效,外设内部移位照常,传输照样"成功"返回。必须上逻辑分析仪。
降到 100kHz 再量。15MHz 的 SCK 需要 ≥30MSa/s 采样率;普通 USB 分析仪测 I2C 用的低速率档根本采不到,会误判"SCK 没起振"。
持续 0xAA 测试模式:固件里写个永不返回的循环发 0xAA,CS/SCK/MOSI 波形稳定可重复,不挑抓取时机,一次就能定位是固件问题还是探头问题。
J-Link 读不到 RA6M5 的 0x4004xxxx/0x4008xxxx 外设寄存器(全返回 0),不要用它判寄存器,只能用固件日志。
4. 颜色通道轮换 / 文字发花:像素字节序
现象:直接写已知值色带,0xF800(红)→显示蓝、0x07E0(绿)→显示红、0x001F(蓝)→显示绿,正好是 16bit 高低字节互换的结果(0xF800↔0x00F8、0x07E0↔0xE007、0x001F↔0x1F00)。
根因:S035 屏四线 SPI 要求像素高字节先发(DBI 标准大端序)。Cortex-M 内存里 RGB565 是小端存储,若把缓冲原样发上线(低字节先发),屏端组装出的像素即高低字节互换,颜色通道轮换。NXP 各工程正常的原因:RW612 走 LCDIC 硬件字节交换(nxp,swap-bytes),MCUXpresso SPI 路径按 16bit 处理,上线都是高字节先发。
修复(按使用的栈二选一):
自研驱动:RAMWR 数据阶段按 16bit 做字节交换后再发(命令为单字节不受影响)。
Zephyr 原生 display 栈:CONFIG_LV_COLOR_16_SWAP=y。LVGL 在 call_flush_cb 里会对 px_map 做 lv_draw_sw_rgb565_swap(),flush 上线即为高字节先发。注意此设置只影响 LVGL 渲染路径,绕过 LVGL 直接调 display_write() 时仍需自己保证大端。
为什么表现为"文字发花"而非明显色错:黑白大色块(0xFFFF/0x0000)字节对称,交换无感;纯色块肉眼也难察觉 R/B 互换(红位不变、绿近似对称)。文字抗锯齿的中间灰阶被交换后变成彩色镶边,肉眼看上去就是"杂点/不清楚"。同一现象此前在 RA6E1+ST7789 上也出现过,应属同类问题。
教训:
1px 棋盘格(0xFFFF/0x0000 交替)对 bit 误码和字节序都不敏感,不是好的传输验证图案。
好的诊断图案:8 条已知值色带(红/绿/蓝/白/黑/0xAAAA/0x8410/黄)——0xAAAA 的 R=68%/G=33%/B=32% 对任何通道交换/旋转都敏感,一次成像即可钉死颜色映射。
"屏在别的平台是好的"只证明屏没坏,字节序/MADCTL 这类软件配置差异照样能让同一块屏表现完全不同。
5. GT911 触摸
Zephyr gpio-i2c 在 RA6M5 上不可用:RA 的 GPIO 在输出模式下读 PIDR 恒为 0(固件实测),导致 bit-bang 读不到 SDA。解决:自研方向切换 bit-bang(touch_bb.c)——释放=配置为输入+上拉,拉低=配置为输出低。
GT911 地址是 0x14 不是 0x5D:复位时序中 INT 脚未被正确控制时 GT911 锁定 0x14。i2c scan 时两个地址都可以试试。
Zephyr goodix,gt911 驱动在无 reset-gpios 属性时会解引用空指针 bus fault;要么给全 reset/irq gpios,要么绕过自研。
读坐标注意:0x814E 起始的 7 字节中 data[0]=状态、data[1]=触摸 ID,X=data[2]|data[3]<<8、Y=data[4]|data[5]<<8(ID 字节曾导致坐标错位)。
本板映射:px=ry, py=319-rx(竖屏 320x480 原始坐标 → 横屏显示)。
6. Zephyr LVGL 胶合层的坑
CONFIG_LVGL=y 时 modules/lvgl/lvgl.c 强制要求 zephyr,display chosen(或 zephyr,displays 节点),否则编译报错。绕过 display 子系统自建驱动时,设备树里的显示节点仍要保留 enabled 给它用。
胶合层会自动创建一个 lv_display 并注册空白屏幕。应用再 lv_display_create() 自建 display 后,必须删掉胶合层那个,否则每次 lv_timer_handler() 都会把它的空白屏刷到屏上覆盖 UI——现象是"界面只剩每秒更新的计数器":
lv_display_t *glue_disp = lv_display_get_default(); /* 在 set_default 之前取 */
lv_display_set_default(disp);
if (glue_disp != NULL && glue_disp != disp) {
lv_display_delete(glue_disp);
}本版未启用 CONFIG_LV_Z_RUN_LVGL_ON_WORKQUEUE/CONFIG_LV_Z_FLUSH_THREAD,胶合层不会自己跑 timer handler,应用主循环每 10ms 调一次 lv_timer_handler() 即可。
7. 其他备忘
串口日志中文在 PowerShell 读取时显示为 ?,是读取端编码问题,非固件问题。
烧录:west flash -d build/lcd_demo -r jlink;脱手复位用 build/jlink_reset.jlink(reset/go/exit)。
构建命令(Git Bash):
cd /d/RA/RA6M5 && export ZEPHYR_BASE=/d/zephyrproject/zephyr \ ZEPHYR_SDK_INSTALL_DIR=/d/luglZephyrproject/zephyr-sdk-1.0.1/zephyr-sdk-1.0.1 \ PATH="/c/ncs/toolchains/936afb6332/opt/bin:/c/Program Files/SEGGER/JLink:$PATH" west build -b ebf_qm6m5 -d build/lcd_demo app/lcd_demo -- -DBOARD_ROOT=D:/RA/RA6M5
8. 源码位置
应用/LVGL:app/lcd_demo/src/main.c(Zephyr display 原生驱动 + LVGL 胶合层 + 触摸接入)
触摸:app/lcd_demo/src/touch_bb.c(方向切换 bit-bang GT911)
配置:app/lcd_demo/prj.conf(含 CONFIG_LV_COLOR_16_SWAP=y)
板卡:boards/ebf/ebf_qm6m5/(spi0/cs-gpios/pinctrl 定义)
overlay:app/lcd_demo/boards/ebf_qm6m5.overlay(mipi_dbi/st7796s 节点,madctl=0x28)
我要赚赏金
