[TOC]
V4L2时间戳
时间戳存储在struct v4l2_buffer的timestamp字段中:
1
2
3
4
|
struct v4l2_buffer {
// ... 其他字段 ...
struct timeval timestamp; // 时间戳(秒 + 微秒)
};
|
timestamp.tv_sec:秒部分(自UNIX Epoch以来的时间:自1970年1月1日00:00:00 UTC 以来经过的秒数。)。
timestamp.tv_usec:微秒部分(1秒 = 1,000,000微秒)。
系统单调时钟
单调时钟(Monotonic Clock): 时间起点是系统启动时间,单调时钟从系统启动的那一刻开始计时,并且随着时间的推移单调递增,它不会受到系统时间调整(如 NTP 校准或用户手动更改系统时间)的影响 。
硬件时钟(TSC)
TSC 通常在系统启动(或硬件复位)时被初始化为 0,并从那一刻开始计数。TSC 是一个单调递增的计数器,它记录了自系统启动以来 CPU 的时钟周期数。TSC 的精度非常高,因为它基于 CPU 的时钟频率(通常在 GHz 级别),可以提供纳秒级的时间分辨率。
计算ARM硬件计数器(cntvct_el0)与系统单调时钟(CLOCK_MONOTONIC_RAW)之间的时间偏移量(纳秒级)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
uint64_t readOffsetNs()
{
unsigned long raw_nsec, tsc_ns;
unsigned long cycles, frq;
struct timespec tp;
asm volatile("mrs %0, cntfrq_el0" : "=r"(frq));
asm volatile("mrs %0, cntvct_el0" : "=r"(cycles));
clock_gettime(CLOCK_MONOTONIC_RAW, &tp);
tsc_ns = (cycles * 100 / (frq / 10000)) * 1000;
raw_nsec = tp.tv_sec * 1000000000 + tp.tv_nsec;
uint64_t offset_ns = llabs(tsc_ns - raw_nsec);
return offset_ns;
}
|
计算系统启动时间(uptime_ms 系统单调时钟)与 Unix 纪元时间(epoch time)之间的偏移量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
long getEpochTimeShift()
{
struct timeval epochtime;
struct timespec vsTime;
struct timespec realTime;
gettimeofday(&epochtime, NULL);
clock_gettime(CLOCK_MONOTONIC_RAW, &vsTime);
clock_gettime(CLOCK_REALTIME, &realTime);
long uptime_ms = vsTime.tv_sec * 1000 + (long)round(vsTime.tv_nsec / 1000000.0);
long epoch_ms = epochtime.tv_sec * 1000 + (long)round(epochtime.tv_usec / 1000.0);
long x_ms = realTime.tv_sec * 1000 + (long)round(realTime.tv_nsec / 1000000.0);
printf("toEpochOffset_ms:%ld, toRealMonoOffset-ms: %ld\n", epoch_ms - uptime_ms, x_ms - uptime_ms);
return epoch_ms - uptime_ms;
}
|