当前位置: 首页 > news >正文

肇庆网站建设咨询山东泰润建设集团网站

肇庆网站建设咨询,山东泰润建设集团网站,软装设计师年终总结,怎样开公司LCD 是很常用的一个外设#xff0c;在Linux 下LCD 的使用更加广泛#xff0c;在搭配 QT 这样的 GUI 库下可以制作出非常精美的 UI 界面。本章我们就来学习一下如何在 Linux 下驱动 LCD 屏幕。 Linux 下 LCD 驱动简析 Framebuffer 设备 先来回顾一下裸机的时候 LCD 驱动是怎…LCD 是很常用的一个外设在Linux 下LCD 的使用更加广泛在搭配 QT 这样的 GUI 库下可以制作出非常精美的 UI 界面。本章我们就来学习一下如何在 Linux 下驱动 LCD 屏幕。 Linux 下 LCD 驱动简析 Framebuffer 设备 先来回顾一下裸机的时候 LCD 驱动是怎么编写的裸机 LCD 驱动编写流程如下 ①、初始化 I.MX6U 的 eLCDIF 控制器重点是 LCD 屏幕宽(width)、高(height)、 hspw、hbp、 hfp、 vspw、 vbp 和 vfp 等信息。 ②、初始化 LCD 像素时钟。 ③、设置 RGBLCD 显存。 ④、应用程序直接通过操作显存来操作 LCD实现在 LCD 上显示字符、图片等信息。 在Linux中应用程序最终也是通过操作RGB LCD的显存来实现在 LCD 上显示字符、图片等信息。在裸机中我们可以随意的分配显存但是在 Linux 系统中内存的管理很严格显存是需要申请的不是你想用就能用的。而且因为虚拟内存的存在驱动程序设置的显存和应用程序访问的显存要是同一片物理内存。 为了解决上述问题 Framebuffer 诞生了 Framebuffer 翻译过来就是帧缓冲简称 fb因此大家在以后的 Linux 学习中见到“Framebuffer”或者“fb”的话第一反应应该想到 RGBLCD或者显示设备。 fb是一种机制将系统中所有跟显示有关的硬件以及软件集合起来虚拟出一个 fb 设备当我们编写好 LCD 驱动以后会生成一个名为/dev/fbX(X0~n)的设备应用程序通过访问/dev/fbX 这个设备就可以访问 LCD。NXP 官方的 Linux 内核默认已经开启了 LCD 驱动因此我们是可以看到/dev/fb0 这样一个设备如图所示 图中的/dev/fb0 就是 LCD 对应的设备文件 /dev/fb0 是个字符设备因此肯定有file_operations 操作集 fb 的 file_operations 操作集定义在 drivers/video/fbdev/core/fbmem.c 文件中如下所示 1495 static const struct file_operations fb_fops { 1496 .owner THIS_MODULE, 1497 .read fb_read, 1498 .write fb_write, 1499 .unlocked_ioctl fb_ioctl, 1500 #ifdef CONFIG_COMPAT 1501 .compat_ioctl fb_compat_ioctl, 1502 #endif 1503 .mmap fb_mmap, 1504 .open fb_open, 1505 .release fb_release, 1506 #ifdef HAVE_ARCH_FB_UNMAPPED_AREA 1507 .get_unmapped_area get_fb_unmapped_area, 1508 #endif 1509 #ifdef CONFIG_FB_DEFERRED_IO 1510 .fsync fb_deferred_io_fsync, 1511 #endif 1512 .llseek default_llseek, 1513 }; 关于 fb 的详细处理过程就不去深究了本章我们的重点是驱动起来 ALPHA 开发板上的LCD。 LCD 驱动简析 LCD 裸机例程主要分两部分 ①、获取 LCD 的屏幕参数。 ②、根据屏幕参数信息来初始化 eLCDIF 接口控制器。 不同分辨率的 LCD 屏幕其 eLCDIF 控制器驱动代码都是一样的只需要修改好对应的屏幕参数即可。屏幕参数信息属于屏幕设备信息内容这些肯定是要放到设备树中的因此我们本章实验的主要工作就是修改设备树 NXP 官方的设备树已经添加了 LCD 设备节点只是此节点的 LCD 屏幕信息是针对 NXP 官方 EVK 开发板所使用的 4.3 寸 480*272 编写的我们需要将其改为我们所使用的屏幕参数。我们简单看一下 NXP 官方编写的 Linux 下的 LCD 驱动打开 imx6ull.dtsi然后找到 lcdif节点内容如下所示 1 lcdif: lcdif021c8000 { 2 compatible fsl,imx6ul-lcdif, fsl,imx28-lcdif; 3 reg 0x021c8000 0x4000; 4 interrupts GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH; 5 clocks clks IMX6UL_CLK_LCDIF_PIX, 6 clks IMX6UL_CLK_LCDIF_APB, 7 clks IMX6UL_CLK_DUMMY; 8 clock-names pix, axi, disp_axi; 9 status disabled; 10 }; 上述代码中的 lcdif 节点信息是所有使用 I.MX6ULL 芯片的板子所共有的并不是完整的 lcdif 节点信息。像屏幕参数这些需要根据不同的硬件平台去添加比如向 imx6ullalientek-emmc.dts 中的 lcdif 节点添加其他的属性信息。从上述代码可以看出 lcdif 节点的 compatible 属性值为“fsl,imx6ul-lcdif”和“fsl,imx28-lcdif”因此在 Linux 源码中搜索这两个字符串即可找到 I.MX6ULL 的 LCD 驱动文件这个文件为 drivers/video/fbdev/mxsfb.c mxsfb.c就是 I.MX6ULL 的 LCD 驱动文件在此文件中找到如下内容 1362 static const struct of_device_id mxsfb_dt_ids[] { 1363 { .compatible fsl,imx23-lcdif, .data mxsfb_devtype[0], }, 1364 { .compatible fsl,imx28-lcdif, .data mxsfb_devtype[1], }, 1365 { /* sentinel */ } 1366 }; ...... 1625 static struct platform_driver mxsfb_driver { 1626 .probe mxsfb_probe, 1627 .remove mxsfb_remove, 1628 .shutdown mxsfb_shutdown, 1629 .id_table mxsfb_devtype, 1630 .driver { 1631 .name DRIVER_NAME, 1632 .of_match_table mxsfb_dt_ids, 1633 .pm mxsfb_pm_ops, 1634 }, 1635 }; 1636 1637 module_platform_driver(mxsfb_driver); 从上述代码可以看出这是一个标准的 platform 驱动当驱动和设备匹配以后mxsfb_probe 函数就会执行。在看 mxsfb_probe 函数之前我们先简单了解一下 Linux 下Framebuffer 驱动的编写流程 Linux 内核将所有的 Framebuffer 抽象为一个叫做 fb_info 的结构体 fb_info 结构体包含了 Framebuffer 设备的完整属性和操作集合因此每一个 Framebuffer 设备都必须有一个 fb_info。换言之就是 LCD 的驱动就是构建 fb_info并且向系统注册 fb_info的过程。 fb_info 结构体定义在 include/linux/fb.h 文件里面内容如下(省略掉条件编译) 448 struct fb_info { 449 atomic_t count; 450 int node; 451 int flags; 452 struct mutex lock; /* 互斥锁 */ 453 struct mutex mm_lock; /* 互斥锁用于 fb_mmap 和 smem_*域*/ 454 struct fb_var_screeninfo var; /* 当前可变参数 */ 455 struct fb_fix_screeninfo fix; /* 当前固定参数 */ 456 struct fb_monspecs monspecs; /* 当前显示器特性 */ 457 struct work_struct queue; /* 帧缓冲事件队列 */ 458 struct fb_pixmap pixmap; /* 图像硬件映射 */ 459 struct fb_pixmap sprite; /* 光标硬件映射 */ 460 struct fb_cmap cmap; /* 当前调色板 */ 461 struct list_head modelist; /* 当前模式列表 */ 462 struct fb_videomode *mode; /* 当前视频模式 */ 463 464 #ifdef CONFIG_FB_BACKLIGHT /* 如果 LCD 支持背光的话 */ 465 /* assigned backlight device */ 466 /* set before framebuffer registration, 467 remove after unregister */ 468 struct backlight_device *bl_dev; /* 背光设备 */ 469 470 /* Backlight level curve */ 471 struct mutex bl_curve_mutex; 472 u8 bl_curve[FB_BACKLIGHT_LEVELS]; 473 #endif ...... 479 struct fb_ops *fbops; /* 帧缓冲操作函数集 */ 480 struct device *device; /* 父设备 */ 481 struct device *dev; /* 当前 fb 设备 */ 482 int class_flag; /* 私有 sysfs 标志 */ ...... 486 char __iomem *screen_base; /* 虚拟内存基地址(屏幕显存) */ 487 unsigned long screen_size; /* 虚拟内存大小(屏幕显存大小) */ 488 void *pseudo_palette; /* 伪 16 位调色板 */ ...... 507 }; fb_info 结构体的成员变量很多我们重点关注 var、 fix、 fbops、 screen_base、 screen_size和 pseudo_palette。 mxsfb_probe 函数的主要工作内容为 ①、申请 fb_info。 ②、初始化 fb_info 结构体中的各个成员变量。 ③、初始化 eLCDIF 控制器。 ④、使用 register_framebuffer 函数向 Linux 内核注册初始化好的 fb_info。register_framebuffer函数原型如下 int register_framebuffer(struct fb_info *fb_info) 函数参数和返回值含义如下 fb_info需要上报的 fb_info。 返回值 0成功负值失败。 接下来我们简单看一下 mxsfb_probe 函数函数内容如下(有缩减) 1369 static int mxsfb_probe(struct platform_device *pdev) 1370 { 1371 const struct of_device_id *of_id 1372 of_match_device(mxsfb_dt_ids, pdev-dev); 1373 struct resource *res; 1374 struct mxsfb_info *host; 1375 struct fb_info *fb_info; 1376 struct pinctrl *pinctrl; 1377 int irq platform_get_irq(pdev, 0); 1378 int gpio, ret; 1379 ...... 1394 1395 res platform_get_resource(pdev, IORESOURCE_MEM, 0); 1396 if (!res) { 1397 dev_err(pdev-dev, Cannot get memory IO resource\n); 1398 return -ENODEV; 1399 } 1400 1401 host devm_kzalloc(pdev-dev, sizeof(struct mxsfb_info), GFP_KERNEL); 1402 if (!host) { 1403 dev_err(pdev-dev, Failed to allocate IO resource\n); 1404 return -ENOMEM; 1405 } 1406 1407 fb_info framebuffer_alloc(sizeof(struct fb_info), pdev-dev); 1408 if (!fb_info) { 1409 dev_err(pdev-dev, Failed to allocate fbdev\n); 1410 devm_kfree(pdev-dev, host); 1411 return -ENOMEM; 1412 } 1413 host-fb_info fb_info; 1414 fb_info-par host; 1415 1416 ret devm_request_irq(pdev-dev, irq, mxsfb_irq_handler, 0, 1417 dev_name(pdev-dev), host); 1418 if (ret) { 1419 dev_err(pdev-dev, request_irq (%d) failed with 1420 error %d\n, irq, ret); 1421 ret -ENODEV; 1422 goto fb_release; 1423 } 1424 1425 host-base devm_ioremap_resource(pdev-dev, res); 1426 if (IS_ERR(host-base)) { 1427 dev_err(pdev-dev, ioremap failed\n); 1428 ret PTR_ERR(host-base); 1429 goto fb_release; 1430 } ...... 1461 1462 fb_info-pseudo_palette devm_kzalloc(pdev-dev, sizeof(u32) * 1463 16, GFP_KERNEL); 1464 if (!fb_info-pseudo_palette) { 1465 ret -ENOMEM; 1466 goto fb_release; 1467 } 1468 1469 INIT_LIST_HEAD(fb_info-modelist); 1470 1471 pm_runtime_enable(host-pdev-dev); 1472 1473 ret mxsfb_init_fbinfo(host); 1474 if (ret ! 0) 1475 goto fb_pm_runtime_disable; 1476 1477 mxsfb_dispdrv_init(pdev, fb_info); 1478 1479 if (!host-dispdrv) { 1480 pinctrl devm_pinctrl_get_select_default(pdev-dev); 1481 if (IS_ERR(pinctrl)) { 1482 ret PTR_ERR(pinctrl); 1483 goto fb_pm_runtime_disable; 1484 } 1485 } 1486 1487 if (!host-enabled) { 1488 writel(0, host-base LCDC_CTRL); 1489 mxsfb_set_par(fb_info); 1490 mxsfb_enable_controller(fb_info); 1491 pm_runtime_get_sync(host-pdev-dev); 1492 } 1493 1494 ret register_framebuffer(fb_info); 1495 if (ret ! 0) { 1496 dev_err(pdev-dev, Failed to register framebuffer\n); 1497 goto fb_destroy; 1498 } ...... 1525 return ret; 1526 } 第 1374 行 host 结构体指针变量表示 I.MX6ULL 的 LCD 的主控接口 mxsfb_info 结构体是 NXP 定义的针对 I.MX 系列 SOC 的 Framebuffer 设备结构体。也就是我们前面一直说的设 备结构体此结构体包含了 I.MX 系列 SOC 的 Framebuffer 设备详细信息比如时钟、 eLCDIF控制器寄存器基地址、 fb_info 等。 第 1395 行从设备树中获取 eLCDIF 接口控制器的寄存器首地址设备树中 lcdif 节点已经设置了 eLCDIF 寄存器首地址为 0X021C8000因此 res0X021C8000。 第 1401 行给 host 申请内存 host 为 mxsfb_info 类型结构体指针。 第 1407 行给 fb_info 申请内存也就是申请 fb_info。 第 1413~1414 行设置 host 的 fb_info 成员变量为 fb_info设置 fb_info 的 par 成员变量为host。通过这一步就将前面申请的 host 和 fb_info 联系在了一起。 第 1416 行申请中断中断服务函数为 mxsfb_irq_handler。 第 1425 行对从设备树中获取到的寄存器首地址(res)进行内存映射得到虚拟地址并保存到 host 的 base 成员变量。因此通过访问 host 的 base 成员即可访问 I.MX6ULL 的整个 eLCDIF 寄存器。其实在 mxsfb.c 中已经定义了 eLCDIF 各个寄存器相比于基地址的偏移值如下所示 67 #define LCDC_CTRL 0x00 68 #define LCDC_CTRL1 0x10 69 #define LCDC_V4_CTRL2 0x20 70 #define LCDC_V3_TRANSFER_COUNT 0x20 71 #define LCDC_V4_TRANSFER_COUNT 0x30 ...... 89 #define LCDC_V4_DEBUG0 0x1d0 90 #define LCDC_V3_DEBUG0 0x1f0 继续回到 mxsfb_probe 函数第1462 行给 fb_info 中的 pseudo_palette申请内存。 第 1473 行调用 mxsfb_init_fbinfo 函数初始化 fb_info重点是 fb_info 的 var、 fix、 fbopsscreen_base 和 screen_size。其中 fbops 是 Framebuffer 设备的操作集 NXP 提供的 fbops 为 mxsfb_ops内容如下 987 static struct fb_ops mxsfb_ops { 988 .owner THIS_MODULE, 989 .fb_check_var mxsfb_check_var, 990 .fb_set_par mxsfb_set_par, 991 .fb_setcolreg mxsfb_setcolreg, 992 .fb_ioctl mxsfb_ioctl, 993 .fb_blank mxsfb_blank, 994 .fb_pan_display mxsfb_pan_display, 995 .fb_mmap mxsfb_mmap, 996 .fb_fillrect cfb_fillrect, 997 .fb_copyarea cfb_copyarea, 998 .fb_imageblit cfb_imageblit, 999 }; 关于 mxsfb_ops 里面的各个操作函数这里就不去详解的介绍了。 mxsfb_init_fbinfo 函数通过调用 mxsfb_init_fbinfo_dt 函数从设备树中获取到 LCD 的各个参数信息。最后 mxsfb_init_fbinfo 函数会调用 mxsfb_map_videomem 函数申请 LCD 的帧缓冲内存(也就是显存)。 第 1489~1490 行设置 eLCDIF 控制器的相应寄存器。 第 1494 行最后调用 register_framebuffer 函数向 Linux 内核注册 fb_info。 mxsfb.c 文件很大还有一些其他的重要函数比如 mxsfb_remove、 mxsfb_shutdown 等这里我们就简单的介绍了一下 mxsfb_probe 函数至于其他的函数大家自行查阅。 LCD 驱动使用 前面已经说了 6ULL 的 eLCDIF 接口驱动程序 NXP 已经编写好了因此 LCD 驱动部分我们不需要去修改。我们需要做的就是按照所使用的 LCD 来修改设备树。重点要注意三个地方 ①、 LCD 所使用的 IO 配置。 ②、 LCD 屏幕节点修改修改相应的属性值换成我们所使用的 LCD 屏幕参数。 ③、 LCD 背光节点信息修改要根据实际所使用的背光 IO 来修改相应的设备节点信息。 接下来我们依次来看一下上面这两个节点改如何去修改 LCD 屏幕 IO 配置 首先要检查一下设备树中 LCD 所使用的 IO 配置这个其实 NXP 都已经给我们写好了不需要修改不过我们还是要看一下。打开 imx6ull-alientek-emmc.dts 文件在 iomuxc 节点中 找到如下内容 1 pinctrl_lcdif_dat: lcdifdatgrp { 2 fsl,pins 3 MX6UL_PAD_LCD_DATA00__LCDIF_DATA00 0x79 4 MX6UL_PAD_LCD_DATA01__LCDIF_DATA01 0x79 5 MX6UL_PAD_LCD_DATA02__LCDIF_DATA02 0x79 6 MX6UL_PAD_LCD_DATA03__LCDIF_DATA03 0x79 7 MX6UL_PAD_LCD_DATA04__LCDIF_DATA04 0x79 8 MX6UL_PAD_LCD_DATA05__LCDIF_DATA05 0x79 9 MX6UL_PAD_LCD_DATA06__LCDIF_DATA06 0x79 10 MX6UL_PAD_LCD_DATA07__LCDIF_DATA07 0x79 11 MX6UL_PAD_LCD_DATA08__LCDIF_DATA08 0x79 12 MX6UL_PAD_LCD_DATA09__LCDIF_DATA09 0x79 13 MX6UL_PAD_LCD_DATA10__LCDIF_DATA10 0x79 14 MX6UL_PAD_LCD_DATA11__LCDIF_DATA11 0x79 15 MX6UL_PAD_LCD_DATA12__LCDIF_DATA12 0x79 16 MX6UL_PAD_LCD_DATA13__LCDIF_DATA13 0x79 17 MX6UL_PAD_LCD_DATA14__LCDIF_DATA14 0x79 18 MX6UL_PAD_LCD_DATA15__LCDIF_DATA15 0x79 19 MX6UL_PAD_LCD_DATA16__LCDIF_DATA16 0x79 20 MX6UL_PAD_LCD_DATA17__LCDIF_DATA17 0x79 21 MX6UL_PAD_LCD_DATA18__LCDIF_DATA18 0x79 22 MX6UL_PAD_LCD_DATA19__LCDIF_DATA19 0x79 23 MX6UL_PAD_LCD_DATA20__LCDIF_DATA20 0x79 24 MX6UL_PAD_LCD_DATA21__LCDIF_DATA21 0x79 25 MX6UL_PAD_LCD_DATA22__LCDIF_DATA22 0x79 26 MX6UL_PAD_LCD_DATA23__LCDIF_DATA23 0x79 27 ; 28 }; 29 30 pinctrl_lcdif_ctrl: lcdifctrlgrp { 31 fsl,pins 32 MX6UL_PAD_LCD_CLK__LCDIF_CLK 0x79 33 MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE 0x79 34 MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC 0x79 35 MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC 0x79 36 ; 37 pinctrl_pwm1: pwm1grp { 38 fsl,pins 39 MX6UL_PAD_GPIO1_IO08__PWM1_OUT 0x110b0 40 ; 41 }; 第 2~27 行子节点 pinctrl_lcdif_dat为 RGB LCD 的 24 根数据线配置项。 第 30~36 行子节点 pinctrl_lcdif_ctrl RGB LCD 的 4 根控制线配置项包括 CLK、ENABLE、 VSYNC 和 HSYNC。 第 37~40 行子节点 pinctrl_pwm1 LCD 背光 PWM 引脚配置项。这个引脚要根据实际情况设置。 上述代码中默认将 LCD 的电气属性都设置为 0X79这里将其都改为 0X49也就是将 LCD 相关 IO 的驱动能力改为 R0/1也就是降低 LCD 相关 IO 的驱动能力。因为前面已经说了正点原子的 ALPHA 开发板上的 LCD 接口用了三个 SGM3157 模拟开关为了防止模拟开关影响到网络因此这里需要降低 LCD 数据线的驱动能力如果你所使用的板子没有用到模拟开关那么就不需要将 0X79 改为 0X49。 LCD 屏幕参数节点信息修改 继续在 imx6ull-alientek-emmc.dts 文件中找到 lcdif 节点节点内容如下所示 1 lcdif { 2 pinctrl-names default; 3 pinctrl-0 pinctrl_lcdif_dat /* 使用到的 IO */ 4 pinctrl_lcdif_ctrl 5 pinctrl_lcdif_reset; 6 display display0; 7 status okay; 8 9 display0: display { /* LCD 属性信息 */ 10 bits-per-pixel 16; /* 一个像素占用几个 bit */ 11 bus-width 24; /* 总线宽度 */ 12 13 display-timings { 14 native-mode timing0; /* 时序信息 */ 15 timing0: timing0 { 16 clock-frequency 9200000; /* LCD 像素时钟单位 Hz */ 17 hactive 480; /* LCD X 轴像素个数 */ 18 vactive 272; /* LCD Y 轴像素个数 */ 19 hfront-porch 8; /* LCD hfp 参数 */ 20 hback-porch 4; /* LCD hbp 参数 */ 21 hsync-len 41; /* LCD hspw 参数 */ 22 vback-porch 2; /* LCD vbp 参数 */ 23 vfront-porch 4; /* LCD vfp 参数 */ 24 vsync-len 10; /* LCD vspw 参数 */ 25 26 hsync-active 0; /* hsync 数据线极性 */ 27 vsync-active 0; /* vsync 数据线极性 */ 28 de-active 1; /* de 数据线极性 */ 29 pixelclk-active 0; /* clk 数据线先极性 */ 30 }; 31 }; 32 }; 33 }; 上述代码就是向 imx6ull.dtsi 文件中的 lcdif 节点追加的内容我们依次来看一下这些属性都是写什么含义。 第 3 行 pinctrl-0 属性 LCD 所使用的 IO 信息这里用到了 pinctrl_lcdif_dat、pinctrl_lcdif_ctrl和 pinctrl_lcdif_reset 这三个 IO 相关的节点pinctrl_lcdif_reset 是 LCD 复位 IO 信息节点正点原子的 I.MX6U-ALPHA 开发板的 LCD 没有用到复位 IO因此 pinctrl_lcdif_reset 可以删除掉。 第 6 行 display 属性指定 LCD 属性信息所在的子节点这里为 display0下面就是 display0子节点内容。 第 9~32 行 display0 子节点描述 LCD 的参数信息第 10 行的 bits-per-pixel 属性用于指明一个像素占用的 bit 数默认为 16bit。本教程我们将 LCD 配置为 RGB888 模式因此一个像素点占用 24bit bits-per-pixel 属性要改为 24。 第 11 行的 bus-width 属性用于设置数据线宽度因为要配置为 RGB888 模式因此 bus-width 也要设置为 24。 第 13~30 行这几行非常重要因为这几行设置了 LCD 的时序参数信息 NXP 官方的 EVK开发板使用了一个 4.3 寸的 480*272 屏幕因此这里默认是按照 NXP 官方的那个屏幕参数设置的。每一个属性的含义后面的注释已经写的很详细了大家自己去看就行了这些时序参数就是我们重点要修改的需要根据自己所使用的屏幕去修改。 LCD 屏幕背光节点信息 正点原子的 LCD 接口背光控制 IO 连接到了 I.MX6U 的 GPIO1_IO08 引脚上 GPIO1_IO08复用为 PWM1_OUT通过 PWM 信号来控制 LCD 屏幕背光的亮度正点原子 I.MX6U-ALPHA 开发板的 LCD 背光引脚和 NXP 官方 EVK 开发板的背光引脚一样因此背光的设备树节点是不需要修改的但是考虑到其他同学可能使用别的开发板或者屏幕 LCD 背光引脚和 NXP 官方 EVK 开发板可能不同因此我们还是来看一下如何在设备树中添加背光节点信息。 首先是 GPIO1_IO08 这个 IO 的配置在 imx6ull-alientek-emmc.dts 中找到如下内容 1 pinctrl_pwm1: pwm1grp { 2 fsl,pins 3 MX6UL_PAD_GPIO1_IO08__PWM1_OUT 0x110b0 4 ; 5 }; pinctrl_pwm1 节点就是 GPIO1_IO08 的配置节点从第 3 行可以看出设置 GPIO1_IO08这个 IO 复用为 PWM1_OUT并且设置电气属性值为 0x110b0。 LCD 背光要用到 PWM1因此也要设置 PWM1 节点在 imx6ull.dtsi 文件中找到如下内容 1 pwm1: pwm02080000 { 2 compatible fsl,imx6ul-pwm, fsl,imx27-pwm; 3 reg 0x02080000 0x4000; 4 interrupts GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH; 5 clocks clks IMX6UL_CLK_PWM1, 6 clks IMX6UL_CLK_PWM1; 7 clock-names ipg, per; 8 #pwm-cells 2; 9 }; imx6ull.dtsi 文件中的 pwm1 节点信息大家不要修改如果要修改 pwm1 节点内容的话请在imx6ull-alientek-emmc.dts 文件中修改。在整个 Linux 源码文件中搜索 compatible 属性的这两个值即可找到 imx6ull 的 pwm 驱动文件 imx6ull 的 PWM 驱动文件为 drivers/pwm/pwm-imx.c这里我们就不详细的去分析这个文件了。继续在 imx6ull-alientek-emmc.dts 文件中找到向 pwm1追加的内容如下所示 1 pwm1 { 2 pinctrl-names default; 3 pinctrl-0 pinctrl_pwm1; 4 status okay; 5 }; 第 3 行设置 pwm1 所使用的 IO 为 pinctrl_pwm1 第 4 行将 status 设置为 okay。 如果背光用的其他 pwm 通道比如 pwm2那么就需要仿照示例代码的内容向pwm2 节点追加相应的内容。 pwm 和相关的 IO 已经准备好了但是 Linux 系统怎么知道PWM1_OUT 就是控制 LCD 背光的呢因此我们还需要一个节点来将 LCD 背光和 PWM1_OUT连 接 起 来 。 这个节点就是backlight backlight 节 点 描 述 可 以 参 考 Documentation/devicetree/indings/video/backlight/pwm-backlight.txt 这个文档此文档详细讲解了backlight 节点该如何去创建这里大概总结一下 ①、节点名称要为“backlight”。 ②、节点的 compatible 属性值要为“pwm-backlight”因此可以通过在 Linux 内核中搜索“ pwm-backlight ” 来 查 找 PWM 背 光 控 制 驱 动 程 序 这 个 驱 动 程 序 文 件 为 drivers/video/backlight/pwm_bl.c感兴趣的可以去看一下这个驱动程序。 ③、pwms属性用于描述背光所使用的PWM以及PWM频率比如本章我们要使用的pwm1pwm 频率设置为 5KHz(NXP 官方推荐设置)。 ④、 brightness-levels 属性描述亮度级别范围为 0~255 0 表示 PWM 占空比为 0%也就是亮度最低 255 表示 100%占空比也就是亮度最高。至于设置几级亮度大家可以自行填写 此属性。 ⑤、 default-brightness-level 属性为默认亮度级别。 根据上述 5 点设置 backlight 节点这个 NXP 已经给我们设置好了大家在 imx6ull-alientekemmc.dts 文件中找到如下内容 backlight {compatible pwm-backlight;pwms pwm1 0 5000000;brightness-levels 0 4 8 16 32 64 128 255;default-brightness-level 6;status okay; }; 第 3 行设置背光使用 pwm1 PWM 频率为 200Hz。 第 4 行设置背 8 级背光(0~7)分别为 0、 4、 8、 16、 32、 64、 128、 255对应占空比为0%、 1.57%、 3.13%、 6.27%、 12.55%、 25.1%、 50.19%、 100%如果嫌少的话可以自行添加一些其他的背光等级值。 第 5 行设置默认背光等级为 6也就是 50.19%的亮度。 关于背光的设备树节点信息就讲到这里整个的 LCD 设备树节点内容我们就讲完了按照这些节点内容配置自己的开发板即可。 实验 编译新的设备树 等待编译生成新的 imx6ull-alientek-emmc.dtb 设备树文件一会要使用新的设备树启动Linux 内核。 make dtbs 使能 Linux logo 显示 Linux 内核启动的时候可以选择显示小企鹅 logo只要这个小企鹅 logo 显示没问题那么我们的 LCD 驱动基本就工作正常了。这个 logo 显示是要配置的不过 Linux 内核一般都会默认 开启 logo 显示但是奔着学习的目的我们还是来看一下如何使能 Linux logo 显示。打开 Linux内核图形化配置界面按下路径找到对应的配置项 图中这三个选项分别对应黑白、 16 位、 24 位色彩格式的 logo我们把这三个都选中都编译进 Linux 内核里面。设置好以后保存退出重新编译 Linux 内核编译完成以后使用新编译出来的 imx6ull-alientek-emmc.dtb 和 zImage 镜像启动系统如果 LCD 驱动工作正常的话就会在 LCD 屏幕左上角出现一个彩色的小企鹅 logo屏幕背景色为黑色如图 59.4.1.2所示 设置 LCD 作为终端控制台 我们一直使用SecureCRT作为Linux开发板终端开发板通过串口和SecureCRT进行通信。现在我们已经驱动起来 LCD 了所以可以设置 LCD 作为终端也就是开发板使用自己的显示设备作为自己的终端然后接上键盘就可以直接在开发板上敲命令了将 LCD 设置为终端控制台的方法如下 设置 uboot 中的 bootargs 重启开发板进入 Linux 命令行重新设置 bootargs 参数的 console 内容命令如下所示 setenv bootargs consoletty1 consolettymxc0,115200 root/dev/nfs rw nfsroot192.168.1.250:/home/zuozhongkai/linux/nfs/rootfs ip192.168.1.251:192.168.1.250:192.168.1.1:255.255.255.0::eth0:off 注意console设置 这里我们设置了两遍 console第一次设置 consoletty1也就是设置 LCD 屏幕为控制台第二遍又设置 consolettymxc0,115200也就是设置串口也作为控制台。相当于我们打开了两个 console一个是 LCD一个是串口大家重启开发板就会发现 LCD 和串口都会显示 Linux 启动 log 信息。但是此时我们还不能使用 LCD 作为终端进行交互因为我们的设置还未完成。 修改/etc/inittab 文件 打开开发板根文件系统中的/etc/inittab 文件在里面加入下面这一行 tty1::askfirst:-/bin/sh 修改完成以后保存/etc/inittab 并退出然后重启开发板重启以后开发板 LCD 屏幕最后一行会显示下面一行语句 Please press Enter to activate this console. 上述提示语句说的是按下回车键使能当前终端大家可以接上一个 USB 键盘 Linux 内核默认已经使能了 USB 键盘驱动了因此可以直接使用 USB 键盘。 至此我们就拥有了两套终端一个是基于串口的 SecureCRT一个就是我们开发板的 LCD屏幕但是为了方便调试我们以后还是以 SecureCRT 为主。我们可以通过下面这一行命令向 LCD 屏幕输出“hello linux” echo hello linux /dev/tty1 LCD 背光调节 前面已经讲过了背光设备树节点设置了 8 个等级的背光调节可以设置为 0~7我们可以通过设置背光等级来实现 LCD 背光亮度的调节进入如下目录 cd /sys/devices/platform/backlight/backlight/backlight 图中的 brightness 表示当前亮度等级 max_brightness 表示最大亮度等级。当前这两个文件内容如图所示 从图中可以看出当前屏幕亮度等级为 6根据前面的分析可以得知这个是 50%亮度。屏幕最大亮度等级为 7。如果我们要修改屏幕亮度只需要向 brightness 写入需要设置的屏幕亮 度等级即可。比如设置屏幕亮度等级为 7那么可以使用如下命令 echo 7 brightness 输入上述命令以后就会发现屏幕亮度增大了如果设置 brightness 为 0 的话就会关闭 LCD背光屏幕就会熄灭。 LCD 自动关闭解决方法 默认情况下 10 分钟以后 LCD 就会熄屏这个并不是代码有问题而是 Linux 内核设置的就和我们用手机或者电脑一样一段时间不操作的话屏幕就会熄灭以节省电能。解决这个问 题有多种方法 我们依次来看一下 按键盘唤醒 最简单的就是按下回车键唤醒屏幕我们在前面将 I.MX6U-ALPHA 开发板上的 KEY按键注册为了回车键因此按下开发板上的 KEY 按键即可唤醒屏幕。如果开发板上没有按键的话可以外接 USB 键盘然后按下 USB 键盘上的回车键唤醒屏幕。 关闭 10 分钟熄屏功能 在 Linux 源码中找到 drivers/tty/vt/vt.c 这个文件在此文件中找到 blankinterval 变量如下所示 179 static int vesa_blank_mode; 180 static int vesa_off_interval; 181 static int blankinterval 10*60; blankinterval 变量控制着 LCD 关闭时间默认是 10*60也就是 10 分钟。将 blankinterval的值改为 0 即可关闭 10 分钟熄屏的功能修改完成以后需要重新编译 Linux 内核得到新的 zImage然后用新的 zImage 启动开发板。 编写一个 APP 来关闭熄屏功能 在 ubuntu 中新建一个名为 lcd_always_on.c 的文件然后在里面输入如下所示内容 #include fcntl.h #include stdio.h #include sys/ioctl.hint main(int argc, char *argv[]) {int fd;fd open(/dev/tty1, O_RDWR);write(fd, \033[9;0], 8);close(fd);return 0; } 使用如下命令编译 lcd_always_on.c 这个文件 arm-linux-gnueabihf-gcc lcd_always_on.c -o lcd_always_on 编译生成 lcd_always_on 以后将此可执行文件拷贝到开发板根文件系统的/usr/bin 目录中然后给予可执行权限。设置 lcd_always_on 这个软件为开机自启动打开/etc/init.d/rcS在此文 件最后面加入如下内容 /usr/bin/lcd_always_on修改完成以后保存/etc/init.d/rcS 文件然后重启开发板即可。关于 Linux 下的 LCD 驱动我们就讲到这里。
http://www.zqtcl.cn/news/209953/

