LV10-01-LCD驱动-03-LCD控制器
接下来了解一下imx6ull中的lcd控制器——eLCDIF?若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
PC端开发环境 | Windows | Windows11 |
Ubuntu | Ubuntu20.04.2的64位版本 | |
VMware® Workstation 17 Pro | 17.6.0 build-24238078 | |
终端软件 | MobaXterm(Professional Edition v23.0 Build 5042 (license)) | |
Win32DiskImager | Win32DiskImager v1.0 | |
Linux开发板环境 | Linux开发板 | 正点原子 i.MX6ULL Linux 阿尔法开发板 |
uboot | NXP官方提供的uboot,使用的uboot版本为U-Boot 2019.04 | |
linux内核 | linux-4.19.71(NXP官方提供) |
点击查看本文参考资料
分类 | 网址 | 说明 |
官方网站 | https://www.arm.com/ | ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档 |
https://www.nxp.com.cn/ | NXP官方网站 | |
https://www.nxpic.org.cn/ | NXP 官方社区 | |
https://u-boot.readthedocs.io/en/latest/ | u-boot官网 | |
https://www.kernel.org/ | linux内核官网 |
点击查看相关文件下载
分类 | 网址 | 说明 |
NXP | https://github.com/nxp-imx | NXP imx开发资源GitHub组织,里边会有u-boot和linux内核的仓库 |
nxp-imx/linux-imx/releases/tag/v4.19.71 | NXP linux内核仓库tags中的v4.19.71 | |
nxp-imx/uboot-imx/releases/tag/rel_imx_4.19.35_1.1.0 | NXP u-boot仓库tags中的rel_imx_4.19.35_1.1.0 | |
I.MX6ULL | i.MX 6ULL Applications Processors for Industrial Products | I.MX6ULL 芯片手册(datasheet,可以在线查看) |
i.MX 6ULL Applications ProcessorReference Manual | I.MX6ULL 参考手册(下载后才能查看,需要登录NXP官网) | |
Source Code | https://elixir.bootlin.com/linux/latest/source | linux kernel源码 |
kernel/git/stable/linux.git - Linux kernel stable tree | linux kernel源码(官网,tag 4.19.71) | |
https://elixir.bootlin.com/u-boot/latest/source | uboot源码 |
一、eLCDIF——液晶控制器
1. eLCDIF简介
IMX6U系列芯片内部自带一个增强型液晶接口外设eLCDIF(Enhanced LCD Interface),配合使用DDR作为显存, 可直接控制液晶面板,无需额外增加液晶控制器芯片。
IMX6U的eLCDIF液晶控制器最高支持1366x768分辨率的屏幕; 可支持多种颜色格式,包括RGB888、RGB565、ARGB8888等(其中的“A”是指透明像素)。 还可配合像素渲染流水线PXP(Pixel Pipeline)进行复杂的图像处理,如格式转换、缩放、翻转以及图层混合等操作, 使IMX6U有非常出色的图形显示性能。特性如下:
①、支持DOTCLK模式,也就是 RGB LCD 的 DE 模式。
②、支持 VSYNC 模式以实现高速数据传输,跟MPU模式类似,多了VSYNC信号。针对高速数据传输(行场信号)。
③、支持MPU模式:有些显示屏自带显存,只需要把命令、数据发送给显示屏即可;就是前面讲的8080接口
④、支持 ITU-R BT.656 格式的 4:2:2 的 YCbCr 数字视频,并且将其转换为模拟 TV 信号。
⑤、支持 8/16/18/24/32 位 LCD,取决于IO的复用设置及寄存器配置。
2. 支持多种接口?
eLCDIF 支持三种接口: MPU 接口、 VSYNC 接口和 DOTCLK 接口。
2.1 MPU 接口
MPU 接口用于在 I.MX6U 和 LCD 屏幕直接传输数据和命令,这个接口用于 6080/8080 接口的 LCD 屏幕,比如我们学习 STM32 的时候常用到的 MCU 屏幕。如果寄存器 LCDIF_CTRL的位 DOTCLK_MODE、 DVI_MODE 和 VSYNC_MODE 都为 0 的话就表示 LCDIF 工作在 MPU接口模式。
关于 MPU 接口的详细信息以及时序参考《I.MX6ULL 参考手册》第 2150 页的“34.4.6 MPU Interface”小节.
2.2 VSYNC 接口
VSYNC 接口时序和 MPU 接口时序基本一样,只是多了 VSYNC 信号来作为帧同步,当LCDIF_CTRL 的位 VSYNC_MODE 为 1 的时候此接口使能。
关于 VSYNC 接口的详细信息可以参考《I.MX6ULL 参考手册》第 2152 页的“34.4.7 VSYNC Interface”小节 。
2.3 DOTCLK 接口
DOTCLK 接口就是用来连接 RGB LCD 接口屏幕的, 它包括 VSYNC、 HSYNC、 DOTCLK和 ENABLE(可选的)这四个信号,这样的接口通常被称为 RGB 接口。
可以看《I.MX6ULL 参考手册》——34.4.8 DOTCLK Interface
3. 框图解析

