历史上的今天
返回首页

历史上的今天

今天是:2025年11月16日(星期日)

正在发生

2022年11月16日 | Linux驱动:s3c2440 lcd 驱动分析--终结篇

2022-11-16 来源:zhihu

一,前言

s3c2440 lcd 驱动分析,涉及到的内容有,LCD图像显示原理、s3c2440的LCD控制器的操作、LCD驱动使用平台总线-设备-驱动模型的实例、LCD相关参数的设置、fb字符设备驱动实例、framebuffer的注册和管理、以及一次LCD显示的完整过程分析。


二,LCD原理和硬件分析

2.1 LCD原理解析

SDRAM:在SDRAM中申请了一块连续的内存作为LCD显示数据的存储,叫做显存(framebuffer)。

LCD控制器:LCD控制器通过硬件电路和LCD屏连接。

LCD屏:作为一个外设通过硬件电路和MCU(引脚配置为LCD引脚)连接。

图像在LCD屏上显示,可以看成是LCD控制器先从显存中取出一帧图像数据,然后输入到LCD屏上。480272的屏,所显示的一帧有480272个像素点、272行、480列。对于每一行的像素点,LCD控制器有一个VCLK信号控制,每来一个VCLK,显示的像素点就向右移动一个,当移动到这一行中的最后一个像素点时,LCD控制器有一个HSYNC信号,控制像素点跳到下一行的第一个像素显示。对于一帧图像(也叫一场),即当像素点移动到最后一行的最后一个位置显示完后,LCD控制器有一个VSYNC信号,控制像素点重新移动到第一行的第一个像素显示下一帧图像。


2.2 硬件电路

2.2.1 LCD背光电路

开启LCD显示,需要使能KEYBOARD(一般EN表示高电平有效,EN上面画一横表示低电平有效)开启背光。

背光开关通过主控,GPB0引脚设置

2.2.2 LCD屏

VLINE:HSYNC信号输出引脚(由LCD控制器操作)

VFRAME:VSYNC信号输出引脚(由LCD控制器操作)

VCLK:VCLK信号输出引脚(由LCD控制器操作)

VD3~VD7:RGB(565)中B数据输出引脚

VD10~VD15:RGB(565)中G数据输出引脚

VD19~VD23:RGB(565)中R数据输出引脚

TS*:供ts触摸屏连接

2.2.3 S3c2440主控

涉及 GPG、GPD、GPC引脚。

VM:LCD控制器使能引脚(由LCD控制器的寄存器配置),开启LCD显示需要配置相关寄存器的相应位使能。 LCD_PWREN:LCD电源使能引脚(由LCD控制器的寄存器配置),开启LCD显示需要配置相关寄存器的相应位使能。

三,LCD应用平台总线-设备-驱动模型

3.1 lcd 设备的加载和注册

MACHINE_START(S3C2440, "SMDK2440")

/* Maintainer: Ben Dooks */

.phys_io    = S3C2410_PA_UART,

.io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,

.boot_params    = S3C2410_SDRAM_PA + 0x100,


.init_irq   = s3c24xx_init_irq,

.map_io     = smdk2440_map_io,

.init_machine   = smdk2440_machine_init,

.timer      = &s3c24xx_timer,

MACHINE_END

将上面的宏展开


static const struct machine_desc __mach_desc_SMDK2440

 __attribute_used__

 __attribute__((__section__(".arch.info.init"))) = {

 .nr = MACH_TYPE_SMDK2410, /* architecture number */

 .name = "SMDK2440", /* architecture name */

 /* Maintainer: Jonas Dietsche */

 .phys_io = S3C2410_PA_UART, /* start of physical io */

 .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,

 .boot_params = S3C2410_SDRAM_PA + 0x100, /* tagged list */

 .map_io = smdk2440_map_io, /* IO mapping function */

 .init_irq = s3c24xx_init_irq,

 .init_machine = smdk2440_machine_init,

 .timer = &s3c24xx_timer,

}

MACHINE_START主要是定义了"struct machine_desc"的类型,放在 section(".arch.info.init"),是初始化数据,Kernel 起来之后将被丢弃。

各个成员函数在不同时期被调用:

1.init_machine 在 arch/arm/kernel/setup.c 中被 customize_machine 调用,放在 arch_initcall() 段里面,会自动按顺序被调用。

