Chinaunix首页 | 论坛 | 博客
  • 博客访问: 385338
  • 博文数量: 81
  • 博客积分: 1290
  • 博客等级: 中尉
  • 技术积分: 821
  • 用 户 组: 普通用户
  • 注册时间: 2011-07-17 07:48
个人简介

Just do IT.

文章分类

全部博文(81)

分类:

2011-07-22 20:01:46

原文地址:Mini2440 LCD 点亮 作者:wangjianchangdx

启动阶段LCD点亮,并且通过配置bootargs,可以将启动信息在LCD上,打印出来。之后LCD熄灭。
原因分析:
① LCD可用,只是背光没打开
② LCD驱动配置错误

echo 1 > /dev/backlight,可以点亮背光。此时发现/dev目录下什么都没有。
查资料发现dev的需要使用到mdev,再查看自己的rcS,发现其中也调用了mdev。
为了确认,调出之前的启动信息,发现:“/etc/init.d/rcS: line 6: mdev: not found”

进入busybox目录,make menuconfig,发现其中确实没有配置mdev。
make && make install
mkfs.cramfs xxx cfamfs.img-mdev.4.0

烧录,OK,dev下出现了很多注册的设备。
悲剧的是其中没有backlight设备文件。这从一方面证明了背光驱动出了问题。


以下为过程之后的总结,由于过程拖的比较长,所以没有一点一点在评论中贴出:

启动的过程中,LCD变亮,并且如果console配置了tty0的话,可以看到LCD上,会有启动信息打印。然而随即LCD熄灭。此时按住复位键不放,发现LCD变量,其上的LOGO也显示出来:这说明了是背光的问题。

 

代码中,关于LCD的位置,最明显的在于,mini2440_init函数了。其中:

static void __init mini2440_init(void)

{

         struct mini2440_features_t features = { 0 };

         int i;

 

         printk(KERN_INFO "MINI2440: Option string mini2440=%s\n",

                            mini2440_features_str);

 

         /* Parse the feature string */

         mini2440_parse_features(&features, mini2440_features_str);   默认的特性为”0tb”,其中’b’代表backlight,打开背光

 

         /* turn LCD on */

         s3c_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND);  配置GPIO,开启LCD

 

         /* Turn the backlight early on */

         WARN_ON(gpio_request(S3C2410_GPG(4), "backlight"));

         gpio_direction_output(S3C2410_GPG(4), 1);           配置GPB4,也就是屏幕背光

 

         /* remove pullup on optional PWM backlight -- unused on 3.5 and 7"s */ 这段注释看不懂,不过下面的代码,把GPB1,配置成了输入口,

         s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_UP);        而非PWM timer1输出口。

         s3c2410_gpio_setpin(S3C2410_GPB(1), 0);

         s3c_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPIO_INPUT);

 

         /* Make sure the D+ pullup pin is output */

         WARN_ON(gpio_request(S3C2410_GPC(5), "udc pup"));

         gpio_direction_output(S3C2410_GPC(5), 0);

 

         /* mark the key as input, without pullups (there is one on the board) */

         for (i = 0; i < ARRAY_SIZE(mini2440_buttons); i++) {

                   s3c_gpio_setpull(mini2440_buttons[i].gpio, S3C_GPIO_PULL_UP);

                   s3c_gpio_cfgpin(mini2440_buttons[i].gpio, S3C2410_GPIO_INPUT);

         }

         if (features.lcd_index != -1) {        初始化LCD

                   int li;

 

                   mini2440_fb_info.displays =

                            &mini2440_lcd_cfg[features.lcd_index];

 

                   printk(KERN_INFO "MINI2440: LCD");

                   for (li = 0; li < ARRAY_SIZE(mini2440_lcd_cfg); li++)

                            if (li == features.lcd_index)

                                     printk(" [%d:%dx%d]", li,

                                               mini2440_lcd_cfg[li].width,

                                               mini2440_lcd_cfg[li].height);

                            else

                                     printk(" %d:%dx%d", li,

                                               mini2440_lcd_cfg[li].width,

                                               mini2440_lcd_cfg[li].height);

                   printk("\n");

                   s3c24xx_fb_set_platdata(&mini2440_fb_info);

         }

 

         s3c24xx_udc_set_platdata(&mini2440_udc_cfg);

         s3c24xx_mci_set_platdata(&mini2440_mmc_cfg);

         s3c_nand_set_platdata(&mini2440_nand_info);

         s3c_i2c0_set_platdata(NULL);

 

         i2c_register_board_info(0, mini2440_i2c_devs,

                                     ARRAY_SIZE(mini2440_i2c_devs));

 

         platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));

 

         if (features.count)   /* the optional features */

                   platform_add_devices(features.optional, features.count);

 

}

 

 

事实证明,LCD的配置是没有问题的,所以将焦点集中在背光之上。从上述代码的注释,以及在网上查询的资料中,都提到了PWM Backlight,于是乎搜寻PWM Backlight的资料;另外,检查配置,发现PWM Backlight配置正常,于是乎从代码入手,查看背光、PWM相关模块的代码。

 

第一个,对PWM背光的理解:

PWM控制LCD背光,LCD背光源有CCFLLED
PWM
LCD的关系并不大,PWM控制LED,只不过这个LED充当背光源的角色罢了。

PWM
输出控制LED的亮暗程度原理?
利用改51单片机的定时器PWM输出控制LED灯的亮暗程度,通过一个参数调节其占空比,比如第一次0/10不亮;1/9 很暗;第二次2/8.....,第九次9/1很亮;第十次,10/0完全亮。   小弟不明白的是:LED的亮暗由其电流和电压决定,所以1/9时的电压比9/1的电压电流高,但是这个电压或者电流怎么计算的了? 1/9不是只是代表其高低电平的时间之比吗? 怎么与LED的电压联系起来呢?

