历史上的今天
返回首页

历史上的今天

今天是: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屏上。480*272的屏,所显示的一帧有480*272个像素点、272行、480列。对于每一行的像素点,LCD控制器有一个VCLK信号控制,每来一个VCLK,显示的像素点就向右移动一个,当移动到这一行中的最后一个像素点时,LCD控制器有一个HSYNC信号,控制像素点跳到下一行的第一个像素显示。对于一帧图像(也叫一场),即当像素点移动到最后一行的最后一个位置显示完后,LCD控制器有一个VSYNC信号,控制像素点重新移动到第一行的第一个像素显示下一帧图像。


2.2 硬件电路

2.2.1 LCD背光电路

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


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 设备和驱动的匹配

platform_driver_register->

    driver_register->

        bus_add_driver->

            driver_attach->

                bus_for_each_dev->

                    __driver_attach

__driver_attach(kernel 2.6.22)

static int __driver_attach(struct device * dev, void * data)

{

    struct device_driver * drv = data;


    /*

     * Lock device and try to bind to it. We drop the error

     * here and always return 0, because we need to keep trying

     * to bind to devices and some drivers will return an error

     * simply if it didn't support the device.

     *

     * driver_probe_device() will spit a warning if there

     * is an error.

     */


    if (dev->parent)    /* Needed for USB */

        down(&dev->parent->sem);

    down(&dev->sem);

    if (!dev->driver)

        driver_probe_device(drv, dev); // 调用驱动层程序的 probe函数

    up(&dev->sem);

    if (dev->parent)

        up(&dev->parent->sem);


    return 0;

}

__driver_attach(kernel 3.4)

static int __driver_attach(struct device *dev, void *data)

{

    struct device_driver *drv = data;


    /*

     * Lock device and try to bind to it. We drop the error

     * here and always return 0, because we need to keep trying

     * to bind to devices and some drivers will return an error

     * simply if it didn't support the device.

     *

     * driver_probe_device() will spit a warning if there

     * is an error.

     */


    // 匹配驱动和设备

    if (!driver_match_device(drv, dev))

        return 0;


    if (dev->parent)    /* Needed for USB */

        device_lock(dev->parent);

    device_lock(dev);

    if (!dev->driver)

        driver_probe_device(drv, dev);

    device_unlock(dev);

    if (dev->parent)

        device_unlock(dev->parent);

推荐阅读

史海拾趣

Hirschmann公司的发展小趣事
虽然TC4013的时钟频率不是直接决定延时时间的因素,但它会影响定时器的触发频率和输出信号的周期。通过调整时钟信号的频率,可以在一定程度上改变输出信号的周期或占空比,从而间接影响定时电路的延时效果。然而,这种方法通常用于调整输出信号的频率特性,而非直接调整延时时间。
Heatron LED Integration公司的发展小趣事

随着LED照明市场的不断扩大,Heatron LED Integration凭借敏锐的市场洞察力,迅速调整市场战略。公司不仅巩固了在国内市场的领先地位,还积极开拓国际市场,与多家国际知名企业建立了长期合作关系。通过参加国际展会、设立海外分支机构等方式,公司成功将产品推向全球多个国家和地区,实现了品牌的国际化。

ETA-USA公司的发展小趣事

ETA-USA公司起源于XXXX年,当时由几位电子工程领域的先驱者在美国密歇根州的Troy市创立了这家专注于电子技术和解决方案的公司。初创时期,ETA-USA面临着技术挑战、资金短缺和市场竞争激烈等多重困难。然而,通过不断创新和提供高质量的工程服务,公司逐渐在电子行业崭露头角,赢得了客户的信任。

GE公司的发展小趣事

进入XXXX年代,ETA-USA开始将重心转向CAE(计算机辅助工程)软件的开发。公司投入大量资源进行研发,成功推出了一系列创新的CAE软件解决方案,如Dynaform,这些软件在覆盖件冲压成形、汽车碰撞模拟等领域取得了显著的应用效果。这一突破不仅巩固了ETA-USA在电子工程领域的地位,也为其后续发展奠定了坚实的基础。

APX Technologies公司的发展小趣事

为了进一步提升公司实力,APX Technologies开始拓展海外市场。公司在多个国家和地区设立了分支机构,并积极招聘当地的优秀人才。通过不断的努力,APX Technologies的产品逐渐在国际市场上占据了一席之地,公司的规模和影响力也不断扩大。

COMPEX公司的发展小趣事

COMPEX公司自成立以来,一直致力于电子技术的研发与创新。在光通讯领域,公司凭借先进的光通讯模块电路板小器件技术,逐渐在市场中占据了一席之地。COMPEX团队不断突破技术壁垒,推出了多款高性能、高可靠性的产品,赢得了客户的广泛认可。同时,公司还积极与国内外知名企业和研究机构合作,共同推动电子行业的技术进步。

问答坊 | AI 解惑

IDT将蓬勃发展的中国半导体市场作为加速信息包处理发展策略的重要部分

IDT将蓬勃发展的中国半导体市场作为加速信息包处理发展策略的重要部分 IDT的产品将促进中国电信基础设施技术建设的跨越发展,并在全球电信市场中发挥重要作用 2004-04-26     全球领先的通信集成电路供应商——IDT公司计划进一步 ...…

查看全部问答>

CCS's autocomplete function (这个功能的使用你知道吗)

要使这个功能有用,写寄存器的时候须同时打开定义的.h文件。如果定CpuTimer0Regs,则要打开CPUtimers.h …

查看全部问答>

wince 可是识别网卡 但是从台式机不能ping到开发板

我的开发板是用cf卡的网卡,在wince中可以识别出是ne2000的网卡,并且也在网络设置那地方识别出了网卡,但是从台式机上ping开发板就是ping不通  是怎么回事啊…

查看全部问答>

PDA上可以做为网络通讯的server端吗??为什么我试过都不行

我想在PDA上开发一个程序用来跟PC机进行通讯,结果发现PDA上无法作为服务端,只能做为客户端?这是为什么? 我用的开发工具是VS.NET 2003,POCKET PC模拟器…

查看全部问答>

求助,有关MODBUS协议的问题,请路人指教

我预通过R485串口读取一个装置的数据,数据是以MODBUS的协议进行传输的,请问,我该如何去读取,麻烦高人给个详细的解答。小弟在此学习了,谢谢。…

查看全部问答>

一起来看看植在树上的LED红绿灯

    红绿灯也叫交通信号灯,是一种在大城市里每天维护交通秩序的重要工具之一。但或许是现有的交通信号灯存在不少缺陷,抑或是对未来交通信号灯美好的憧憬,设 计师们对交通信号灯做了一次又次的重新设计。这款由设计师Gisung Han, ...…

查看全部问答>

stm32f101仿真器时停不下来

不知道是哪错了~ 我在用JLINK仿真stm32f101的时候,发现点问题~ 可以烧写程序~进入主程序后~可以单步执行,可以运行到断点处~ 但是只要没有断点,全速运行后,点stop 停下来的时候 程序就自动关掉了~就报下面的这个错误(如图)~ 知道什么 ...…

查看全部问答>

如何把八位二进制数转为十进制数并用七段显示译码器输出

如题,求高手指点,能给出所用器件或电路图的更佳,先在此言谢…

查看全部问答>

【已换】两块LPC1227想换一块STM32F429

本帖最后由 wsdymg 于 2014-5-28 10:51 编辑 已换…

查看全部问答>