I.MX6ULL平台SPI驱动实战:ST7789 LCD屏幕移植与设备树配置详解

张开发
2026/4/18 20:24:14 15 分钟阅读

分享文章

I.MX6ULL平台SPI驱动实战:ST7789 LCD屏幕移植与设备树配置详解
1. I.MX6ULL与ST7789 LCD屏幕的硬件适配基础I.MX6ULL作为一款广泛应用于嵌入式领域的处理器其灵活的SPI接口配置能力使其成为驱动小尺寸LCD屏幕的理想选择。ST7789控制器驱动的LCD屏幕如常见的1.3寸240x240分辨率型号因其性价比高、接口简单在物联网设备和便携式仪器中广受欢迎。这种组合在实际项目中非常实用特别是当你的开发板没有配备RGB接口屏幕时。我第一次接触这个组合是在一个智能家居中控项目里。当时需要一块能够显示简单UI的屏幕但开发板上的RGB接口已经被其他外设占用。ST7789的SPI接口只需要4根线SCLK、MOSI、DC、CS就能工作RESET和背光控制还是可选的这大大简化了硬件连接。实测下来这种方案在保证显示效果的同时对系统资源的占用也很低。硬件连接时要注意几个关键点SPI时钟线SCLK要尽量短避免信号完整性问题如果屏幕支持3.3V电平可以直接与I.MX6ULL连接否则需要电平转换背光控制如果不需要调光可以直接接3.3VRESET引脚最好保留有些屏幕在上电时需要正确的复位时序2. 设备树配置详解SPI控制器与引脚复用设备树配置是让LCD屏幕正常工作的第一步也是最容易出错的地方。在I.MX6ULL上我们需要配置两个关键部分SPI控制器节点和引脚复用pinctrl。先来看SPI控制器的配置。假设我们使用ECSPI1接口在设备树文件通常是arch/arm/boot/dts/100ask_imx6ull-14x14.dts中找到ecspi1节点。除了基本的SPI配置外ST7789需要特别注意三个GPIOecspi1 { pinctrl-names default; pinctrl-0 pinctrl_ecspi1; fsl,spi-num-chipselects 1; cs-gpios gpio4 24 GPIO_ACTIVE_LOW; dc-gpios gpio4 21 GPIO_ACTIVE_HIGH; rst-gpio gpio4 23 GPIO_ACTIVE_HIGH; status okay; spidev: st7789s0 { compatible 100ask,st7789s; spi-max-frequency 25000000; reg 0; }; };这里有几个容易踩坑的地方cs-gpios的GPIO_ACTIVE_LOW表示片选是低电平有效这个要根据屏幕规格书确认dc-gpios用于区分命令和数据必须配置正确spi-max-frequency不要超过屏幕支持的最大值25MHz对ST7789已经足够接下来是引脚复用配置。I.MX6ULL的引脚复用非常灵活但也容易配置冲突pinctrl_ecspi1: spi_st7789s { fsl,pins MX6UL_PAD_CSI_DATA04__ECSPI1_SCLK 0x000010B1 MX6UL_PAD_CSI_DATA06__ECSPI1_MOSI 0x000010B1 MX6UL_PAD_CSI_DATA07__ECSPI1_MISO 0x000010B1 MX6UL_PAD_CSI_DATA03__GPIO4_IO24 0x000010B0 MX6UL_PAD_CSI_DATA00__GPIO4_IO21 0x000010B0 MX6UL_PAD_CSI_DATA02__GPIO4_IO23 0x000010B0 ; };配置完成后建议用以下命令检查配置是否生效cat /proc/device-tree/soc/aips-bus02000000/spba-bus02000000/ecspi02008000/status cat /proc/device-tree/soc/aips-bus02000000/spba-bus02000000/ecspi02008000/st7789s0/compatible3. SPI驱动框架与ST7789驱动实现Linux内核的SPI驱动框架分为控制器驱动和设备驱动两部分。我们主要关注设备驱动也就是ST7789的驱动实现。首先需要定义spi_driver结构体这是驱动与内核的接口static struct spi_driver st7789s_driver { .probe st7789s_probe, .remove st7789s_remove, .driver { .owner THIS_MODULE, .name ST7789S_NAME, .of_match_table st7789s_of_match, }, .id_table st7789s_id, };数据发送是SPI驱动的核心功能。ST7789需要区分命令和数据这通过DC引脚实现static int st7789_write_reg(struct st7789_dev *dev, u8 reg, u8 *buf, int len) { int ret; struct spi_transfer t[2] { { .tx_buf reg, .len 1, }, { .tx_buf buf, .len len, } }; struct spi_message m; gpio_set_value(dev-dc_gpio, 0); // 命令模式 spi_message_init(m); spi_message_add_tail(t[0], m); ret spi_sync(dev-spi, m); if (buf len) { gpio_set_value(dev-dc_gpio, 1); // 数据模式 spi_message_init(m); spi_message_add_tail(t[1], m); ret spi_sync(dev-spi, m); } return ret; }在实际项目中我发现ST7789的初始化序列非常重要。不同厂商的屏幕可能有细微差别最好从供应商那里获取准确的初始化代码。一个典型的初始化序列如下static void st7789s_reginit(struct st7789_dev *dev) { st7789_write_reg(dev, ST7789_SWRESET, NULL, 0); mdelay(150); st7789_write_reg(dev, ST7789_SLPOUT, NULL, 0); mdelay(500); st7789_write_reg(dev, ST7789_COLMOD, \x05, 1); mdelay(10); // 更多初始化命令... }4. 驱动调试与性能优化技巧驱动开发中最耗时的往往是调试阶段。以下是我在实际项目中总结的几个调试技巧首先确保SPI通信基本正常# 检查SPI设备是否注册成功 ls /dev/spidev* # 使用spidev_test工具测试SPI通路 ./spidev_test -D /dev/spidev1.0 -v如果屏幕没有任何反应按以下步骤排查检查电源和背光是否正常用示波器检查SPI时钟和数据线是否有信号确认RESET时序是否正确有些屏幕需要特定的复位脉冲检查DC引脚在发送命令和数据时的电平变化性能优化方面有几个关键点使用DMA传输可以显著提高刷新率合理设置SPI时钟分频过高的频率会导致数据错误实现双缓冲机制可以减少屏幕闪烁针对ST7789的特性使用其局部刷新功能一个实用的性能优化示例是改进刷屏函数static void st7789_fb_flush(struct st7789_dev *dev, u16 *buf) { u8 x[4] {0}; // 设置刷新区域为全屏 x[0] 0; x[1] 0; x[2] (dev-width-1)8; x[3] (dev-width-1)0xff; st7789_write_reg(dev, ST7789_CASET, x, 4); x[0] 0; x[1] 0; x[2] (dev-height-1)8; x[3] (dev-height-1)0xff; st7789_write_reg(dev, ST7789_RASET, x, 4); // 启用内存写入 st7789_write_reg(dev, ST7789_RAMWR, NULL, 0); // 使用DMA传输帧缓冲 gpio_set_value(dev-dc_gpio, 1); spi_write(dev-spi, (u8 *)buf, dev-width * dev-height * 2); }在调试过程中可能会遇到屏幕显示颜色不正确的问题。这通常是因为颜色格式不匹配ST7789支持RGB565和RGB666等格式需要确保驱动和屏幕初始化设置一致。

更多文章