3.1 通讯引脚
上图的标号 1 处表示eLCDIF的通讯引脚,eLCDIF的通讯引脚与液晶显示面板控制信号一一对应, 包含有HSYNC、VSYNC、DE、CLK以及RGB数据线各8根。设计硬件时把液晶面板与IMX6对应的这些引脚连接起来即可, 查阅《I.MX6ULL 参考手册》——Table 34-5. Pin use in DOTCLK Mode ,可获知eLCDIF信号线对应的引脚,具体见下表。
3.2 总线接口
eLCDIF的液晶接口有两个总线接口,System Bus总线,用于向eLCDIF液晶接口的FIFO中写入数据。 而Control Bus用于设置eLCDIF用于读、写控制寄存器以及DMA、数据寄存器等等。
3.3 液晶接口(LCD Interface)
上图的标号处表示eLCDIF的液晶接口(LCD Interface),它是eLCDIF外设的主要功能部件,受控制总线(Control Bus)的寄存器控制, 从系统总线(System Bus)获得输入像素数据,经过一系列转换后通过eLCDIF的通讯引脚发送至外接的液晶面板。
其中控制总线的寄存器可以配置显存地址、输入像素数据的格式、输出的数据信号线宽度、 各个控制信号的有效极性以及控制时序中的VSW、VBP等参数,还能配置使用DMA传输。
使用寄存器初始化好eLCDIF的后,它会从“LFIFO”和“TXFIFO”中获取数据进行转换处理(格式转换、移位等操作)并传输出去。 当FIFO中的数据量低于一定程度时,它会向系统总线(SystemBus)发起请求,系统总线会把显存地址的数据搬运至FIFO中。 FIFO还可以配置阈值,低于该阈值时系统总线会提高获取数据的优先级。
eLCDIF正常运行后,数据从显存到液晶屏全程不需要内核的干预,程序控制时我们只要把像素数据写入到显存即可。
3.4 驱动时钟
elcdf模块包含两个时钟信号,分别是BUS CLOCK(apb_clk)和DISPLAY CLOCK(pix_clk)。
3.4.1 BUS CLOCK(apb_clk)
这个BUS CLOCK(apb_clk)就是指eLCDIF外设的 根时钟LCDIF_CLK_ROOT,它给eLCDIF提供驱动的时钟源,在时钟树中的结构具体如下图所示。

LCDIF_CLK_ROOT根时钟可以选择多种输入时钟源,首先是时钟源预选择器(Pre-multiplexer)支持使用如下时钟:
- PLL2:System PLL,该时钟频率通常为528MHz。
- PLL2 PFD0:该时钟常规配置为352MHz。
- PLL2 PFD1:该时钟常规配置为594MHz。
- PLL3 PFD3:该时钟常规配置为454.74MHz。
- PLL3 PFD1:该时钟常规配置为664.62MHz。
- PLL5:Video PLL,该时钟常规配置为649.52MHz。
预选择器得到的时钟,可根据需要进行分频配置,分频后输入到时钟源选择器(multiplexer)作为LCDIF_CLK_ROOT默认的时钟源, 除此之外,图中的时钟的选择器还包含其它可选的输入时钟:ipp_di0_clk、ipp_di1_clk、ldb_di0_clk、ldb_di1_clk, 不过关于这些时钟在参考手册中并没有介绍,而且在寄存器中并没有这些时钟源的分频、选择的配置, 也许该选择器是兼容其它设备而保留的内容,所以使用时我们直接选择预选择器得到的时钟作为LCDIF_CLK_ROOT的输入时钟源即可。
3.4.2 DISPLAY CLOCK(pix_clk)
这个DISPLAY CLOCK(pix_clk)是指eLCDIF与液晶面板接口的 像素时钟LCDIF_pix_clk,它的时钟频率与根时钟LCDIF_CLK_ROOT一致,不过它们 的时钟开关是分开的,其中 LCDIF_CLK_ROOT 使用寄存器位CCM_CCGR2[CG14] 控制,而LCDIF_pix_clk使用寄存器位CCM_CCGR3[CG5]控制。
4. 数据传输与处理
这里就简单了解下吧,看看手册中的框图。
- 《I.MX6ULL 参考手册》——34.4.2 Write Data Path

