linux的内核延时包括短延时,长延时以及休眠延时。 1.1.1 短延时Linux内核中提供了如下3个函数分别进行纳秒、微秒和毫秒延迟。 - void ndelay(unsigned long nsecs);
- void udelay(unsigned long usecs);
- void mdelay(unsigned long msecs);
复制代码上述延迟的实现原理本质上是忙等待,它根据CPU频率进行一定次数的循环。在单片机程序中,经常见到如下的延时函数: - void delay(unsigned int i,j)
- {
- for(i=0;i<255;i++)
- for(j=0;j<255,j++);
- }
复制代码ndelay()、udelay()和 mdelay()函数的实现方式机理与此类似。毫秒相对内核来说已经很大了,在进行毫秒延时时,不推荐使用这种忙等待的方式延时。 1.1.2 长延时内核中进行延迟的一个很直观的方法是比较当前的jiffies和目标jiffies(设置为当前 jiffies加上时间间隔的jiffies),直到未来的jiffies达到目标jiffies。 jiffies是一个全局变量,用来记录自系统启动以来产生的节拍的总数,它反应了系统所运行的时间。启动时,内核将该变量初始化为0,此后,每次时钟中断处理程序都会增加该变量的值。一秒内时钟中断的次数等于HZ,所以jiffies一秒内增加的值也就是Hz。 系统运行时间以秒为单位,等于jiffies/HZ。注意,jiffies类型为无符号长整型(unsigned long),其他任何类型存放它都不正确。 将以秒为单位的时间转化为jiffies: 将jiffies转化为以秒为单位的时间: 相比之下,内核中将秒转换为jiffies用的多些。 以下程序表示延时100个jiffies: - <span style="line-height: 1.5;">unsigned long delay = jiffies + 100;</span>
- while (time_before(jiffies, delay));
复制代码以下程序表示延时2秒: - unsigned long delay = jiffies + 2*HZ;
- while (time _ before(jiffies, delay));
复制代码 1.1.3 休眠延时休眠延时指在进程调用延时期间主动进入睡眠状态,CPU被其他进程使用。对于毫秒级以上的延时,推荐使用休眠延时,内核提供了以下几个函数: - void msleep(unsigned int millisecs);
- unsigned long msleep_interruptible(unsigned int milosecs);
- void ssleep(unsigned int seconds);
复制代码 1.1.4 内核延时示例编写一个驱动模块,通过不同的延时方式,控制蜂鸣器间隔鸣叫。 在kernel/drivers/char/x4412目录下新建x4412-delay.c文件,参考代码如下: - #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/fs.h>
- #include <linux/uaccess.h>
- #include <linux/timer.h>
- #include <linux/jiffies.h>
- #include <linux/delay.h>
- #include <linux/sched.h>
- #include <linux/kthread.h>
- #include <linux/gpio.h>
- #include <plat/gpio-cfg.h>
- static void x4412_beep_init(void)
- {
- int ret;
- ret = gpio_request(EXYNOS4_GPD0(1), "GPD0(1)");
- if(ret)
- printk("x4412-beep: request gpio GPD0(1) fail\n");
- s3c_gpio_setpull(EXYNOS4_GPD0(1), S3C_GPIO_PULL_UP);
- s3c_gpio_cfgpin(EXYNOS4_GPD0(1), S3C_GPIO_SFN(1));
- gpio_set_value(EXYNOS4_GPD0(1), 0);
- }
- static int thread_process(void* param)
- {
- unsigned long delay;
- while(1)
- {
- set_current_state(TASK_UNINTERRUPTIBLE);
- if(kthread_should_stop())
- {
- printk("kernel thread should stop;file:%s;line:%d\n", __FILE__, __LINE__);
- break;
- }
- //滴
- mdelay(5*HZ);
- gpio_set_value(EXYNOS4_GPD0(1), 1);
- mdelay(1*HZ);
- gpio_set_value(EXYNOS4_GPD0(1), 0);
- //滴滴
- delay = jiffies + 2*HZ;
- while(time_before(jiffies,delay));//延时2s
- gpio_set_value(EXYNOS4_GPD0(1), 1);
- mdelay(100);//延时100000us,即100ms
- gpio_set_value(EXYNOS4_GPD0(1), 0);
- mdelay(100);//延时100ms
- gpio_set_value(EXYNOS4_GPD0(1), 1);
- msleep_interruptible(100);//延时100ms
- gpio_set_value(EXYNOS4_GPD0(1), 0);
- //滴滴滴
- mdelay(5*HZ);
- gpio_set_value(EXYNOS4_GPD0(1), 1);
- mdelay(100);
- gpio_set_value(EXYNOS4_GPD0(1), 0);
- mdelay(100);
- gpio_set_value(EXYNOS4_GPD0(1), 1);
- mdelay(100);
- gpio_set_value(EXYNOS4_GPD0(1), 0);
- mdelay(100);
- gpio_set_value(EXYNOS4_GPD0(1), 1);
- mdelay(100);
- gpio_set_value(EXYNOS4_GPD0(1), 0);
- }
- return 1;
- }
- static struct task_struct* x4412_thread = NULL;
- static int __init x4412_second_init(void)
- {
- int err = 0;
- x4412_beep_init();
- x4412_thread = kthread_create(thread_process, NULL, "x4412_thread");
- if(IS_ERR(x4412_thread))
- {
- err = PTR_ERR(x4412_thread);
- x4412_thread = NULL;
- printk(KERN_ERR "unable to start kernel thread:%d\n", err);
- return err;
- }
- wake_up_process(x4412_thread);
- printk("x4412 kernel thread start;file:%s;line:%d\n", __FILE__, __LINE__);
- return 0;
- }
- static void x4412_second_exit(void)
- {
- int ret = -1;
- if(x4412_thread)
- {
- ret = kthread_stop(x4412_thread);
- x4412_thread = NULL;
- }
- gpio_set_value(EXYNOS4_GPD0(1), 0);
- gpio_free(EXYNOS4_GPD0(1));
- }
- MODULE_AUTHOR("www.9tripod.com");
- MODULE_LICENSE("Dual BSD/GPL");
- module_init(x4412_second_init);
- module_exit(x4412_second_exit);
复制代码 该驱动使用了多种延时方法,用于控制蜂鸣器的鸣叫间隔。 在kernel/drivers/char/x4412/Kconfig中添加如下语句: - config X4412_DELAY_DRIVER
- tristate "x4412 delay driver"
- default m
- help
- compile for x4412 delay driver,y for kernel,m for module.
复制代码 在kernel/drivers/char/x4412/Makefile中添加如下语句: - obj-$(CONFIG_X4412_DELAY_DRIVER) += x4412-delay.o
复制代码 编译内核,在kernel/drivers/char/x4412目录下将会生成目标文件x4412-delay.ko。加载内核,观察蜂鸣器的现象。当卸载模块后,蜂鸣器将停止鸣叫。 编译好的驱动模块:
x4412-delay.ko
(4.01 KB, 下载次数: 4)
|