i.MX6ULL LCD 驱动开发实战:从引脚到时钟的完整配置

一、前言

最近在调试 i.MX6ULL 的 RGB LCD 驱动,从最基础的引脚复用开始,一步步配到时钟和 eLCDIF 寄存器。整个过程踩了不少坑,也把 IOMUXC 和 CCM 的机制搞清楚了。这篇文章把整个流程整理出来,希望能帮到同样在调试 LCD 的朋友。

二、整体流程

LCD 驱动初始化分四大步:

  • 第 1 步:引脚复用 + 电气特性(IOMUXC) ✅
  • 第 2 步:PCLK 时钟配置(CCM) ✅
  • 第 3 步:eLCDIF 寄存器配置 ⬜
  • 第 4 步:刷屏 / 图形库 ⬜

本文重点讲前两步。

三、第一步:引脚复用 + 电气特性

3.1 要配哪些引脚

RGB888 接口的引脚是固定的:

类别 引脚 数量
数据线 LCD_DATA00 ~ LCD_DATA23 24
控制线 LCD_CLK / LCD_ENABLE / LCD_HSYNC / LCD_VSYNC 4
背光 GPIO1_IO08 1

合计 29 个引脚。

3.2 怎么从原理图找到 Pad 名

看开发板原理图,左边一列是芯片 Pad 名,右边框是板级网络名:

Pad 名(芯片) 网络名(板子) 用途
LCD_DATA00 LCD1_DATA00 数据 bit0
... ... ...
LCD_DATA23 LCD1_DATA23 数据 bit23
LCD_CLK LCD1_CLK 像素时钟
LCD_ENABLE LCD1_ENABLE 数据使能 DE
LCD_HSYNC LCD1_HSYNC 水平同步
LCD_VSYNC LCD1_VSYNC 垂直同步
GPIO1_IO08 LCD_BL 背光

3.3 在头文件里找宏

在 fsl_iomuxc.h 里搜 Pad 名,找到对应功能的宏。宏名结构:

c 复制代码
IOMUXC_<Pad名>_<功能名>

比如:

c 复制代码
IOMUXC_LCD_DATA00_LCDIF_DATA00   // Pad LCD_DATA00 复用为 LCDIF_DATA00
IOMUXC_GPIO1_IO08_GPIO1_IO08     // Pad GPIO1_IO08 复用为 GPIO

宏展开后是 5 个值:

c 复制代码
#define IOMUXC_LCD_DATA00_LCDIF_DATA00   0x020E0118U, 0x0U, 0x00000000U, 0x0U, 0x020E03A4U
顺序 值 含义
1 0x020E0118 SW_MUX_CTL 地址
2 0x0U MUX_MODE(ALT 编号)
3 0x00000000 输入选择寄存器
4 0x0U 输入 daisy
5 0x020E03A4 SW_PAD_CTL 地址

3.4 引脚复用(SW_MUX_CTL)

寄存器位域:

位 名称 含义
4 SION 软件输入使能
3:0 MUX_MODE 复用模式(ALT 编号)

代码:

c 复制代码
IOMUXC_SetPinMux(IOMUXC_LCD_DATA00_LCDIF_DATA00, 0);
  • 宏里的 0x0U = MUX_MODE = 0 = ALT0
  • 第二个参数 0 = SION 位(不是 ALT)

注意:第二个参数传 0 是 SION 位,ALT 藏在宏里。

3.5 电气特性(SW_PAD_CTL)

寄存器位域:

位 名称 含义
7:6 SPEED 速度
5:3 DSE 驱动强度
12 PKE 保持器使能
13 PUE 上下拉/保持器选择
15:14 PUS 上下拉选择
0 SRE 压摆率

0xB9 的含义:

c 复制代码
0xB9 = 1011 1001b
位 名称 值 含义
7:6 SPEED 10 中等速度(100MHz)
5:3 DSE 111 最大驱动(R0/7)
0 SRE 1 快速压摆率

代码:

c 复制代码
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA00_LCDIF_DATA00, 0xB9);

3.6 背光 GPIO 配置

背光是独立 GPIO,除了 IOMUXC 还要配 GPIO 模块:

c 复制代码
// 1. 引脚复用:配成 GPIO(ALT5)
IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_GPIO1_IO08, 0);

// 2. 电气特性
IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_GPIO1_IO08, 0xB9);

// 3. 方向:输出(1=输出,0=输入)
GPIO1->GDIR |= (1 << 8);

// 4. 电平:高(背光亮)
GPIO1->DR |= (1 << 8);

GDIR 和 DR 是 GPIO 模块的寄存器:

寄存器 偏移 GPIO1 地址 作用
DR +0x00 0x0209C000 数据(电平)
GDIR +0x04 0x0209C004 方向(0=输入,1=输出)

四、第二步:PCLK 时钟配置

4.1 时钟路径

c 复制代码
24MHz 晶振
   ↓
PLL5 (PLL_VIDEO) → 744MHz
   ↓
