NTP的进一步研究:PPS驱动开发

目标板在使用GPS15/35时,连上卫星,会发出每秒1次的脉冲(1 Pluse Per Second),一般称为1PPS或PPS。由于其脉冲间隔非常精确(误差基本在2ms左右),因此可以用PPS来校准GPS收取时间的准秒。GPS收取时间是通过串口发送数据,但由于各种不稳定性,导致偏差时有发生,在GPS发送时间后,NTP的refclock驱动调用PPS了校准整秒,使得每次偏差都不会过大,而且会加速收敛过程。(理论上使用1PPS后,GPS的根偏差会非常的小)。

PS:但是目前所做的实验,在1PPS使用时经常会出现杂波,而示波器上却无任何反映,非常正常,此问题有待解决。具体驱动理论参考linux驱动开发。

由于NTP所使用的PPS接口为IOCTL接口,所以驱动主要使用IOCTL方法。具体层次构架见上一篇NTP文章。
1、开始

下载PPSkit,是一个给linux打支持1PPS的补丁。(其实现方法和本文有所不同。)PPSKit目前最高只支持2.4内核,而目标板使用的是2.6内核,因此需要重写驱动。
首先来介绍下PPSKit,其精度非常高,号称支持到纳秒级别。它主要是修改通用串口驱动,在串口的DCD(载波检测)上附加上PPS。当驱动检测到DCD信号时,为一个上升沿出发的PPS信号,否则,则是下降沿出发的PPS信号。具体处理哪个信号是根据mode的设置。
上层需要调用timepps的api来使用PPS驱动,主要方法是PPS_IOC_FETCH来当发生PPS中断时获取时间。上层调用时,驱动会睡眠在中断序列上,等待中断。一旦中断发生,将取得的系统时间返回给上层。PPSKit里使用的则是串口中断,依附在串口的信号机制上。其他还有一部分就是修改系统的时间格式、时间处理函数等。

2、Working

为了实现方便,我们不需要再去番2.6的内核,找串口驱动什么的。这只会加大难度。我们要做的只是设置一个中断,编写一个独立的设备,并做好IOCTL的接口。我们这里使用中断8。

#define PPS_IRQ IRQ_EINT8



然后注册中断,注册设备等,这些都可以找通用的模板参考。

static int __init pps_init(void)		//init
{
	int retval;
	int ret;

	set_irq_type(PPS_IRQ,IRQT_FALLING);
	ret=request_irq(PPS_IRQ,pps_irq,SA_INTERRUPT,"PPS",NULL);
	if(ret)
	{
		printk("Request irq failed/n");
		return -EBUSY;
	}

	//register
	retval=register_chrdev(0,DEVICE_NAME,&pps_ops);
	if(retval<0)
	{
		printk(KERN_ERR"fail to reg pps/n");
		return retval;
	}
	PPS_MAJOR=retval;
	devfs_mk_cdev(MKDEV(PPS_MAJOR,PPS_MINORS),S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,DEVICE_NAME);

	printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " " DRIVER_AUTHOR "/n");
	return retval;
}

static void __exit pps_exit(void)		//exit
{
    devfs_remove(DEVICE_NAME);
    unregister_chrdev(PPS_MAJOR,DEVICE_NAME);
	printk(KERN_INFO DRIVER_DESC "" DRIVER_VERSION " " DRIVER_AUTHOR "BYE!/n");
}

module_init(pps_init);
module_exit(pps_exit);



最后就是实现方法,参考PPSkit的方法,很简单。要注意IOCTL接口。

static struct file_operations pps_ops = {
	.owner		=	THIS_MODULE,
	.open		=	pps_open,
	.release		=	pps_release,
	.read		=	pps_read,
	.ioctl		=	pps_ioctl,
};



最后,交叉编译,放到目标板上测试。主要是测试中断。

Makefile:

ifneq ($(KERNELRELEASE),)
    obj-m :=pps.o
else
    KERNELDIR ?= 你的2.6内核所在
    PWD := $(shell pwd)
default:
	 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
	 rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
endif


#insmod pps.ko

#rmmod pps




  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

左脉千帆云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值