PWM的一个周期分成10块。
你说的1/9的意思是,这10块时间里,只有1块的时间让LED导通,剩下9块的时间里LED截止。假设PWM信号的幅值是5V,那么在导通的1块时间里LED电压的确是5V的,但是在剩下9块时间里,它的电压却是0V。也就是说从一个周期整体看来,LED的平均电压只有5*0.1+0*0.9=0.5V
PWM
信号频率很高的,我们无法通过肉眼来观察到每一个周期LED灯亮灭的变化过程,所以只好通过平均电压这样一种方式来决定这个LED的亮的程度了。

 

第二个,LCD相关的驱动代码在drivers/video,背光相关的在drivers/video/backlight。观察产生的.o文件,发现被编译了的有backlight.c/lcd.c/platform_lcd.c/pwm_bl.c

 

File

Init

description

Lcd.c

postcore_initcall

sysfs下创建lcd目录,另外,还有lcd_device_regist等函数

Platform_lcd.c

module_init

注册LCD driver

Backlight.c

postcore_initcall

sysfs下创建backlight目录,其中还有背光设备注册函数、亮度的调整函数

Pwm_bl.c

module_init

注册pwm backlight驱动

 

查看postcore_initcall(include/linux/init.h)的定义:

 

#define pure_initcall(fn)           __define_initcall("0",fn,0)

 

#define core_initcall(fn)            __define_initcall("1",fn,1)

#define core_initcall_sync(fn)          __define_initcall("1s",fn,1s)

#define postcore_initcall(fn)             __define_initcall("2",fn,2)

#define postcore_initcall_sync(fn)  __define_initcall("2s",fn,2s)

#define arch_initcall(fn)            __define_initcall("3",fn,3)

#define arch_initcall_sync(fn)          __define_initcall("3s",fn,3s)

#define subsys_initcall(fn)                 __define_initcall("4",fn,4)

#define subsys_initcall_sync(fn)      __define_initcall("4s",fn,4s)

#define fs_initcall(fn)                          __define_initcall("5",fn,5)

#define fs_initcall_sync(fn)               __define_initcall("5s",fn,5s)

#define rootfs_initcall(fn)                  __define_initcall("rootfs",fn,rootfs)

#define device_initcall(fn)                 __define_initcall("6",fn,6)

#define device_initcall_sync(fn)       __define_initcall("6s",fn,6s)

#define late_initcall(fn)             __define_initcall("7",fn,7)

#define late_initcall_sync(fn)           __define_initcall("7s",fn,7s)

 

#define __initcall(fn) device_initcall(fn)

 

******

 

#define module_init(x)     __initcall(x);

 

按顺序,postcore_initcall定义的函数,被存放在使用module_init定义的函数之前。

查看内核链接时生成的System.map文件,

__initcall_start

********

__early_initcall_end

********

__initcall_consistent_init1

__initcall_s3c2442_core_init1

__initcall_s3c2440_core_init1

__initcall_s3c24xx_gpiolib_init1

__initcall_s3c24xx_dma_sysclass_init1

__initcall_sysctl_init1

__initcall_ksysfs_init1

__initcall_async_init1

********

__initcall_lcd_class_init2

********

__initcall_pwm_backlight_init6

 

这些都会在start_kernel->rest_init->kernel_init->do_basic_setup-> do_initcalls,其中按顺序调用__initcall_start, __initcall_end之间的init函数。

 

综上,并没有发现对backlight的初始化配置部分。

 

再搜寻PWM配置部分,在arch/arm/plat-samsung/pwm.c中,有arch_initcall(pwm_init);定义的pwm_init函数。其中有对pwm driver的注册,驱动的probe函数中,有对pwm相关寄存器的配置。

 

返回mini2440_init函数,该函数被定义在mach_desc数据结构中。在start_kernel->setup_arch中,有init_machine = mdesc->init_machine; 在全代码树中搜索”init_machine”发现,就在setu_arch函数上,有一个customize_machine函数,其中调用init_machine函数,而customize_machine是使用arch_initcall(customize_machine);定义的。

 

现在解释另外一个问题,关于probe函数的调用时机问题,在各模块的init函数中,只是注册sys文件系统或注册驱动数据结构,绝非调用probe函数。跟踪platform_drive_register函数发现,在其中有对autoprobe的判断,如果是autoprobe的话,就会便利platform_bus上已挂载的设备链表,亦即调用probe函数。注册设备时,亦是如此。

 

由以上分析可知:

     pwm已被配置,backlight没被配置

     Mini2440_initpwm_blinit函数之前被调用

     Backlight被注册在sys目录下,也证实了网上搜集的资料

 

尝试着,修改mini2440_initGPB1的配置,将其修改为pwm timer1的输出。

 

/* remove pullup on optional PWM backlight -- unused on 3.5 and 7"s */

         /*s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_UP);

trace();

         s3c2410_gpio_setpin(S3C2410_GPB(1), 0);

trace();

         s3c_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPIO_INPUT);*/

         s3c_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPB1_TOUT1);

 

编译,烧写,运行

echo 1 > /sys/class/leds/backlight/brightness

LCD被点亮


之前LCD点亮之后又熄灭的原因,是驱动程序的初始化(pwm_bl.c中的pwm_backlight_probe函数)使然。

阅读(1728) | 评论(0) | 转发(0) |
0

上一篇:Linux内核移植

下一篇:用 GDB 调试程序

给主人留下些什么吧!~~