- 《I.MX6ULL 参考手册》——34.4.3 Read Data Path

二、eLCDIF寄存器
查看任何芯片的LCD控制器寄存器时,记住几个要点:
① 怎么把LCD的信息告诉LCD控制器:即分辨率、行列时序、像素时钟等;
② 怎么把显存地址、像素格式告诉LCD控制器。
对于i.MX6ULL来说,我们可以看《I.MX6ULL参考手册》——34.6 eLCDIF Memory Map/Register Definition

1. LCDIF_CTRLn
eLCDIF General Control Register (LCDIF_CTRLn):

位域 | 名称 | 读写 | 描述 |
[31] | SFTRST | R/W | 软件复位,正常工作时应设为0;如果设为1,它会复位整个LCD控制器 |
[30] | CLKGATE | R/W | 时钟开关, 0:正常工作时要设置为0; 1:关闭LCD控制器时钟 |
[29] | YCBCR422_INPUT | R/W | 使用RGB接口时,设置为0;其他接口我们暂时不关心 |
[28] | READ_WRITEB | R/W | 使用RGB接口时,设置为0;其他接口我们暂时不关心 |
[27] | WAIT_FOR_VSYNC_EDGE | R/W | 在VSYNC模式时,设置为1;我们不关心 |
[26] | DATA_SHIFT_DIR | R/W | 在DVI模式下才需要设置,我们不关心 |
[25:21] | SHIFT_NUM_BITS | R/W | 在DVI模式下才需要设置,我们不关心 |
[20] | DVI_MODE | R/W | 设置为1时,使用DVI模式,就是ITU-R BT.656数字接口 |
[19] | BYPASS_COUNT | R/W | DOTCLK和DVI模式下需要设置为1;MPU、VSYNC模式时设为0 |
[18] | VSYNC_MODE | R/W | 使用VSYNC模式时,设置为1 |
[17] | DOTCLK_MODE | R/W | 使用DOTCLK模式时,设置为1;本实验用的就是这个模式 |
[16] | DATA_SELECT | R/W | MPU模式下才用到,我们不关心 |
[15:14] | INPUT_DATA_SWIZZLE | R/W | 显存中像素颜色的数据转给LCD控制器时,字节位置是否交换: 0x0:NO_SWAP,不交换; 0x0:LITTLE_ENDIAN,小字节序,跟NO_SWAP一样; 0x1:BIG_ENDIAN_SWAP,字节0、3交换;字节1、2交换; 0x1:SWAP_ALL_BYTES,字节0、3交换;字节1、2交换; 0x2:HWD_SWAP,半字交换,即0x12345678转为0x56781234 0x3:HWD_BYTE_SWAP,在每个半字内部放换字节, 即0x12345678转换为0x34127856 |
[13:12] | CSC_DATA_SWIZZLE | R/W | 显存中的数据被传入LCD控制器内部并被转换为24BPP后,在它被转给LCD接口之前,字节位置是否交换: 0x0:NO_SWAP,不交换; 0x0:LITTLE_ENDIAN,小字节序,跟NO_SWAP一样; 0x1:BIG_ENDIAN_SWAP,字节0、3交换;字节1、2交换; 0x1:SWAP_ALL_BYTES,字节0、3交换;字节1、2交换; 0x2:HWD_SWAP,半字交换,即0x12345678转为0x56781234 0x3:HWD_BYTE_SWAP,在每个半字内部放换字节, 即0x12345678转换为0x34127856 |
[11:10] | LCD_DATABUS_WIDTH | R/W | LCD数据总线宽度,就是对外输出的LCD数据的位宽, 0x0:16位; 0x1:8位; 0x2:18位; 0x3:24位 |
[9:8] | WORD_LENGTH | R/W | 输入的数据格式,即显存中每个像素占多少位, 0x0:16位; 0x1:8位; 0x2:18位; 0x3:24位 |
[7] | RGB_TO_YCBCR422_CSC | R/W | 设置为1时,使能颜色空间转换:RGB转为YCbCr |
[6] | ENABLE_PXP_HANDSHAKE | R/W | 当LCDIF_MASTER设置为1时,再设置这位, 则LCD控制器跟PXP之间的握手机制被关闭(我们不关心) |
[5] | MASTER | R/W | 设置为1时,LCD控制器成为bus master |
[4] | RSRVD0 | R/W | 保留 |
[3] | DATA_FORMAT_16_BIT | R/W | WORD_LENGTH为0时,表示一个像素用16位,此位作用如下: 0:数据格式为ARGB555; 1:数据格式为RGB565 |
[2] | DATA_FORMAT_18_BIT | R/W | WORD_LENGTH为2时,表示一个像素用18位,RGB数据还是保存在32位数据里,此位作用如下: 0:低18位用来表示RGB666,高14位无效 1:高18位用来表示RGB666,低14位无效 |
[1] | DATA_FORMAT_24_BIT | R/W | WORD_LENGTH为3时,表示一个像素用24位,此位作用如下: 0:所有的24位数据都有效,格式为RGB888 1:转给LCD控制器的数据是24位的,但只用到其中的18位, 每个字节用来表示一个原色,每字节中高2位无效 |
[0] | RUN | R/W | 使能LCD控制器,开始传输数据 |
2. LCDIF_CTRL1n
eLCDIF General Control1 Register (LCDIF_CTRL1n):

