Commit ec8b2e68 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

Merge branch 'master' of ohwr.org:fmc-projects/fmc-delay-1ns-8cha

parents 3bb91660 4b397849
......@@ -3,7 +3,7 @@
* File : fd_main_regs.h
* Author : auto-generated by wbgen2 from fd_main_wishbone_slave.wb
* Created : Wed Apr 11 11:05:22 2012
* Created : Mon May 21 20:09:50 2012
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE fd_main_wishbone_slave.wb
......@@ -274,6 +274,9 @@
#define FD_TSBCR_COUNT_W(value) WBGEN2_GEN_WRITE(value, 10, 12)
#define FD_TSBCR_COUNT_R(reg) WBGEN2_GEN_READ(reg, 10, 12)
/* definitions for field: RAW readout mode enable in reg: Timestamp Buffer Control Register */
#define FD_TSBCR_RAW WBGEN2_GEN_MASK(22, 1)
/* definitions for register: Timestamp Buffer Interrupt Register */
/* definitions for field: IRQ timeout [milliseconds] in reg: Timestamp Buffer Interrupt Register */
......@@ -344,6 +347,13 @@
#define FD_TDER2_PELT_DRIVE_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define FD_TDER2_PELT_DRIVE_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: Timestamp Buffer Debug Values Register */
/* definitions for register: Timestamp Buffer Advance Register */
/* definitions for field: Advance buffer readout in reg: Timestamp Buffer Advance Register */
#define FD_TSBR_ADVANCE_ADV WBGEN2_GEN_MASK(0, 1)
/* definitions for register: Interrupt disable register */
/* definitions for field: TS Buffer not empty. in reg: Interrupt disable register */
......@@ -445,6 +455,10 @@
#define FD_REG_TDER1 0x0000006c
/* [0x70]: REG Test/Debug register 1 */
#define FD_REG_TDER2 0x00000070
/* [0x74]: REG Timestamp Buffer Debug Values Register */
#define FD_REG_TSBR_DEBUG 0x00000074
/* [0x78]: REG Timestamp Buffer Advance Register */
#define FD_REG_TSBR_ADVANCE 0x00000078
/* [0x80]: REG Interrupt disable register */
#define FD_REG_EIC_IDR 0x00000080
/* [0x84]: REG Interrupt enable register */
......
......@@ -36,9 +36,19 @@ typedef struct fdelay_device
void *priv_io; /* pointer to the I/O routines private data */
} fdelay_device_t;
typedef struct {
int64_t utc, utc_sh;
int32_t coarse, coarse_sh;
int32_t start_offset;
int32_t subcycle_offset;
int32_t frac;
} fdelay_raw_time_t;
typedef struct
{
int32_t utc; /* TAI seconds */ /* FIXME: replace all UTCs with TAIs or seconds for clarity */
fdelay_raw_time_t raw;
int64_t utc; /* TAI seconds */ /* FIXME: replace all UTCs with TAIs or seconds for clarity */
int32_t coarse; /* 125 MHz counter cycles */
int32_t frac; /* Fractional part (<8ns) */
uint16_t seq_id; /* Sequence ID to detect missed timestamps */
......@@ -113,5 +123,9 @@ int fdelay_configure_pulse_gen(fdelay_device_t *dev, int channel_mask, int enabl
/* (pulse mode only) Returns non-0 when all of the channels in channel mask have produced their programmed pulses */
int fdelay_outputs_triggered(fdelay_device_t *dev, int channel_mask, int blocking);
void fdelay_set_user_offset(fdelay_device_t *dev,int input, int64_t offset);
int fdelay_get_time(fdelay_device_t *dev, fdelay_time_t *t);
int fdelay_set_time(fdelay_device_t *dev, const fdelay_time_t t);
#endif
......@@ -20,6 +20,7 @@
#define CS_DAC 0 /* AD9516 PLL */
#define CS_PLL 1 /* AD9516 PLL */
#define CS_GPIO 2 /* MCP23S17 GPIO */
#define CS_NONE 3
/* MCP23S17 GPIO expander pin locations: bit 8 = select bank 2, bits 7..0 = mask of the pin in the selected bank */
#define SGPIO_TERM_EN (1<<0) /* Input termination enable (1 = on) */
......@@ -84,7 +85,9 @@ struct fine_delay_hw
int32_t board_temp; /* Current temperature of the board, unit = 1/16 degC */
int wr_enabled;
int wr_state;
int raw_mode;
struct fine_delay_calibration calib;
int64_t input_user_offset, output_user_offset;
};
/* some useful access/declaration macros */
......
......@@ -3,24 +3,16 @@ CFLAGS = -I../include -g -Imini_bone -Ispll
#uncomment for extra tests (DAC, output stage INL/DNL)
#CFLAGS += -DPERFORM_LONG_TESTS
OBJS_LIB = fdelay_lib.o fdelay_bus.o rr_io.o i2c_master.o onewire.o mini_bone/minibone_lib.o mini_bone/ptpd_netif.o spec_common.o
OBJS_LIB = fdelay_lib.o i2c_master.o onewire.o mini_bone/minibone_lib.o mini_bone/ptpd_netif.o spec_common.o
all: testprog lib testprog3 testprog4
all: testprog lib gs
lib: $(OBJS_LIB)
gcc -shared -o libfinedelay.so $(OBJS_LIB)
testprog: lib fdelay_test.o
gcc -o fdelay_test $(OBJS_LIB) fdelay_test.o -lm
#testprog2: lib fdelay_cal.o
# gcc -o fdelay_cal $(OBJS_LIB) fdelay_cal.o -lm
testprog3: lib fdelay_pps_demo.o
testprog: lib fdelay_pps_demo.o
gcc -o fdelay_pps_demo $(OBJS_LIB) fdelay_pps_demo.o -lm
testprog4: lib fdelay_eeprom.o
gcc -o fdelay_eeprom $(OBJS_LIB) fdelay_eeprom.o -lm
gs: lib fdelay-gs.o
gcc -o fdelay-gs $(OBJS_LIB) fdelay-gs.o -lm
clean:
rm -f libfinedelay.so $(OBJS_LIB)
\ No newline at end of file
/* Simple demo that reads samples using the read call */
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include <signal.h>
#include <sys/select.h>
#define FDELAY_INTERNAL // for sysfs_get/set
#include "fdelay_lib.h"
#define PACKED __attribute__((packed))
#define TYPE_START_LOGGING 1
#define TYPE_END_LOGGING 2
#define TYPE_TIMESTAMP 3
struct fdelay_time {
uint64_t utc;
uint32_t coarse;
uint32_t frac;
uint32_t seq_id;
uint32_t channel;
};
PACKED struct binary_timestamp {
int32_t card_id;
uint8_t type;
PACKED struct fdelay_time ts;
};
#define MAX_BOARDS 64
struct board_def {
fdelay_device_t *b;
int term_on;
int64_t input_offset;
int64_t output_offset;
int hw_index;
int in_use;
int fd;
struct {
int64_t offset_pps, width, period;
int enabled;
} outs [4];
};
struct board_def boards[MAX_BOARDS];
static FILE *log_file = NULL;
void log_write(fdelay_time_t *t, int card_id)
{
struct binary_timestamp bt;
if(!log_file)
return;
bt.ts.utc = t->utc;
bt.ts.coarse = t->coarse;
bt.ts.frac = t->frac;
bt.ts.seq_id = t->seq_id;
bt.ts.channel = 0;
bt.type = TYPE_TIMESTAMP;
bt.card_id = card_id;
fwrite(&bt, sizeof(struct binary_timestamp), 1, log_file);
fflush(log_file);
}
void log_start(char *log_file_name)
{
struct binary_timestamp bt;
log_file = fopen(log_file_name, "a+");
if(!log_file)
{
fprintf(stderr, "Can't open the log file: %s\n", log_file_name);
exit(-1);
}
bt.card_id = 0;
bt.type = TYPE_START_LOGGING;
fwrite(&bt, sizeof(struct binary_timestamp), 1, log_file);
fflush(log_file);
}
void log_stop()
{
struct binary_timestamp bt;
if(!log_file)
return;
bt.card_id = 0;
bt.type = TYPE_END_LOGGING;
fwrite(&bt, sizeof(struct binary_timestamp), 1, log_file);
fflush(log_file);
fclose(log_file);
}
int64_t parse_num(const char *n_str)
{
struct {
char unit;
int64_t multiplier;
} units[] = {
{'p', 1LL},
{'n', 1000LL},
{'u', 1000000LL},
{'m', 1000000000LL},
{'s', 1000000000000LL},
{' ', 0}
};
int64_t n;
char unit;
int rv = sscanf(n_str,"%lli%c", &n, &unit);
if(rv == 1)
return n;
else if (rv == 2)
{
int i;
for(i=0; units[i].multiplier; i++)
if(units[i].unit == unit)
return units[i].multiplier * n;
fprintf(stderr,"Unrecognized numeric constant '%s' (wrong units?)\n", n_str);
exit(-1);
}
fprintf(stderr,"Unrecognized numeric constant '%s'\n", n_str);
exit(-1);
}
#define MAX_TOKENS 16
#define MAX_TOK_LENGTH 256
typedef char token_array[MAX_TOKENS][MAX_TOK_LENGTH];
/* returns: tokenized arguments to tokens, command (1st word) to cmd */
int next_command(FILE *f_config, char *cmd, token_array tokens)
{
char line [1024];
char *running;
const char *delims=" \n\r\t";
int i;
int n = 0;
do {
if(feof(f_config))
return -1;
fgets(line, sizeof(line), f_config);
running = strdupa(line);
while(*running == ' ' || *running == '\t') running++;
strncpy(cmd, strsep (&running , delims), MAX_TOK_LENGTH);
} while(cmd[0] == '#' || cmd[0] == ' ' || cmd[0] == '\n' || cmd[0] == '\r' || !cmd[0]);
for(i=0;i<MAX_TOKENS;i++)
{
char *token = strsep (&running , delims);
if(token == NULL)
return n;
if(strlen(token) > 0)
{
// printf("tok %p\n", tokens[0]);
strncpy(&tokens[n][0], token, MAX_TOK_LENGTH);
n++;
}
}
return 0;
}
#define CUR boards[current_board]
void load_config(const char *config_file)
{
token_array args;
char cmd [MAX_TOK_LENGTH];
int current_board = 0;
int n_args;
FILE *f_config=fopen(config_file, "r");
if(!f_config)
{
fprintf(stderr,"Can't open configuration file '%s'\n", config_file);
exit(-1);
}
memset(boards, 0, sizeof(boards));
while((n_args = next_command(f_config, cmd, args)) >= 0)
{
if(!strcmp(cmd, "board"))
{
current_board = parse_num(args[0]);
CUR.in_use = 1;
}
if(!strcmp(cmd, "hw_index"))
{
CUR.hw_index = parse_num(args[0]);
printf("Adding board %d, hw_index %x\n", current_board, CUR.hw_index);
}
if(!strcmp(cmd, "termination"))
CUR.term_on = parse_num(args[0]);
if(!strcmp(cmd, "input_offset"))
CUR.input_offset = parse_num(args[0]);
if(!strcmp(cmd, "output_offset"))
CUR.output_offset = parse_num(args[0]);
if(!strcmp(cmd, "out"))
{
int index = parse_num(args[0]) - 1;
if(index < 0 || index > 3)
{
fprintf(stderr,"Invalid output index\n");
exit(-1);
}
CUR.outs[index].offset_pps = parse_num(args[1]);
CUR.outs[index].width = parse_num(args[2]);
CUR.outs[index].period = parse_num(args[3]);
CUR.outs[index].enabled = 1;
// printf("OutCfg: %d %lli %lli %lli\n", index, CUR.outs[index].offset_pps, CUR.outs[index].width, CUR.outs[index].period);
}
if(!strcmp(cmd, "log_file"))
log_start(args[0]);
}
fclose(f_config);
}
#undef CUR
void enable_wr(fdelay_device_t *b, int index)
{
int lock_retries = 50;
printf("Locking to WR network [board=%d]...", index);
fflush(stdout);
fdelay_configure_sync(b, FDELAY_SYNC_LOCAL);
sleep(2);
fdelay_configure_sync(b, FDELAY_SYNC_WR);
while(fdelay_check_sync(b) <= 0)
{
printf(".");
fflush(stdout);
sleep(1);
if(lock_retries-- == 0)
{
fprintf(stderr," WR lock timed out\n");
exit(1);
}
}
printf("\n");
fflush(stdout);
}
/* Add two timestamps */
static fdelay_time_t ts_add(fdelay_time_t a, fdelay_time_t b)
{
a.frac += b.frac;
if(a.frac >= 4096)
{
a.frac -= 4096;
a.coarse++;
}
a.coarse += b.coarse;
if(a.coarse >= 125000000)
{
a.coarse -= 125000000;
a.utc ++;
}
a.utc += b.utc;
return a;
}
int configure_board(struct board_def *bdef)
{
fdelay_device_t *b = malloc(sizeof(fdelay_device_t));
int i;
if(spec_fdelay_init(b, bdef->hw_index >>8, bdef->hw_index & 0xff) < 0)
{
fprintf(stderr,"Can't open fdelay board @ hw_index %x\n", bdef->hw_index);
exit(-1);
}
bdef->b = b;
fdelay_configure_trigger(bdef->b, 0, bdef->term_on);
enable_wr(b, bdef->hw_index);
int val = bdef->input_offset;
// fdelay_sysfs_set((struct __fdelay_board *)b, "fd-input/user-offset", (uint32_t *)&val);
fdelay_set_user_offset(b, 1, val);
for(i=0;i<4;i++)
{
char path[1024];
int val = bdef->output_offset;
snprintf(path, sizeof(path), "fd-ch%d/user-offset", i+1);
fdelay_set_user_offset(b, 0, val);
// fdelay_sysfs_set((struct __fdelay_board *)b, path,(uint32_t *) &val);
}
for(i=0;i<4;i++)
{
if(bdef->outs[i].enabled)
{
fdelay_time_t t_cur, pps_offset, width;
// struct fdelay_pulse p;
fdelay_get_time(bdef->b, &t_cur);
// printf("Configure output %d [t_cur %d:%d]\n", i+1,t_cur.utc, t_cur.coarse);
// fdelay_pico_to_time(&bdef->outs[i].offset_pps, &pps_offset);
// fdelay_pico_to_time(&bdef->outs[i].width, &width);
t_cur.utc += 2;
t_cur.coarse = 0;
t_cur.frac = 0;
t_cur = ts_add(t_cur, fdelay_from_picos(bdef->outs[i].offset_pps));
//printf("Configure output %d [t_start %d:%d width %lld period %lld]\n", i+1,t_cur.utc, t_cur.coarse, bdef->outs[i].width, bdef->outs[i].period);
fdelay_configure_pulse_gen(bdef->b, i+1, 1, t_cur, bdef->outs[i].width, bdef->outs[i].period, -1);
// fdelay_configure_output_pulse()
/* p.rep = -1;
p.mode = FD_OUT_MODE_PULSE;
p.start = t_cur;
p.end = ts_add(t_cur, width);*/
// fdelay_pico_to_time(&bdef->outs[i].period, &p.loop);
// fdelay_config_pulse(bdef->b, i, &p);
}
}
/*enable input */
for(i=0;i<4;i++)
if(bdef->outs[i].enabled)
while(!fdelay_channel_triggered(bdef->b, i+1)) usleep(100000);
printf("Configuration complete\n");
fflush(stdout);
return 0;
}
void handle_readout(struct board_def *bdef)
{
int64_t t_ps;
fdelay_time_t t;
static time_t start;
int done;
while(fdelay_read(bdef->b, &t, 1) == 1)
{
t_ps = (t.coarse * 8000LL) + ((t.frac * 8000LL) >> 12);
printf("card 0x%04x, seq %5i: time %lli s, %lli.%03lli ns [%x] ", bdef->hw_index, t.seq_id, t.utc, t_ps / 1000LL, t_ps % 1000LL, t.coarse);
printf("raw utc=%lld coarse=%d startoffs=%d suboffs=%d frac=%d [%x]\n", t.raw.utc, t.raw.coarse, t.raw.start_offset, t.raw.subcycle_offset, t.raw.frac- 30000, t.raw.frac);
log_write(&t, bdef->hw_index);
}
}
void sighandler(int sig)
{
if(sig == SIGINT || sig== SIGTERM || sig==SIGKILL)
{
fprintf(stderr,"Cleaniung up...\n");
log_stop();
exit(0);
}
}
int fdelay_dbg_sync_lost(fdelay_device_t *dev);
int main(int argc, char *argv[])
{
int i, maxfd = -1;
fd_set allset, curset;
signal(SIGINT, sighandler);
signal(SIGTERM, sighandler);
signal(SIGKILL, sighandler);
if(argc < 2)
{
printf("usage: %s <configuration-file>\n", argv[0]);
return 0;
}
load_config(argv[1]);
for(i=0;i<MAX_BOARDS;i++)
if(boards[i].in_use) {
int fd;
configure_board(&boards[i]);
}
for(i=0;i<MAX_BOARDS;i++)
if(boards[i].in_use) {
int fd;
fdelay_configure_readout(boards[i].b, 1);
fdelay_configure_trigger(boards[i].b, 1, boards[i].term_on);
}
for(;;)
{
for(i=0;i<MAX_BOARDS;i++) {
if(!boards[i].in_use)
continue;
// printf(".");
handle_readout(&boards[i]);
if(fdelay_dbg_sync_lost(boards[i].b))
{
printf("Weird, sync lost @ board %x. Reconfiguring...\n", boards[i].b);
configure_board(&boards[i]);
}
}
usleep(100);
}
}
This diff is collapsed.
......@@ -9,22 +9,28 @@ main(int argc, char *argv[])
fdelay_device_t dev;
fdelay_time_t t_cur, t_start;
if(spec_fdelay_init(argc, argv, &dev) < 0)
if(spec_fdelay_init(&dev, 5, 0) < 0)
return -1;
// Get the current time of the FD core - and program the card to start producing the PPS and 10 MHz one second later */
fdelay_get_time(&dev, &t_cur);
printf("Current Time: %lld:%d\n", t_cur.utc, t_cur.coarse);
t_cur.utc = 0;
t_cur.coarse = 0;
fdelay_configure_sync(&dev, FDELAY_SYNC_LOCAL);
fdelay_set_time(&dev, t_cur);
printf("Current Time: %ld:%d\n", t_cur.utc, t_cur.coarse);
fdelay_get_time(&dev, &t_cur);
printf("Current Time: %ld:%d\n", t_cur.utc, t_cur.coarse);
t_start.coarse = t_cur.coarse;
t_start.utc = t_cur.utc+1;
t_start.coarse = 0;//t_cur.coarse;
t_start.utc = t_cur.utc + 3;
t_start.frac = 0;
fdelay_configure_pulse_gen(&dev, 1, 1, t_start, 48000LL, 100000LL, -1); /* Output 1, period = 100 ns, width = 48 ns - a bit asymmetric 10 MHz */
fdelay_configure_pulse_gen(&dev, 2, 1, t_start, 48000LL, 1000000000000LL, -1); /* Output 2: period = 1 second, width = 48 ns - PPS signal */
fdelay_configure_pulse_gen(&dev, 2, 1, t_start, 1000000000000LL/2LL, 1000000000000LL, -1); /* Output 2: period = 1 second, width = 48 ns - PPS signal */
while(!fdelay_channel_triggered(&dev, 1) || fdelay_channel_triggered(&dev, 2))
while(!fdelay_channel_triggered(&dev, 1) || !fdelay_channel_triggered(&dev, 2))
usleep(10000); /* wait until both outputs have triggered*/;
return 0;
}
......@@ -3,7 +3,7 @@
#include "fdelay_lib.h"
#include "rr_io.h"
extern int spec_fdelay_init(int argc, char *argv[], fdelay_device_t *dev);
extern int spec_fdelay_init(fdelay_device_t *dev, int pbus, int pdev);
main(int argc, char *argv[])
{
......@@ -11,12 +11,14 @@ main(int argc, char *argv[])
fdelay_time_t t;
/* Initialize the fine delay generator */
if(spec_fdelay_init(argc, argv, &dev) < 0)
if(spec_fdelay_init(&dev, 0x05, 0x00) < 0)
{
fdelay_show_test_results();
// fdelay_show_test_results();
return -1;
}
return 0;
/* Enable trigger input and 50 ohm termination */
/* Enable all outputs and set them to 500 ns delay, 100 ns pulse width, single output pulse per trigger */
......
#BIG WARNING: the offsets in this file are for the hacked version of fdelay-gs, which uses fdelay test program instead of the real driver.
# use with caution!
#Path to the timestamp log file
log_file ./pp.log
#######################
# Select board 0
#######################
board 0
# Hardware index if the board (i.e. the PCIe bus/dev)
hw_index 0x0b00
# Select termination (warning! affects the accuracy!)
termination 0
# WARNING!!! These are fine delay card calibration values, obtained with time interval measurements.
# Don't change unless you know what you are doing.
# WARNING 2: define these for ALL boards independently
input_offset -69100p
output_offset 20400p
# Output configuration
# out output_ID offset_from_pps[ps] width[ps] period[ps]
# out 1 = PPS signal, 1us pulse width
out 1 0 500u 1000u
out 2 0 500u 1000u
out 4 0 500u 1000u
out 3 0 250u 499999990p
# #######################
# # Select board 1
# #######################
#
board 1
hw_index 0x0500
input_offset -69100p
output_offset 20400p
termination 0
out 1 0 500u 1000u
out 2 0 500u 1000u
out 4 0 500u 1000u
out 3 0 250u 499999990p
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "fdelay_lib.h"
#include "rr_io.h"
void spec_writel(void *priv, uint32_t data, uint32_t addr)
{