相关文章:

  • 码云pages做静态网站广西建设培训网
  • 建设网站需要花钱吗网站seo方案策划书
  • 德阳网站怎么做seo陈木胜个人资料
  • 电子规划书商务网站建设wordpress主机推荐
  • wordpress设置多站点html5开发手机app
  • 移动互联和网站开发哪个好做推广便宜的网站有哪些
  • 极速网站建设定制价格微信公众号运营助手
  • .net制作网站开发教程在线修图编辑器
  • 哪些网站可以做详情页聊城高新区建设局网站
  • 湖南网站优化代运营山东建设厅证件查询网址
  • 以百度云做网站空间浙江外贸网站建设
  • 南通网站建设推广专家wordpress 信息流 主题
  • 网站培训机构有哪些大学生做企业网站
  • 网站培训班有哪些课程做的好的大学生旅行有哪些网站好
  • 昌江县住房和城乡建设局网站佛山建设网站制作
  • 做网站 图片 文件夹 放哪儿北京模板网站建设
  • 网站制作公司哪家正规注册工程公司名称大全
  • 佛山微信网站建设哪家好做电商讲师课程的网站
  • 泰州城乡建设网站深圳logo设计公司哪家好
  • 东阳网站建设yw81wordpress登录注册页面梅花
  • 网站备案 厦门福州企业网站开发
  • 全国中小企业网站域名注册服务机构
  • 微信网站怎么做下载附件wordpress 代码执行
  • 5050众筹网站开发福州餐饮网站建设
  • 北京国家建设部网站网站备案需要去哪里
  • 廊坊哪里能够做网站网站改版影响
  • 比较好的源码网站手机网站支付如何制作
  • 深圳做网站哪个公司好重庆工程造价信息2021
  • 做电商宠物带哪个网站最好最近一周的重大新闻
  • 做网站难度李沧网站建设电话