PHC产生PPS,调用了一些PPS接口,以下为查阅分析的PPS接口资料。
一、简介
LinuxPPS提供了一个编程接口(API),用于在系统中定义多个PPS源。
PPS是指“每秒脉冲”,PPS源只是一个每秒提供高精度信号的设备,以便应用程序可以使用它来调整系统时钟时间。
PPS源可以连接到串行端口(通常连接到数据载波检测引脚)或并行端口(ACK引脚)或特殊CPU的GPIO(这是嵌入式系统中的常见情况),但在每种情况下,当新脉冲到达时,系统记录该秒脉冲的时间戳。
二、PPS接口的使用
1.注册PPS
在内核中注册PPS源,首先要定义一个pps_source_info结构体
然后在模块初始化时调用pps_register_source()
在linuxptp的应用中
ptp_clock_register()//ptp_clock.c
pps_register_source(); //pps源的名字命名为ptp[index]如ptp1,可以通过cat /sys/class/pps/pps0/name查询到。
2.产生PPS事件
注册之后,可以调用pps_event()产生PPS事件,ts参数表示PPS事件的时间戳。例如可以在中断处理函数中调用pps_event,这个中断可以是外部的PPS信号触发的中断,也可以是定时器产生的中断。应用层可以读取pps事件来感知外部pps或内部pps事件。
示例代码可以查看drivers/pps/clients/pps-ktimer.c
驱动中对pps_event的调用链
dpaa2_ptp_irq_handler_thread()//ptp要产生pps信号给其他设备使用
event.type = PTP_CLOCK_PPS
ptp_clock_event()
pps_get_ts
ktime_get_snapshot()//获取系统时间快照
pps_event(ptp->pps_source, &evt, PTP_PPS_EVENT,NULL)//pps_event()和pps_get_ts()配合使用,pps_get_ts()用来产生 pps事件的时间,pps_event()是用来产生pps事件信号
ttimespec_to_pps_ktime()
pps->assert_tu = ts_real;
pps->assert_sequence++;
pps_kc_event(pps,ts,event); //call hardpps() on pps event
hardpps(&ts->ts_real, &ts->ts_raw) //注意,这个地方是有条件进入的,当pps =pps_kc_hardpps_dev 且event& pps_kc_hardpps_mode时,hardpps()后面细讲
wake_up_interruptible_all()唤醒中断,应用软件如果调用pps_read()会返回
3.读取pps事件
read()
posix_clock_read()//这部分为驱动代码,将数据从内核态拷贝到用户态
clk->opt.read()
ptp_read()
wait_event_interruptible()//等待条件是否满足,不满足则阻塞,满足则唤醒, (收到外部的PPS信号时,会读取寄存器时间放到事件队列中,然后唤醒此处的中断)唤醒后:取队列中的内容,拷贝到用户空间
4.hardpps()
而pps_kc_hardpps_dev和pps_kc_hardpps_mode这两个全局变量是何时被赋值的?可以追到timepps.h文件
time_pps_kcbind() //timepps.h
ioctl(handle,PPS_KC_BIND,&__bind_args)
pps_cdev_ioctl()//pps.c
case PPS_KC_BIND:
pps_kc_bind() //对pps_kc_hardpps_dev和pps_kc_hardpps_mode进行赋值
查遍linuxptp代码未发现调用调用ioctl(handle,PPS_KC_BIND,&__bind_args)的地方,所以在linuxptp的应用中不会调用hardpps()。
那么hardpps()是做啥用的?是ntp应用中调整系统时间用的。
上图来源于https://www.ntp.org/ntpfaq/NTP-s-config-adv.htm#Q-PPS-API
PPS API描述了关于PPS的一些列接口,PPS API是一个公共的程序接口,记录在RFC2783协议中,下述链接是关于PPS API的详细描述
https://datatracker.ietf.org/doc/html/rfc2783#section-3.4.1
linux对PPS的驱动使用描述:
https://www.kernel.org/doc/html/latest//driver-api/pps.html
三、补充phc对外部pps信号的处理
GPS的PPS通过GPIO或者其他方式连接到PHC,当GPIO电平变化触发中断,中断处理函数如下
devm_request_threaded_irq()
走if (status & DPRTC_EVENT_ETS1)或if (status & DPRTC_EVENT_ETS2)
extts_clean_up()
ptp_qoriq->read(reg_etts_l)//读寄存器
ptp_qoriq->read(reg_etts_h)//读寄存器,组合成时间放在event中
ptp_clock_event()
enqueue_external_timestamp(&ptp->tsevq, event);//将event数据放在ptp->tsevq队列尾部
wake_up_interruptible(&ptp->tsev_wq);//唤醒等待队列中断,应用程序在read中被唤醒,唤醒ptp_read()中断
疑问:系统是在什么时候写寄存器regs->etts_regs->tmr_etts1_l和tmr_etts1_h的呢?