我是使用TFT LCD,LCD控制器使用DOTCLK模式。本寄存器会用到BYTE_PACKING_FORMAT 。
位域 | 名称 | 读写 | 描述 |
[19:16] | BYTE_PACKING_FORMAT | R/W | 用来表示一个32位的word中,哪些字节是有效的,即哪些字节是用来表示颜色的。 bit16、17、18、19分别对应byte0、1、2、3;某位为1,就表示对应的字节有效。 默认值是0xf,表示32位的word中,所有字节都有效。 对于8bpp,可以忽略本设置,所有的字节都是有效的; 对于16bpp,bit[1:0]、bit[3:2]分别对应一个字节,组合中的2位都为1时,对应的字节才有效; 对于24bpp,0x7表示32位数据中只用到3个字节,这称为“24 bit unpacked format”,即ARGB,其中的A字节被丢弃 |
[0] | RESET | R/W | 用来复位了接的LCD, 0:LCD_RESET引脚输出低电平; 1:LCD_RESET引脚输出高电平 |
3. LCDIF_TRANSFER_COUNT
eLCDIF Horizontal and Vertical Valid Data Count Register(LCDIF_TRANSFER_COUNT):

位域 | 名称 | 读写 | 描述 |
[31:16] | V_COUNT | R/W | 一帧中,有多少行有效数据,高16位是V_COUNT,是 LCD 的垂直分辨率。 |
[15:0] | H_COUNT | R/W | 一行中,有多少个像素,低 16 位是 H_COUNT,是 LCD 的水平分辨率。 |
如果 LCD 分辨率为1024*600 的话,那么 V_COUNT 就是 600, H_COUNT 就是 1024。
4. LCDIF_VDCTRL0n
eLCDIF VSYNC Mode and Dotclk Mode Control Register0(LCDIF_VDCTRL0n):

本寄存器用来设置Vsync信号相关的时序,及极性。
位域 | 名称 | 读写 | 描述 |
[29] | VSYNC_OEB | R/W | 用来控制VSYNC信号,对于DOTCLK模式,设为0, 0:VSYNC是输出引脚,用LCD控制器产生; 1:VSYNC是输入引脚 |
[28] | ENABLE_PRESENT | R/W | 在DOTCLK模式下,硬件是否会产生数据使能信号ENALBE: 0:不产生; 1:产生 |
[27] | VSYNC_POL | R/W | 用来决定VSYNC脉冲的极性, 0:低脉冲; 1:高脉冲 |
[26] | HSYNC_POL | R/W | 用来决定HSYNC脉冲的极性, 0:低脉冲; 1:高脉冲 |
[25] | DOTCLK_POL | R/W | 用来决定DOTCLK的极性, 0:LCD控制器在DOTCLK下降沿发送数据,LCD在上升沿捕获数据; 1:反过来 |
[24] | ENABLE_POL | R/W | 用来决定ENABLE信号的极性, 0:数据有效期间,ENABLE信号为低; 1:反过来 |
[21] | VSYNC_PERIOD_UNIT | R/W | 用来决定VSYNC_PERIOD的单位, 0:单位是像素时钟(pix_clk),这在VSYNC模式下使用; 1:单位是“整行”,这在DOTCLK模式下使用 |
[20] | VSYNC_PULSE_WIDTH_UNIT | R/W | 用来决定VSYNC_PULSE_WIDTH的单位, 0:单位是像素时钟(pix_clk); 1:单位是“整行” |
[19] | HALF_LINE | R/W | VSYNC周期是否周加上半行的时间, 0:VSYNC周期=VSYNC_PERIOD; 1:VSYNC周期=VSYNC_PERIOD+HORIZONTAL_PERIOD/2 |
[18] | HALF_LINE_MODE | R/W | 0:第1帧将在一行的中间结束,第2帧在一行的中间开始; 1:所有帧结束前都加上半行时间,这样所有帧都会起始于“行的开头” |
[17:0] | VSYNC_PULSE_WIDTH | R/W | VSYNC脉冲的宽度 |
5. LCDIF_VDCTRL1
eLCDIF VSYNC Mode and Dotclk Mode Control Register1(LCDIF_VDCTRL1):