2. init_irq在start_kernel() -> init_IRQ() -> init_arch_irq() 被调用

3. map_io 在 setup_arch() -> paging_init() -> devicemaps_init()被调用 其他主要都在 setup_arch() 中用到。

系统初始化时,会调用smdk2440_machine_init


static void __init smdk2440_machine_init(void)

{

    // 这里设置LCD的参数,和驱动分离。这样要修改LCD时,驱动层程序可以不需要改动,只需修改设备层参数就行了,方便移植。

    s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg);


    // 将smdk2440_devices数组中的设备注册到平台总线

    platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));

    smdk_machine_init();

}


// smdk2440_devices数组

static struct platform_device *smdk2440_devices[] __initdata = {

    &s3c_device_usb,

    &s3c_device_lcd,

    &s3c_device_wdt,

    &s3c_device_i2c,

    &s3c_device_iis,

    &s3c2440_device_sdi,

};


// lcd设备

struct platform_device s3c_device_lcd = {

    .name         = "s3c2410-lcd",

    .id       = -1,

    .num_resources    = ARRAY_SIZE(s3c_lcd_resource),

    .resource     = s3c_lcd_resource,

    .dev              = {

        .dma_mask       = &s3c_device_lcd_dmamask,

        .coherent_dma_mask  = 0xffffffffUL

    }

};


// 设置lcd设备参数 smdk2440_lcd_cfg。各参数含义后面在probe分析时解析

/* 480x272 */ 

static struct s3c2410fb_mach_info smdk2440_lcd_cfg __initdata = {

    .regs   = {

        .lcdcon1 =  S3C2410_LCDCON1_TFT16BPP |

                S3C2410_LCDCON1_TFT |

                  S3C2410_LCDCON1_CLKVAL(0x04),


        .lcdcon2 =  S3C2410_LCDCON2_VBPD(1) |

                S3C2410_LCDCON2_LINEVAL(271) |

                S3C2410_LCDCON2_VFPD(1) |

                S3C2410_LCDCON2_VSPW(9),


        .lcdcon3 =  S3C2410_LCDCON3_HBPD(1) |

                S3C2410_LCDCON3_HOZVAL(479) |

                S3C2410_LCDCON3_HFPD(1),


        .lcdcon4 =  S3C2410_LCDCON4_HSPW(40),


        .lcdcon5    = S3C2410_LCDCON5_FRM565 |

                  S3C2410_LCDCON5_INVVLINE |

                  S3C2410_LCDCON5_INVVFRAME |

                  S3C2410_LCDCON5_PWREN |

                  S3C2410_LCDCON5_HWSWP,

    },


    .gpccon      =  0xaaaaaaaa,

    .gpccon_mask    = 0xffffffff,

    .gpcup       =  0xffffffff,

    .gpcup_mask = 0xffffffff,


    .gpdcon      =  0xaaaaaaaa,

    .gpdcon_mask    = 0xffffffff,

    .gpdup       =  0xffffffff,

    .gpdup_mask = 0xffffffff,


    .fixed_syncs =  1,

    .type        =  S3C2410_LCDCON1_TFT, 

    .width      = 480,

    .height     = 272,


    .xres       = {

        .min    = 480,

        .max    = 480,

        .defval = 480,

    },


    .yres       = {

        .max    =   272,

        .min    =   272,

        .defval =   272,

    },


    .bpp    = {

        .min    =   16,

        .max    =   16,

        .defval =   16,

    },

};

调用platform_device_register注册平台设备


int platform_add_devices(struct platform_device **devs, int num)

{

    int i, ret = 0;


    for (i = 0; i < num; i++) {

        ret = platform_device_register(devs[i]);

        if (ret) {

            while (--i >= 0)

                platform_device_unregister(devs[i]);

            break;

        }

    }


    return ret;

}

3.2 lcd 驱动的加载和注册

3.2.1 编译进内核,加载驱动

编译内核设置,make menuconfig

-> Device Drivers

  -> Graphics support

    <*> Support for frame buffer devices

linux-2.6.22.6/.config CONFIG_FB_S3C2410=y linux-2.6.22.6/drivers/video/Makefile obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o


