目标板在使用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