Commit 0618ea14 authored by Federico Vaga's avatar Federico Vaga

Merge branch 'configurable-timing-base'

parents 9dd2bd69 05f2ee15
......@@ -74,6 +74,11 @@ static struct zio_attribute zfad_cset_ext_zattr[] = {
ZIO_ATTR_EXT("tstamp-acq-str-b", ZIO_RO_PERM,
ZFA_UTC_ACQ_START_FINE, 0),
/* Timing base */
ZIO_ATTR_EXT("tstamp-base-s", ZIO_RW_PERM, ZFA_UTC_SECONDS, 0),
ZIO_ATTR_EXT("tstamp-base-t", ZIO_RW_PERM, ZFA_UTC_COARSE, 0),
/* Parameters (not attributes) follow */
/*
......@@ -161,12 +166,16 @@ static int zfad_conf_set(struct device *dev, struct zio_attribute *zattr,
uint32_t usr_val)
{
struct fa_dev *fa = get_zfadc(dev);
unsigned int baseoff = fa->fa_adc_csr_base;
struct zio_channel *chan;
int i, range, err, reg_index;
reg_index = zattr->id;
i = FA_NCHAN;
if (zattr->id >= ZFA_UTC_SECONDS && zattr->id <= ZFA_UTC_ACQ_END_FINE)
baseoff = fa->fa_utc_base;
switch (reg_index) {
/*
* Most of the following "case" statements are simply
......@@ -242,11 +251,19 @@ static int zfad_conf_set(struct device *dev, struct zio_attribute *zattr,
case ZFA_CHx_STA:
reg_index = zfad_get_chx_index(reg_index, to_zio_chan(dev));
break;
case ZFA_UTC_COARSE:
if (usr_val >= FA_UTC_CLOCK_FREQ) {
dev_err(dev,
"ticks time must be in the range [0, %d]\n",
FA_UTC_CLOCK_FREQ);
return -EINVAL;
}
break;
case ZFA_CTL_FMS_CMD:
return zfad_fsm_command(fa, usr_val);
}
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[reg_index], usr_val);
fa_writel(fa, baseoff, &zfad_regs[reg_index], usr_val);
return 0;
}
......@@ -259,10 +276,14 @@ static int zfad_info_get(struct device *dev, struct zio_attribute *zattr,
uint32_t *usr_val)
{
struct fa_dev *fa = get_zfadc(dev);
unsigned int baseoff = fa->fa_adc_csr_base;
int i, reg_index;
i = FA_NCHAN;
if (zattr->id >= ZFA_UTC_SECONDS && zattr->id <= ZFA_UTC_ACQ_END_FINE)
baseoff = fa->fa_utc_base;
switch (zattr->id) {
/* FIXME temporary until TLV control */
case ZFA_CH1_OFFSET:
......@@ -309,7 +330,7 @@ static int zfad_info_get(struct device *dev, struct zio_attribute *zattr,
reg_index = zattr->id;
}
*usr_val = fa_readl(fa, fa->fa_adc_csr_base, &zfad_regs[reg_index]);
*usr_val = fa_readl(fa, baseoff, &zfad_regs[reg_index]);
return 0;
}
static const struct zio_sysfs_operations zfad_s_op = {
......
......@@ -59,8 +59,12 @@ enum fa_dev_ext_attributes {
ZFAD_ATTR_ACQ_START_S,
ZFAD_ATTR_ACQ_START_C,
ZFAD_ATTR_ACQ_START_F,
ZFAD_ATTR_BASE_S,
ZFAD_ATTR_BASE_C,
};
#define FA_UTC_CLOCK_FREQ 125000000
#define FA_UTC_CLOCK_NS 8
#define FA_NCHAN 4 /* We have 4 of them,no way out of it */
/* ADC DDR memory */
......@@ -243,7 +247,6 @@ enum fa_sw_param_id {
ZFA_SW_PARAM_COMMON_LAST,
};
/*
* Bit pattern used in order to factorize code between SVEC and SPEC
* Depending of the carrier, ADC may have to listen vaious IRQ sources
......
......@@ -32,7 +32,9 @@
(1LL << FMCADC_CONF_CHN_TERMINATION) | \
(1LL << FMCADC_CONF_CHN_OFFSET)
#define FMCADC_ZIO_BRD_MASK (1LL << FMCADC_CONF_BRD_STATE_MACHINE_STATUS) | \
(1LL << FMCADC_CONF_BRD_N_CHAN)
(1LL << FMCADC_CONF_BRD_N_CHAN) | \
(1LL << FMCADC_CONF_UTC_TIMING_BASE_S) | \
(1LL << FMCADC_CONF_UTC_TIMING_BASE_T)
struct fmcadc_operations fa_100ms_4ch_14bit_op = {
.open = fmcadc_zio_open,
......
......@@ -319,6 +319,22 @@ static int fmcadc_zio_config_brd(struct __fmcadc_dev_zio *fa,
unsigned int index, uint32_t *value, unsigned int direction)
{
switch (index) {
case FMCADC_CONF_UTC_TIMING_BASE_S:
if (direction)
return fa_zio_sysfs_set(fa, "cset0/tstamp-base-s",
value);
else
return fa_zio_sysfs_get(fa, "cset0/tstamp-base-s",
value);
break;
case FMCADC_CONF_UTC_TIMING_BASE_T:
if (direction)
return fa_zio_sysfs_set(fa, "cset0/tstamp-base-t",
value);
else
return fa_zio_sysfs_get(fa, "cset0/tstamp-base-t",
value);
break;
case FMCADC_CONF_BRD_STATE_MACHINE_STATUS:
if (!direction)
return fa_zio_sysfs_get(fa, "cset0/fsm-state",
......
......@@ -13,6 +13,8 @@
#ifndef FMCA_ADC_100MA4B4CHA_H_
#define FMCA_ADC_100MA4B4CHA_H_
#define FA_UTC_CLOCK_NS 8
/*
* Trigger Extended Attribute Enumeration
*/
......
......@@ -83,6 +83,9 @@ enum fmcadc_board_status {
FMCADC_CONF_BRD_MIN_FREQ_HZ,
FMCADC_CONF_BRD_STATE_MACHINE_STATUS,
FMCADC_CONF_BRD_N_CHAN,
FMCADC_CONF_UTC_TIMING_BASE_S,
FMCADC_CONF_UTC_TIMING_BASE_T,
FMCADC_CONF_UTC_TIMING_BASE_B,
__FMCADC_CONF_BRD_ATTRIBUTE_LAST_INDEX,
};
enum fmcadc_configuration_type {
......
......@@ -4,11 +4,12 @@ LIBADC = ../lib/
ZIO ?= ../zio
CFLAGS = -Wall -g -ggdb -I$(LIBADC) -I$(ZIO)/include $(EXTRACFLAGS)
LDFLAGS = -L$(LIBADC) -lfmcadc -lpthread
LDFLAGS = -L$(LIBADC) -lfmcadc -lpthread -lrt
DEMOS := fald-simple-acq fald-acq fald-trg-cfg
DEMOS += fald-simple-get-conf
DEMOS += fald-test
DEMOS += fald-bad-clock
all: demo
......
/*
* Copyright CERN 2014
* Author: Federico Vaga <federico.vaga@gmail.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <getopt.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <linux/zio-user.h>
#include <fmcadc-lib.h>
#include <fmc-adc-100m14b4cha.h>
/* Subtract the `struct timespec' values X and Y,
storing the result in RESULT.
Return 1 if the difference is negative, otherwise 0. */
int timespec_subtract (result, x, y)
struct timespec *result, *x, *y;
{
/* Perform the carry for the later subtraction by updating y. */
if (x->tv_nsec < y->tv_nsec) {
int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
y->tv_nsec -= 1000000000 * nsec;
y->tv_sec += nsec;
}
if (x->tv_nsec - y->tv_nsec > 1000000000) {
int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
y->tv_nsec += 1000000000 * nsec;
y->tv_sec -= nsec;
}
/* Compute the time remaining to wait.
tv_nsec is certainly positive. */
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_nsec = x->tv_nsec - y->tv_nsec;
/* Return 1 if result is negative. */
return x->tv_sec < y->tv_sec;
}
static void fald_help()
{
printf("\nfald-bad-clock [OPTIONS] <devid>\n\n");
printf(" -i <seconds> observation interval\n\n");
printf(" -h show this help\n\n");
exit(1);
}
int main (int argc, char *argv[])
{
struct fmcadc_dev *adc;
struct fmcadc_conf brd_cfg;
struct timespec sys_start, sys_cur, adc_cur, dlt_ts, dlt_dlt_ts = {0, 0};
int err, devid, interval = 360;
uint32_t adc_sec, adc_ticks;
char c;
/* Prepare the board timing base configuration */
memset(&brd_cfg, 0, sizeof(brd_cfg));
brd_cfg.type = FMCADC_CONT_TYPE_BRD;
while ((c = getopt(argc, argv, "i:h")) >= 0) {
switch (c) {
case 'i':
err = sscanf(optarg, "%d", &interval);
if (err != 1)
fald_help();
break;
case '?':
case 'h':
fald_help();
break;
}
}
sscanf(argv[argc-1], "%x", &devid);
adc = fmcadc_open("fmc-adc-100m14b4cha", devid, 0, 0, FMCADC_F_FLUSH);
if (!adc) {
fprintf(stderr, "%s: cannot open device: %s",
argv[0], fmcadc_strerror(errno));
exit(1);
}
do {
err = clock_gettime(CLOCK_REALTIME, &sys_start);
if (err) {
fprintf(stderr, "%s: cannot get real time: %s",
argv[0], strerror(errno));
exit(1);
}
} while (sys_start.tv_nsec > 1000);
/* Configure ADC internal clock */
adc_sec = sys_start.tv_sec;
adc_ticks = sys_start.tv_nsec / FA_UTC_CLOCK_NS;
fmcadc_set_conf(&brd_cfg, FMCADC_CONF_UTC_TIMING_BASE_T, adc_ticks);
fmcadc_set_conf(&brd_cfg, FMCADC_CONF_UTC_TIMING_BASE_S, adc_sec);
err = fmcadc_apply_config(adc, 0 , &brd_cfg);
if (err && errno != FMCADC_ENOMASK) {
fprintf(stderr, "%s: cannot configure board %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
fprintf(stdout,
"ADC clock configured: %010li s %010li ns ( %i %ins ticks)\n",
sys_start.tv_sec, sys_start.tv_nsec,
adc_ticks, FA_UTC_CLOCK_NS);
/* Measure how clock diverge */
while (interval--) {
/* Get the system clock */
err = clock_gettime(CLOCK_REALTIME, &sys_cur);
if (err) {
fprintf(stderr, "%s: cannot get real time: %s",
argv[0], strerror(errno));
exit(1);
}
/* Get the ADC clock */
err = fmcadc_retrieve_config(adc, &brd_cfg);
if (err) {
fprintf(stderr, "%s: cannot get trigger config: %s\n",
argv[0], fmcadc_strerror(errno));
exit(1);
}
fmcadc_get_conf(&brd_cfg, FMCADC_CONF_UTC_TIMING_BASE_S,
&adc_sec);
fmcadc_get_conf(&brd_cfg, FMCADC_CONF_UTC_TIMING_BASE_T,
&adc_ticks);
adc_cur.tv_sec = adc_sec;
adc_cur.tv_nsec = adc_ticks * FA_UTC_CLOCK_NS;
/* Get the difference between system and ADC clock */
timespec_subtract(&dlt_ts, &sys_cur, &adc_cur);
/* How bad is? */
timespec_subtract(&dlt_dlt_ts, &dlt_ts, &dlt_dlt_ts);
/* Show time stamps and delta */
printf(" sys %ld.%.9ld s\n", sys_cur.tv_sec,
sys_cur.tv_nsec);
printf(" adc %ld.%.9ld s\n", adc_cur.tv_sec,
adc_cur.tv_nsec);
printf("|dlt| %ld.%.9ld s (%ld.%.9ld s)\n",
dlt_ts.tv_sec, dlt_ts.tv_nsec,
dlt_dlt_ts.tv_sec, dlt_dlt_ts.tv_nsec);
dlt_dlt_ts = dlt_ts;
if (dlt_ts.tv_sec) {
timespec_subtract(&dlt_dlt_ts, &sys_cur, &sys_start);
printf("Clock diverged of %ld.%.9ld s in %ld.%.9ld s\n",
dlt_ts.tv_sec, dlt_ts.tv_nsec,
dlt_dlt_ts.tv_sec, dlt_dlt_ts.tv_nsec);
break;
}
printf(" sleep 1 s\n");
sleep(1);
}
exit(0);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment