赞
踩
今天开始学习下linux的定时器。
设备树还是沿用gpio的设备树。定义下led的结构体,这里追加了timeperiod和timer_list。
- #define TIMER_CNT 1
-
- #define TIMER_NAME "timer"
-
- #define CLOSE_CMD (_IO(0XEF, 0x1)) /* 关闭定时器 */
-
- #define OPEN_CMD (_IO(0XEF, 0x2)) /* 打开定时器 */
-
- #define SETPERIOD_CMD (_IO(0XEF, 0x3)) /* 设置定时器周期命令 */
-
-
-
-
-
- /* leddev设备结构体 */
-
- struct leddev_dev{
-
- dev_t devid; /* 设备号 */
-
- struct cdev cdev; /* cdev */
-
- struct class *class; /* 类 */
-
- struct device *device; /* 设备 */
-
- int major; /* 主设备号 */
-
- int minor;
-
- struct device_node *node; /* LED设备节点 */
-
- int led0; /* LED灯GPIO标号 */
-
- int timeperiod;
-
- struct timer_list timer;
-
- spinlock_t lock;
-
- };
-
-
-
- struct leddev_dev leddev; /* led设备 */
定义出口和入口函数
- /*
- * @description : 驱动模块加载函数
- * @param : 无
- * @return : 无
- */
-
- static int __init leddriver_init(void)
-
- {
-
- printk(" driver initial \r\n");
-
- return platform_driver_register(&led_driver);
-
- }
-
-
-
- /*
- * @description : 驱动模块卸载函数
- * @param : 无
- * @return : 无
- */
-
- static void __exit leddriver_exit(void)
-
- {
-
- printk(" driver exit \r\n");
-
- platform_driver_unregister(&led_driver);
-
- }
-
-
-
- module_init(leddriver_init);
-
- module_exit(leddriver_exit);
-
- MODULE_LICENSE("GPL");
-
- MODULE_AUTHOR("jinqijun");
-
接下来platform的probe的函数。这里追加了3个函数。
init_timer(&leddev.timer);
leddev.timer.function = timer_function; //回调函数
leddev.timer.data = (unsigned long)&leddev;
- static int led_probe(struct platform_device *dev)
-
- {
-
- printk("probe match\r\n");
-
- spin_lock_init(&leddev.lock);
-
- /* 1、设置设备号 */
-
- if (leddev.major) {
-
- leddev.devid = MKDEV(leddev.major, 0);
-
- register_chrdev_region(leddev.devid, TIMER_CNT, TIMER_NAME);
-
- } else {
-
- alloc_chrdev_region(&leddev.devid, 0, TIMER_CNT, TIMER_NAME);
-
- leddev.major = MAJOR(leddev.devid);
-
- }
-
-
-
- /* 2、注册设备 */
-
- cdev_init(&leddev.cdev, &led_fops);
-
- cdev_add(&leddev.cdev, leddev.devid, TIMER_CNT);
-
-
-
- /* 3、创建类 */
-
- leddev.class = class_create(THIS_MODULE, TIMER_NAME);
-
- if (IS_ERR(leddev.class)) {
-
- return PTR_ERR(leddev.class);
-
- }
-
-
-
- /* 4、创建设备 */
-
- leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, TIMER_NAME);
-
- if (IS_ERR(leddev.device)) {
-
- return PTR_ERR(leddev.device);
-
- }
-
-
-
- /* 5、初始化IO */
-
- leddev.node = of_find_node_by_path("/jin-gpio-led");
-
- if (leddev.node == NULL){
-
- printk("gpio node nost find!\r\n");
-
- return -EINVAL;
-
- }
-
- //三个参数,设备节点,设备数属性名称,个数
-
- leddev.led0 = of_get_named_gpio(leddev.node, "led-gpio", 0);
-
- printk("led0 register\r\n");
-
-
-
- if (leddev.led0 < 0) {
-
- printk("can't get led-gpio\r\n");
-
- return -EINVAL;
-
- }
-
-
-
- //使用IO,必须先申请 ,使用of_get_named_gpio获取GPIO的属性,led0给GPIO设置了名字
-
- gpio_request(leddev.led0, "jin-led0");
-
- gpio_direction_output(leddev.led0, 1); /* led0 IO设置为输出,默认高电平 */
-
-
-
- init_timer(&leddev.timer);
-
- leddev.timer.function = timer_function;
-
- leddev.timer.data = (unsigned long)&leddev;
-
- return 0;
-
- }
卸载函数,这里需要添加del_timer_sync.
- static int led_remove(struct platform_device *dev)
-
- {
-
- gpio_set_value(leddev.led0, 1); /* 卸载驱动的时候关闭LED */
-
- gpio_free(leddev.led0); /* 释放IO */
-
- del_timer_sync(&leddev.timer);
-
-
-
- cdev_del(&leddev.cdev); /* 删除cdev */
-
- unregister_chrdev_region(leddev.devid, TIMER_CNT); /* 注销设备号 */
-
- device_destroy(leddev.class, leddev.devid);
-
- class_destroy(leddev.class);
-
- printk(" remove \r\n");
-
- return 0;
-
- }
匹配列表,不需要修改。
- /* 匹配列表 */
-
- static const struct of_device_id match_tree[] = {
-
- { .compatible = "jin-gpio-led" },
-
- { /* Sentinel */ }
-
- };
-
-
-
- /* platform驱动结构体 */
-
- static struct platform_driver led_driver = {
-
- .driver = {
-
- .name = "12345", /* 驱动名字,用于和设备匹配 */
-
- .of_match_table = match_tree, /* 设备树匹配表 */
-
- },
-
- .probe = led_probe,
-
- .remove = led_remove,
-
- };
接下来编写app相关函数,timer_unlocked_ioctl函数里,可以修正定时器的参数。
timer_function就类似单片机的中断函数,会定时执行。
- static int led_open(struct inode *inode, struct file *filp)
-
- {
-
- printk(" led_open \r\n");
-
- filp->private_data = &leddev; /* 设置私有数据 */
-
- leddev.timeperiod = 1000;
-
- return 0;
-
- }
-
-
-
-
-
- static long timer_unlocked_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
-
- {
-
- struct leddev_dev *dev = (struct timer_dev *)filp->private_data;
-
- int timerperiod;
-
- unsigned long flags;
-
-
-
- switch(cmd){
-
- case CLOSE_CMD:
-
- del_timer_sync(&dev->timer);
-
- printk(" close cmd \r\n");
-
- break;
-
-
-
- case OPEN_CMD:
-
- spin_lock_irqsave(&dev->lock,flags);
-
- timerperiod = dev->timeperiod;
-
- spin_unlock_irqrestore(&dev->lock,flags);
-
- mod_timer(&dev->timer,jiffies + msecs_to_jiffies(timerperiod));
-
- printk(" open cmd \r\n");
-
- break;
-
-
-
- case SETPERIOD_CMD:
-
- spin_lock_irqsave(&dev->lock,flags);
-
- dev->timeperiod = arg;
-
- spin_unlock_irqrestore(&dev->lock, flags);
-
- mod_timer(&dev->timer, jiffies + msecs_to_jiffies(arg));
-
- printk(" set period cmd \r\n");
-
- break;
-
-
-
- default:
-
- break;
-
- }
-
-
-
- return 0 ;
-
- }
-
-
-
-
-
-
-
- /* 设备操作函数 */
-
- static struct file_operations led_fops = {
-
- .owner = THIS_MODULE,
-
- .open = led_open,
-
- .unlocked_ioctl = timer_unlocked_ioctl,
-
- };
-
-
-
- void timer_function(unsigned long arg)
-
- {
-
- struct leddev_dev *dev = (struct leddev_dev *)arg;
-
- static int sta = 1;
-
- int timerperiod;
-
- unsigned long flags;
-
-
-
- sta = !sta;
-
- gpio_set_value(dev->led0,sta);
-
- //printk(" time function \r\n");
-
- spin_lock_irqsave(&dev->lock,flags);
-
- timerperiod = dev->timeperiod;
-
- spin_unlock_irqrestore(&dev->lock,flags);
-
- mod_timer(&dev->timer,jiffies+msecs_to_jiffies(dev->timeperiod));
-
- }
以上为linux的定时器。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。