打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
利用用平台GPIO LED调试
摘自:  http://blog.csdn.net/hellowxwworld/article/details/11001739
如有侵权,敬请告知,谢谢。
GPIO 驱动的 LED 由于操作简单和可视化即可以在板上直接看到其闪烁时长和频率,我们可以通过LED这种特性用于调试开发过程当中各种情景, 如统计某个中断出发频率,某些在linux 内核比较难以调试的环境, 比如休眠唤醒模式, soc各种低功耗模式等环境, 这样即使在普通串口打印不能正常工作的环境,我们也可以利用LED辅助这些环境下的调试。

0 GPIO LED 设备驱动分析

区分于keyboard的led驱动(由input 子设备管理),GPIO LEDS使用led-clas驱动框架, 用户空间通过/sys/class/leds/board-led/ 访问led的各种属性,其中max_brightness  代表最大亮度,brightness代表亮度, 复杂的led  系统支持delay_{on,  off} 用来控制led交替闪烁哦的时长, trigger 用来触发led事件,例如开启关闭

配置内核CONFIG

  1. CONFIG_LEDS_GPIO=y  
  2. CONFIG_LEDS_TRIGGERS=y  

1 重要数据结构

  1. o 描述gpio led 设备结构  
  2. /* For the leds-gpio driver */  
  3. struct gpio_led {  
  4.     const char *name; // 每个led的名字  
  5.     const char *default_trigger;  // 指定默认触发源  
  6.     unsigned     gpio; // 控制led 的io pin  
  7.     unsigned    active_low : 1; // low 时为off  
  8.     unsigned    retain_state_suspended : 1;  // 休眠时是否保存状态,等到唤醒后恢复  
  9.     unsigned    default_state : 2; // 默认状态, 0:开, 1:关, 2:保持  
  10.     /* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */  
  11. };  
  12. o int led_classdev_register(); gpio led注册时会创建sys接口,由以下结构体控制  
  13. struct led_classdev {  
  14.     const char        *name;  
  15.     int             brightness; // 当前亮度  
  16.     int             max_brightness; // 最大亮度  
  17.     int             flags;  // 反映led状态  
  18.   
  19.     /* Lower 16 bits reflect status */  
  20. #define LED_SUSPENDED        (1 << 0)  
  21.     /* Upper 16 bits reflect control information */  
  22. #define LED_CORE_SUSPENDRESUME    (1 << 16)  
  23.   
  24.     /* Set LED brightness level */  
  25.     /* Must not sleep, use a workqueue if needed */  
  26.     void        (*brightness_set)(struct led_classdev *led_cdev,  
  27.                       enum led_brightness brightness); // 亮度设置回调  
  28.     /* Get LED brightness level */  
  29.     enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); // 亮度获取回调  
  30.   
  31.     /* 
  32.      * Activate hardware accelerated blink, delays are in milliseconds 
  33.      * and if both are zero then a sensible default should be chosen. 
  34.      * The call should adjust the timings in that case and if it can't 
  35.      * match the values specified exactly. 
  36.      * Deactivate blinking again when the brightness is set to a fixed 
  37.      * value via the brightness_set() callback. 
  38.      */  
  39.     int        (*blink_set)(struct led_classdev *led_cdev,  
  40.                      unsigned long *delay_on,  
  41.                      unsigned long *delay_off); // 硬件加速闪烁回调, 毫秒级别  
  42.   
  43.     struct device        *dev;  
  44.     struct list_head     node;            /* LED Device list */ // 每个led驱动加入双向循环链表管理  
  45.     const char        *default_trigger;    /* Trigger to use */ // 默认trigger, 一般设置为dummy  
  46.   
  47.     unsigned long         blink_delay_on, blink_delay_off; // blink delay  
  48.     struct timer_list     blink_timer; // 定时器实现 blink时长控制  
  49.     int             blink_brightness; //  闪烁亮度  
  50.   
  51. #ifdef CONFIG_LEDS_TRIGGERS  
  52.     /* Protects the trigger data below */  
  53.     struct rw_semaphore     trigger_lock;  // 读写信号量处理竞态  
  54.   
  55.     struct led_trigger    *trigger; // 事件触发结构体  
  56.     struct list_head     trig_list; // 触发源列表  
  57.     void            *trigger_data; // 数据pointer  
  58. #endif  
  59. };  
  60. o led事件触发回调  
  61. struct led_trigger {  
  62.     /* Trigger Properties */  
  63.     const char     *name; // 触发源  
  64.     void        (*activate)(struct led_classdev *led_cdev); //亮灯回调  
  65.     void        (*deactivate)(struct led_classdev *led_cdev); // 关灯回调  
  66.   
  67.     /* LEDs under control by this trigger (for simple triggers) */  
  68.     rwlock_t      leddev_list_lock; // 读写所,防止竟态  
  69.     struct list_head  led_cdevs; // 双向循环链表控制每个led的触发处理handler  
  70.   
  71.     /* Link to next registered trigger */  
  72.     struct list_head  next_trig; // 管理同个led的不同触发处理handler  
  73. }  