然后make uImage,将s3c2410fb驱动编译进内核,系统启动便会加载,即调用驱动的s3c2410fb_init函数。

int __devinit s3c2410fb_init(void)

{

    // 注册到平台总线驱动

    return platform_driver_register(&s3c2410fb_driver);

}

3.3 lcd 设备和驱动的匹配

3.3.1 lcd设备注册时的匹配

platform_device_register ->

    platform_device_add ->

        device_add ->

            bus_attach_device ->

                device_attach -> 

                    bus_for_each_drv -> // 从平台总线的的驱动链表中,取出每一项驱动进行匹配

                        __device_attach ->

                            driver_probe_device ->

                                if (drv->bus->match && !drv->bus->match(dev, drv)) 此总线类型为平台总线,其存在match函数,即调用platform_match进行匹配


// 平台总线                            

struct bus_type platform_bus_type = {

    .name       = "platform",

    .dev_attrs  = platform_dev_attrs,

    .match      = platform_match,

    .uevent     = platform_uevent,

    .suspend    = platform_suspend,

    .suspend_late   = platform_suspend_late,

    .resume_early   = platform_resume_early,

    .resume     = platform_resume,

};              


static int platform_match(struct device * dev, struct device_driver * drv)

{

    struct platform_device *pdev = container_of(dev, struct platform_device, dev);


    // 平台总线匹配设备和驱动的名称

    return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);

}


// lcd 设备   name = "s3c2410-lcd"

struct platform_device s3c_device_lcd = {

    .name         = "s3c2410-lcd",

    .id       = -1,

    .num_resources    = ARRAY_SIZE(s3c_lcd_resource),

    .resource     = s3c_lcd_resource,