位域 | 名称 | 读写 | 描述 |
[29] | VSYNC_PERIOD | R/W | 两个垂直同步信号之间的间隔,即垂直方向同步信号的总周期; 单位由VSYNC_PERIOD_UNIT决定 |
这个寄存器是 VSYNC 和 DOTCLK 模式控制寄存器 1,此寄存器只有一个功能,用来设置 VSYNC 总周期,就是:屏幕高度+VSPW+VBP+VFP。
6. LCDIF_VDCTRL2
LCDIF VSYNC Mode and Dotclk Mode Control Register2(LCDIF_VDCTRL2):

HSYNC_PULSE_WIDTH:水平同步信号脉冲宽度;
HSYNC_PERIOD:两个水平同步信号之间的总数,即水平方向同步信号的总周期
位域 | 名称 | 读写 | 描述 |
[31:18] | HSYNC_PULSE_WIDTH | R/W | HSYNC脉冲的宽度(单位:pix_clk) |
[17:0] | HSYNC_PERIOD | R/W | 整行的宽度,即两个HYSNC信号之间的宽度(单位:pix_clk) |
这个寄存器分为高 16 位和低 16 位两部分,高 16位是 HSYNC_PULSE_WIDTH,用来设置 HSYNC 信号宽度,也就是 HSPW。低 16 位是HSYNC_PERIOD,设置 HSYNC 总周期,就是:屏幕宽度+HSPW+HBP+HFP。
7. LCDIF_VDCTRL3
eLCDIF VSYNC Mode and Dotclk Mode Control Register3(LCDIF_VDCTRL3):

位域 | 名称 | 读写 | 描述 |
[29] | MUX_SYNC_SIGNALS | R/W | 用不着 |
[28] | VSYNC_ONLY | R/W | 0:DOTCLK模式时必须设置为0; 1:VSYNC模式时必须设置为1 |
[27:16] | HORIZONTAL_WAIT_CNT | R/W | 水平方向上的等待像素个数,等于thp+thb |
[15:0] | VERTICAL_WAIT_CNT | R/W | 垂直方向上的等待行数,等于tvp+tvb |
HORIZONTAL_WAIT_CNT(bit27:16):此位用于 DOTCLK 模式,用于设置 HSYNC 信号产生到有效数据产生之间的时间,也就是 HSPW+HBP。
VERTICAL_WAIR_CNT(bit15:0):和 HORIZONTAL_WAIT_CNT 一样,只是此位用于VSYNC 信号,也就是 VSPW+VBP。
8. LCDIF_VDCTRL4
eLCDIF VSYNC Mode and Dotclk Mode Control Register4(LCDIF_VDCTRL4):

位域 | 名称 | 读写 | 描述 |
[31:29] | DOTCLK_DLY_SEL | R/W | 在LCD控制器内部的DOTCLK输出到LCD_DOTCK引脚时,延时多久: 0:2ns; 1:4ns; 2:6ns; 3:8ns; 其他值保留 |
[18] | SYNC_SIGNALS_ON | R/W | 同步信号使能位,设置为 1 的话使能 VSYNC、 HSYNC、DOTCLK 这些信号。DOTCLK模式下必须设为1 |
[17:0] | DOTCLK_H_VALID_DATA_CNT | R/W | 水平方向上的有效像素个数(pix_clk),即分辨率的y |
9. LCDIF_CUR_BUF
LCD Interface Current Buffer Address Register(LCDIF_CUR_BUF):