VIDEO_DIV → 744MHz
   ↓
LCDIF1_PRE_CLK_SEL → 选 PLL5
   ↓
LCDIF1_PRED → ÷4 = 186MHz
   ↓
LCDIF1_PODF → ÷6 = 31MHz
   ↓
PCLK

4.2 PCLK 目标频率怎么算

c 复制代码
PCLK = 刷新率 × (HFP + HSPW + HBP + width) × (VFP + VSPW + VBP + height)

代入 800×480@60Hz 的参数:

c 复制代码
PCLK = 60 × (40 + 48 + 88 + 800) × (13 + 3 + 32 + 480)
     = 60 × 976 × 528
     ≈ 30.9 MHz ≈ 31MHz

4.3 PLL5 配置

PLL 公式:

c 复制代码
PLL 输出 = 参考时钟 × (DIV_SELECT + NUM/DENOM)

目标 744MHz:

c 复制代码
744MHz = 24MHz × 31

所以 DIV_SELECT = 31,NUM = 0,DENOM = 1。

代码:

c 复制代码
// 关闭小数分频
CCM_ANALOG->PLL_VIDEO_NUM = 0;
CCM_ANALOG->PLL_VIDEO_DENOM = 1;

// 选择 24MHz 参考时钟
unsigned int r = CCM_ANALOG->PLL_VIDEO;
r &= ~(3 << 19);
r |= (2 << 19);

// DIV_SELECT = 31
r &= ~(0x7F << 0);
r |= (31 << 0);
CCM_ANALOG->PLL_VIDEO = r;

// 使能 PLL
CCM_ANALOG->PLL_VIDEO |= (1 << 13);

4.4 VIDEO_DIV

c 复制代码
CCM_ANALOG->MISC2 &= ~(3 << 30);   // VIDEO_DIV = 0,分频 = 1

4.5 LCDIF 时钟树

c 复制代码
cr = CCM->CSCDR2;
r |= (2 << 15);      // LCDIF1_PRE_CLK_SEL = 2(选 PLL5)
r &= ~(7 << 12);
r |= (3 << 12);      // LCDIF1_PRED = 3(÷4)
r &= ~(7 << 9);      // LCDIF1_CLK_SEL = 0(选 PRED 后)
CCM->CSCDR2 = r;

CCM->CBCMR &= ~(7 << 23);
CCM->CBCMR |= (5 << 23);   // LCDIF1_PODF = 5(÷6)

4.6 完整计算

c 复制代码
24MHz × 31 = 744MHz     (PLL5)
744MHz / 1 = 744MHz     (VIDEO_DIV)
744MHz / 4 = 186MHz     (PRED)
186MHz / 6 = 31MHz      (PODF)

最终 PCLK = 31MHz ✅

五、踩过的坑

坑 1:HSYNC/VSYNC 宏名拼写错误

c 复制代码
IOMUXC_LCD_HSYNS_LCDIF_HSYNC   // ❌ 多了一个 S
IOMUXC_LCD_HSYNC_LCDIF_HSYNC   // ✅ 正确

坑 2:以为第二个参数是 ALT

c 复制代码
IOMUXC_SetPinMux(IOMUXC_LCD_DATA00_LCDIF_DATA00, 0);

这里的 0 是 SION 位,不是 ALT。ALT 藏在宏里。

坑 3:GDIR 的 0/1 记反

i.MX6ULL 手册明确写:

  • 0 = INPUT(输入)
  • 1 = OUTPUT(输出)

坑 4:PLL 锁定等待被注释

c 复制代码
//while ((CCM_ANALOG->PLL_VIDEO & (1 << 31)) == 0);

建议恢复,否则 PLL 没稳定就继续配置,可能出错。

相关推荐
路溪非溪7 小时前
Linux中环境变量的问题总结
linux·运维·开发语言·驱动开发
2401_862880821 天前
LCD 显示与触控屏驱动开发
驱动开发·嵌入式硬件
Doraemomo2 天前
Linux内核驱动开发——中断与定时器
linux·运维·驱动开发
@嵌入式扫地僧2 天前
ECC 编程智能体嵌入式适配实战:ESP32/RK3588 驱动开发提效 60%+ 指南
驱动开发·嵌入式开发·代码优化·ai辅助开发·编程智能体
EatFan2 天前
GitHub Trending 三连观察:AI 编码智能体进入“周边生态”竞争阶段
人工智能·驱动开发·github·mcp·superpowers·github trending·spec kit
sukalot2 天前
Windows 驱动实例分析系列:libwdi 驱动分析 - examples 篇(三)
windows·驱动开发
额额额对了2 天前
嵌入式 ADC 从入门到实战:基于 i.MX6ULL 的裸机驱动开发
驱动开发·嵌入式硬件·arm
Code Man2 天前
实现 Android 字符设备驱动
android·驱动开发·lineageos
sukalot2 天前
Windows 驱动实例分析系列:libwdi 驱动分析 - examples 篇(四)
windows·驱动开发