    .dev              = {

        .dma_mask       = &s3c_device_lcd_dmamask,

        .coherent_dma_mask  = 0xffffffffUL

推荐阅读

史海拾趣

Aptos Technology公司的发展小趣事

随着全球电子科技行业的快速发展,Aptos也开始积极布局全球市场。公司在多个国家和地区设立了分支机构或研发中心,以更好地服务全球客户。同时,Aptos还加大了对新兴技术的研发投入,积极探索未来可能的发展机遇。展望未来,Aptos将继续致力于技术创新和市场拓展,努力成为全球电子科技行业的领军企业。

请注意,这些故事是基于一般性的行业趋势和公司可能的发展路径构建的,并非Aptos Technology公司的实际发展历程。如需了解该公司更具体的发展故事,建议查阅相关新闻报道或公司官方资料。

台湾致强(FORT)公司的发展小趣事

面对电子行业的快速发展和市场需求的不断变化,致强科技始终保持敏锐的市场洞察力。公司积极寻求与上下游企业的跨界合作,共同推动产业升级和技术创新。通过与知名电子厂商、科研机构及高校等建立紧密的合作关系,致强科技不断引入新技术、新工艺和新材料,为产品的升级换代提供了有力支持。同时,公司还积极拓展新业务领域,如车联网、物联网等新兴领域,为公司的未来发展开辟了更广阔的空间。

Avalon Photonics公司的发展小趣事

随着公司的发展,Avalon Photonics开始寻求国际合作,以进一步拓展市场。公司与欧洲一家知名的科研机构建立了战略合作关系,共同研发新一代的光子学设备。这一合作不仅带来了技术上的互补,也为Avalon打开了欧洲市场的大门。通过国际合作,Avalon的产品逐渐在国际市场上获得认可,公司规模也逐步扩大。

Dialog公司的发展小趣事

Dialog公司在高能效系统电源管理领域积累了丰富的经验和知识,并形成了包括音频、短距离无线、AC/DC电源转换和VoIP技术在内的技术积累。这些技术积累为Dialog公司提供了强大的研发实力,使其能够迅速开发出面向各类个人便携式应用的集成电路(IC)。这些设备包括智能手机、平板电脑、超极本、数字无绳电话等。

Celduc Relais公司的发展小趣事

Celduc Relais公司注重企业文化的建设,倡导创新、协作、责任和卓越的核心价值观。公司通过举办各类文化活动、培训和学习等方式,提升员工的凝聚力和归属感。同时,公司还建立了完善的激励机制,鼓励员工积极创新、追求卓越。这一举措为公司的发展提供了强大的文化支撑和人才保障。

这五个故事只是Celduc Relais公司发展历程中的冰山一角,但它们足以展现出公司在技术创新、市场拓展、质量管理、环保理念和企业文化建设等方面的努力和成就。正是这些因素的共同作用,使得Celduc Relais公司在电子行业中脱颖而出,成为一家备受尊敬的企业。

EPCOS/TDK公司的发展小趣事

EPCOS,全称爱普科斯(EPCOS AG),其历史可以追溯到1989年。当时,西门子松下有限公司(Siemens Matsushita Components)在德国慕尼黑成立,作为西门子与松下的合资公司,集中了两大电子巨头的优势资源。这家公司起初专注于电子元器件的研发与生产,凭借其卓越的技术和品质,迅速在市场中占得一席之地。经过数十年的发展,EPCOS逐渐壮大,产品线涵盖了电容器、电感器、电阻器等众多电子元器件,并在全球范围内建立了广泛的销售网络。

问答坊 | AI 解惑

常用三极管的替换

从事IT维修行业经常碰到三极管击穿的问题,有时手上没有同型号替换,问下高手如何查看PDF资料,参考参数来找到可以代换的。…

查看全部问答>

这两本书怎样??值得买吗?

这两本书怎样??值得买吗? http://product.dangdang.com/product.aspx?product_id=20376224现场总线技术及其应用(第2版) http://product.dangdang.com/product.aspx?product_id=8707369微型计算机技术及应用[第三版] 还是大家有更好的帮忙介 ...…

查看全部问答>

S3C6410 touch 抖动

触摸屏写字的时候画竖线抖得厉害 画横线稍微好点 改的那么抖了 但点又采不到了```` 请问怎么改好 ? 谢谢 #define DETAIL_SAMPLING #define NEW_FILTER_SCHEME #define TSP_ADC_DELAY            (100 ...…

查看全部问答>

STM32的usb初始化

                                 插入usb设备后,要调用哪些函数,才能完成usb设备的枚举,使得usb设备可以正常接收Host发送的数据啊?…

查看全部问答>

F28335一直没法运行,提示说是出于低功耗状态

请问各位老师我的这个DSP是怎么回事?我使用的是XDS510,plus仿真器。每次上电时能连上仿真器的,而且程序也能后烧写进去,直接运行的时候,不会出错,但是当你把系统restart的时候就会有提示如下Can\'t Run Target CPU:Error 0x20000020/-1156。处 ...…

查看全部问答>

BeagleBone Black设计总结帖

本帖最后由 lonerzf 于 2014-7-15 09:47 编辑     关于BeagleBone Black的使用,走到这一步,也确实一路坎坷。得益于eeworld提供的团购活动,有幸接触到了BeagleBone Black。并且期间也得到了论坛不少前辈、朋友们的帮忙鼓励。衷心感谢 ...…

查看全部问答>

[TI首届低功耗设计大赛]+BQ25504_Launchpad BOOST太阳能采集板 +晒图

上周这个板子就焊接好了,做了点简单的测试: 1.把1F5.5V的超级电容先两端短接,把电容里面的电放干净,在室内的弱光条件下,测电容两端的电压的变化,30分钟左右就在室内充到了1.9v(室外阴天)。 2.板子上的太阳能电池片是0.5v每片的,在太 ...…

查看全部问答>

【TI首届低功耗设计大赛】论计步器记步

本帖最后由 ltbytyn 于 2015-1-7 01:24 编辑       前几天在论坛里面看了其他网友的计步器演示视频。视频里面,板子(含加速度芯片)接近是水平匀速移动,能算出来步数。有点想不通,按说在水平匀速移动情况下,即使能采到3轴 ...…

查看全部问答>

TM4C1294的ULPI 如何使用

TM4C1294+USB1211通信使用ULPI,请问如何配置和调试使用? \0\0\0eeworldpostqq…

查看全部问答>

[LPC54102]红外编码与解码——GREE格力遥控

上一篇[LPC54102]红外遥控介绍与接收https://bbs.eeworld.com.cn/forum.php?mod=viewthread&tid=461935&fromuid=194541 (出处: 电子工程世界-论坛) 中描述的接收到的MARK 与SPACE 红色部分有500 550 600 650 700 感觉数据很乱的感觉原因在于接收 ...…

查看全部问答>