2 注册GPIO LEDS设备

  1. static struct gpio_led __initdata gpio_leds[] = {  
  2.     [0] = {  
  3.         .name = "gpio-led0",  
  4.         .default_trigger = "cpuidle",  
  5.         .gpio = LED_ID1,  
  6.         .active_low = true,  
  7.         .retain_state_suspended = false,  
  8.         .default_state = LEDS_GPIO_DEFSTATE_OFF,  
  9.     },  
  10.     [1] = {  
  11.         .name = "gpio-led1",  
  12.         .default_trigger = "mmc",  
  13.         .gpio = LED_ID2,  
  14.         .active_low = true,  
  15.         .retain_state_suspended = true,  
  16.         .default_state = LEDS_GPIO_DEFSTATE_OFF,  
  17.     },  
  18.     ret = gpio_led_register_device(-1, &gpio_led); // 注册gpio leds设备  
  19.         -> ret = platform_device_register_resndata();  // 注册gpio leds设备  
  20.   
  21.   
  22. driver probe  
  23.     gpio_led_probe() // 驱动加载后probe  
  24.         -> create_gpio_led() // 申请gpio, 初始化设备并且填充上述相关回调  
  25.             -> gpio_request()  
  26.             -> gpio_direction_output()  
  27.             -> INIT_WORK(&led_dat->work, gpio_led_work) // 使用工作队列处理例如闪烁,开关等事件  
  28.             -> led_classdev_register(parent, &led_dat->cdev); // 建立sys接口,提供用户空间控制度  

2 调试时只需用到led的开关足以,无需blink闪烁的功能

o 用于调试低功耗
定义不同低功耗模式的各个led,在cpu进入idle, aftr和lpa模式后就会点亮对应的leds,退出以后就会关闭相应的leds,四个cpu每个对应一个led,aftr和lpa各用一个,一共6个。
根据上述驱动配置,具体的对应关系如下:
调试对象        LED灯编号
AFTR            gpio-led0
LPA                gpio-led5
CPU0 IDLE:        gpio-led2
CPU1~3 IDLE        分别对应其他的三个LEDS

可以按照以下步骤利用led调试
o 以dummy为例,定义一个led trigger
  1. DEFINE_LED_TRIGGER(dummy_led_trigger)  
o 绑定该led trigger到驱动中的那个leds灯
  1. led_trigger_register_simple("dummy", &cpuidle_led_trigger);  
o 通过开、关led灯来定义某个dummy问题的原因
比如说,我们怀疑某个驱动中某一个操作有问题,那么可以在前后加上点灯和灭灯的动作,如果这个操作导致系统挂起,那led等点亮后就不会灭掉,因而可以用来确认问题的位置,例如:
  1. led_trigger_event(aftr_led_trigger, LED_FULL);  
  2. /* Some potentially problematic operations */  
  3. led_trigger_event(aftr_led_trigger, LED_OFF);  
  4.     -> led_set_brightness()  
  5.         -> gpio_set_value();  
3 更简单用法
直接封装gpio的操作已达到操作led亮灭的目的
  1. void led1_on() {  
  2.     s3c_gpio_cfgpin(LED_ID1, S3C_GPIO_OUTPUT);  
  3.     s3c_gpio_setpull(LED_ID1, S3C_GPIO_PULL_NONE);  
  4.     gpio_set_value(LED_ID1, 1);  
  5. }  
  6. void led1_off() {  
  7.     s3c_gpio_cfgpin(LED_ID1, S3C_GPIO_OUTPUT);  
  8.     s3c_gpio_setpull(LED_ID1, S3C_GPIO_PULL_NONE);  
  9.     gpio_set_value(LED_ID1, 0);  
  10. }  


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
linux设备驱动之led子系统<一>
LED子系统中的硬件驱动层
Linux 虚拟文件系统sysfs之属性文件attribute 整理(一)
Linux内核的LED设备驱动框架【转】
如何使用AM6254的GPIO?
linux GPIO驱动
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服