位域 | 名称 | 读写 | 描述 |
[31:0] | ADDR | R/W | LCD控制器正在传输的当前帧在显存中的地址 |
10. LCDIF_NEXT_BUF
LCD Interface Next Buffer Address Register(LCDIF_NEXT_BUF):

位域 | 名称 | 读写 | 描述 |
[31:0] | ADDR | R/W | 下一帧在显存中的地址 |
LCD控制器传输完当前帧后,会把LCDIF_NEXT_BUF寄存器的值复制到LCDIF_CUR_BUF寄存器。
三、裸机demo
1. 硬件原理图
1.1 电路原理图

三个 SGM3157 的目的是在未使用 RGBLCD 的时候将 LCD_DATA7、LCD_DATA15 和 LCD_DATA23 这三个线隔离开来,因为 ALIENTEK 的屏幕的 LCD_R7/G7/B7这几个线用来设置 LCD 的 ID,所以这几根线上有上拉/下拉电阻。但是 I.MX6U 的 BOOT 设置也用到了 LCD_DATA7、 LCD_DATA15 和 LCD_DATA23 这三个引脚,所以接上屏幕以后屏幕上的 ID 电阻就会影响到 BOOT 设置,会导致代码无法运行,所以先将其隔离开来,如果要使用 RGB LCD 屏幕的时候再通过 LCD_DE 将其“连接”起来。
1.2 连接方式

1.3 参数计算
我使用的屏幕是ATK-MD0430R-800480,读出来的ID会是0x4384。这款屏幕对应的一些时间参数如下:
ATK-MD0430R-800480 ID=4384 |
|||
HOZVAL(水平显示区域) | thd | 800 | tCLK |
HSPW(horizontal sync width) | thp | 48 | tCLK |
HBP(horizontal back porch) | thb | 88 | tCLK |
HFP(horizontal front porth) | thf | 40 | tCLK |
LINE(垂直显示区域) | tvd | 480 | th |
VSPW(vertical sync width) | tvp | 3 | th |
VBP(vertical back porch) | tvb | 32 | th |
VFP(vertical front porch) | tvf | 13 | th |
像素时钟 | - | 31 | MHz |
1 | 显示一行的时间: HSPW + HBP + HOZVAL + HFP |
2. 生成字模
想要显示英文字符的话需要用软件生成字模,这里可以用PCtoLCD2002 。字模选项设置界面。设置界面中点阵格式和取模方式等参数配置如图

上图设置的取模方式,在右上角的取模说明里面有,即:从第一列开始向下每取 8 个点作为一个字节,如果最后不足 8 个点就补满 8 位。取模顺序是从高到低,即第一个点作为最高位。如*——-取为 10000000。其实就是按下图的方式:

从上到下,从左到右,高位在前。我们按这样的取模方式,然后把 ASCII 字符集按 12*6 大小、 16*8、 24*12 和 32*16 大小取模出来(对应汉字大小为 12*12、 16*16、 24*24 和 32*32,字符的只有汉字的一半大!)。将取出的点阵数组保存在 font.h 里面,每个 12*6 的字符占用 12 个字节,每个 16*8 的字符占用 16 个字节,每个 24*12 的字符占用 36 个字节,每个 32*16 的字符占用 64 个字节。
3. demo源码
看这里:21_lcd/01_lcd_demo · 苏木/imx6ull-bare-demo - 码云 - 开源中国。
3.1 出现的报错问题
这里有个坑,就是关于内联函数的。接下来看一下:
原本在 21_lcd/01_lcd_demo/bsp/lcd/bsp_lcd.c文件中定义了两个内联函数:
1 | /* |
然后在21_lcd/01_lcd_demo/bsp/lcd/bsp_lcd.h中做如下声明:
1 | inline void lcd_drawpoint(unsigned short x,unsigned short y,unsigned int color); |
这样在编译的时候会警告,说有找不到这两个函数定义。这个,一般来说,内联函数最好是定义在头文件中,并且加上static关键字保证一定可以展开。
3.2 解决办法
这里若是想要在.h文件中声明,在.c文件中实现,需要在 21_lcd/01_lcd_demo/bsp/lcd/bsp_lcd.c文件中定义两个内联函数:
1 | /* |
然后在21_lcd/01_lcd_demo/bsp/lcd/bsp_lcd.h中做如下声明:
1 | void lcd_drawpoint(unsigned short x,unsigned short y,unsigned int color); |
我一般还是直接定义到头文件去。