Commit 42eb52c4 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

uploaded Fine Delay production test suite from INCAA

parent b994489a
#!/bin/sh
# Copyright CERN, 2011
# Author: Matthieu Cattin <matthieu.cattin@cern.ch>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
LOGDIR=./log_fmcdelay1ns4cha
mkdir -p $LOGDIR
sudo rm -fr $LOGDIR/pts*
serial=$1
if [ x$1 = x"" ]; then
echo -n "Please scan CERN serial number bar-code, then press [ENTER]: "
read serial
fi
if [ x$serial = x"" ]; then
serial=0000
fi
extra_serial=$2
if [ x$2 = x"" ]; then
echo -n "If needed input extra serial number and press [ENTER] OR just press [ENTER]: "
read extra_serial
fi
if [ x$extra_serial = x"" ]; then
extra_serial=0000
fi
echo " "
nb_test_limit=2
nb_test=1
while [ "$nb_test" -le "$nb_test_limit" ]
do
echo "--------------------------------------------------------------"
echo "Test series run $nb_test out of $nb_test_limit"
echo " "
sudo ./ptsDelay.py -b FmcDelay1ns4cha -s $serial -e $extra_serial -t./test/fmcdelay1ns4cha/python -l $LOGDIR 00 01 02 03 04 05
if [ "$nb_test" != "$nb_test_limit" ]
then
echo " "
echo -n "Do you want to run the test series again [y,n]? "
read reply
if [ "$reply" != "y" ]
then
break
fi
fi
nb_test=$(($nb_test+1))
done
echo "--------------------------------------------------------------"
echo " "
echo -n "End of the test, do you want to switch the computer OFF? [y,n]"
read reply
if [ "$reply" = "y" ]
then
sudo halt
fi
This diff is collapsed.
*******************************************************************************
FmcDelay1ns4cha tests for PTS environment
*******************************************************************************
CERN, 2012 (INCAA Computers BV)
Author: Bert Gooijer <bert.gooijer@incaacomputers.com>
Licence: GPL v2 or later.
Website: http://www.ohwr.org/projects/pts
Website: http://www.incaacomputers.com
This batch of tests tests the solderings of the FmcAdc100M14b4cha:
- test00: Load firmware, initialize and self-calibrate Fine Delay Card
- test01: Test of the leds
- test02: DMTD calibration procedure for zero offsets
- test03: Test of writing calibration data to EEPROM (reads back for validation)
- test04: Test of output enable lines and front panel signals with CNT-91 via USB
- test05: Write IPMI card information into EEPROM
This tests are made to work stand-alone too. So, it is possible to call each one using 'sudo ./test0x.py'
Before running standalone you have to install driver by running shortcut on desktop.
These tests are designed to use Python 2.7 or higher.
The following Python libraries are needed:
- scipy
- matplotlib
- Pyro4
It might be needed to create this file as well:
/usr/lib/python2.7/dist-packages/larz/__init__.py
This note explains how to setup an Ubuntu PC for FmcDelay1ns4cha production
test suite.
Ubuntu version must be 11.04
The following packages must be installed:
git
python-scipy
python-matplotlib
Copy PTS git repository:
cd ~
git clone git://ohwr.org/misc/pts.git
Pyro4 must be installed:
cd ~/pts/test/fmcadc100m14b4cha/python/
tar -xf Pyro4-4.10.tar.gz
cd Pyro4-4.10
chmod +x setup.py
sudo python setup.py install
Create the following file:
sudo touch /usr/lib/python2.7/dist-packages/larz/__init__.py
Compile spec-sw stuff:
cd ~/pts/spec-sw/kernel
make install all modules
remove spec driver from /lib/modules so rawrabbit driver can be loaded for other cards
Install specdriver
gksu insmod /home/user/pts/spec-sw/kernel/spec.ko
It can be placed in an executable file on the desktop
running it from the PTS suite installs the driver automatically
Compile usbtmc stuff:
cd ~/pts/usbdriver
make
Install usbtmc driver:
make file usbtmc in folder /etc/init.d with this command in it: sudo /home/user/pts/usbdriver/usbtmc_load
sudo update-rc.d usbtmc defaults
test with: cat /dev/usbtmc0
Create a script file to launch the test program:
cd ~
touch run_ptsDelay.sh
chmod +x run_ptsDelay.sh
Edit the script file as follow:
#!/bin/sh
echo " "
echo " "
echo "********************************************************************************"
echo "* FmcDelay1ns4cha Test program *"
echo "********************************************************************************"
echo " "
cd ~/pts && sudo ./fmcdelay1ns4cha.sh
Create an alias to be able to launch the test program by typing "test".
Add the fllowing to ~/.bashrc
alias testDelay='~/run_ptsDelay.sh'
Define bash as the default shell:
chsh -s /bin/bash <username>
In "System > Preferences > Startup Applications" add the following to
automatically open a terminal at startup:
Command: gnome-terminal
#ifndef __ACAM_GPX_H
#define __ACAM_GPX_H
#define AR0_ROsc (1<<0)
#define AR0_RiseEn0 (1<<1)
#define AR0_FallEn0 (1<<2)
#define AR0_RiseEn1 (1<<3)
#define AR0_FallEn1 (1<<4)
#define AR0_RiseEn2 (1<<5)
#define AR0_FallEn2 (1<<6)
#define AR0_HQSel (1<<7)
#define AR0_TRiseEn(port) (1<<(10+port))
#define AR0_TFallEn(port) (1<<(19+port))
#define AR1_Adj(chan, value) (((value) & 0xf) << (chan * 4))
#define AR2_GMode (1<<0)
#define AR2_IMode (1<<1)
#define AR2_RMode (1<<2)
#define AR2_Disable(chan) (1<<(3+chan))
#define AR2_Adj(chan, value) (((value)&0xf)<<(12+4*(chan-7)))
#define AR3_RaSpeed(num,val) (val << (num*2 + 21))
#define AR3_Zero (0) // nothing interesting for the Fine Delay
#define AR4_StartTimer(value) ((value) & 0xff)
#define AR4_Quiet (1<<8)
#define AR4_MMode (1<<9)
#define AR4_MasterReset (1<<22)
#define AR4_PartialReset (1<<23)
#define AR4_AluTrigSoft (1<<24)
#define AR4_EFlagHiZN (1<<25)
#define AR4_MTimerStart (1<<26)
#define AR4_MTimerStop (1<<27)
#define AR5_StartOff1(value) ((value)&0x3ffff)
#define AR5_StopDisStart (1<<21)
#define AR5_StartDisStart (1<<22)
#define AR5_MasterAluTrig (1<<23)
#define AR5_PartialAluTrig (1<<24)
#define AR5_MasterOenTrig (1<<25)
#define AR5_PartialOenTrig (1<<26)
#define AR5_StartRetrig (1<<27)
#define AR6_Fill(value) ((value)&0xff)
#define AR6_StartOff2(value) (((value)&0x3ffff)<<8)
#define AR6_InSelECL (1<<26)
#define AR6_PowerOnECL (1<<27)
#define AR7_HSDiv(value) ((value)&0xff)
#define AR7_RefClkDiv(value) (((value)&0x7)<<8)
#define AR7_ResAdj (1<<11)
#define AR7_NegPhase (1<<12)
#define AR7_Track (1<<13)
#define AR7_MTimer(value) (((value) & 0x1ff)<<15)
#define AR14_16BitMode (1<<4)
#define AR8I_IFIFO1(reg) ((reg) & 0x1ffff)
#define AR8I_Slope1(reg) ((reg) & (1<<17) ? 1 : 0)
#define AR8I_StartN1(reg) (((reg) >> 18) & 0xff)
#define AR8I_ChaCode1(reg) (((reg) >> 26) & 0x3)
#define AR9I_IFIFO2(reg) ((reg) & 0x1ffff)
#define AR9I_Slope2(reg) ((reg) & (1<<17) ? 1 : 0)
#define AR9I_StartN2(reg) (((reg) >> 18) & 0xff)
#define AR9I_ChaCode2(reg) (((reg) >> 26) & 0x3)
#define AR8R_IFIFO1(reg) ((reg) & 0x3fffff)
#define AR9R_IFIFO2(reg) ((reg) & 0x3fffff)
#define AR11_StopCounter0(num) ((num) & 0xff)
#define AR11_StopCounter1(num) (((num) & 0xff) << 8)
#define AR11_HFifoErrU(num) (1 << (num+16))
#define AR11_IFifoErrU(num) (1 << (num+24))
#define AR11_NotLockErrU (1 << 26)
#define AR12_HFifoE (1<<11)
#define AR12_NotLocked (1<<10)
#endif
/*
Register definitions for slave core: Fine Delay Channel WB Slave
* File : fd_channel_regs.h
* Author : auto-generated by wbgen2 from fd_channel_wishbone_slave.wb
* Created : Wed Apr 11 11:05:22 2012
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE fd_channel_wishbone_slave.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_FD_CHANNEL_WISHBONE_SLAVE_WB
#define __WBGEN2_REGDEFS_FD_CHANNEL_WISHBONE_SLAVE_WB
#include <inttypes.h>
#if defined( __GNUC__)
#define PACKED __attribute__ ((packed))
#else
#error "Unsupported compiler?"
#endif
#ifndef __WBGEN2_MACROS_DEFINED__
#define __WBGEN2_MACROS_DEFINED__
#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))
#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))
#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))
#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))
#endif
/* definitions for register: Delay Control Register */
/* definitions for field: Enable channel in reg: Delay Control Register */
#define FD_DCR_ENABLE WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Delay mode select in reg: Delay Control Register */
#define FD_DCR_MODE WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Pulse generator arm in reg: Delay Control Register */
#define FD_DCR_PG_ARM WBGEN2_GEN_MASK(2, 1)
/* definitions for field: Pulse generator triggered in reg: Delay Control Register */
#define FD_DCR_PG_TRIG WBGEN2_GEN_MASK(3, 1)
/* definitions for field: Start Delay Update in reg: Delay Control Register */
#define FD_DCR_UPDATE WBGEN2_GEN_MASK(4, 1)
/* definitions for field: Delay Update Done in reg: Delay Control Register */
#define FD_DCR_UPD_DONE WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Force Calibration Delay in reg: Delay Control Register */
#define FD_DCR_FORCE_DLY WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Disable Fine Part update in reg: Delay Control Register */
#define FD_DCR_NO_FINE WBGEN2_GEN_MASK(7, 1)
/* definitions for field: Disable Fine Part update in reg: Delay Control Register */
#define FD_DCR_FORCE_HI WBGEN2_GEN_MASK(8, 1)
/* definitions for register: Fine Range Register */
/* definitions for register: Pulse start time / offset (MSB TAI seconds) */
/* definitions for register: Pulse start time / offset (LSB TAI seconds) */
/* definitions for register: Pulse start time / offset (8 ns cycles) */
/* definitions for register: Pulse start time / offset (sub-cycle fine part) */
/* definitions for register: Pulse end time / offset (MSB TAI seconds) */
/* definitions for register: Pulse end time / offset (LSB TAI seconds) */
/* definitions for register: Pulse end time / offset (8 ns cycles) */
/* definitions for register: Pulse end time / offset (sub-cycle fine part) */
/* definitions for register: Pulse spacing (TAI seconds) */
/* definitions for register: Pulse spacing (8 ns cycles) */
/* definitions for register: Pulse spacing (sub-cycle fine part) */
/* definitions for register: Repeat Count Register */
/* definitions for field: Repeat Count in reg: Repeat Count Register */
#define FD_RCR_REP_CNT_MASK WBGEN2_GEN_MASK(0, 16)
#define FD_RCR_REP_CNT_SHIFT 0
#define FD_RCR_REP_CNT_W(value) WBGEN2_GEN_WRITE(value, 0, 16)
#define FD_RCR_REP_CNT_R(reg) WBGEN2_GEN_READ(reg, 0, 16)
/* definitions for field: Continuous Waveform Mode in reg: Repeat Count Register */
#define FD_RCR_CONT WBGEN2_GEN_MASK(16, 1)
/* [0x0]: REG Delay Control Register */
#define FD_REG_DCR 0x00000000
/* [0x4]: REG Fine Range Register */
#define FD_REG_FRR 0x00000004
/* [0x8]: REG Pulse start time / offset (MSB TAI seconds) */
#define FD_REG_U_STARTH 0x00000008
/* [0xc]: REG Pulse start time / offset (LSB TAI seconds) */
#define FD_REG_U_STARTL 0x0000000c
/* [0x10]: REG Pulse start time / offset (8 ns cycles) */
#define FD_REG_C_START 0x00000010
/* [0x14]: REG Pulse start time / offset (sub-cycle fine part) */
#define FD_REG_F_START 0x00000014
/* [0x18]: REG Pulse end time / offset (MSB TAI seconds) */
#define FD_REG_U_ENDH 0x00000018
/* [0x1c]: REG Pulse end time / offset (LSB TAI seconds) */
#define FD_REG_U_ENDL 0x0000001c
/* [0x20]: REG Pulse end time / offset (8 ns cycles) */
#define FD_REG_C_END 0x00000020
/* [0x24]: REG Pulse end time / offset (sub-cycle fine part) */
#define FD_REG_F_END 0x00000024
/* [0x28]: REG Pulse spacing (TAI seconds) */
#define FD_REG_U_DELTA 0x00000028
/* [0x2c]: REG Pulse spacing (8 ns cycles) */
#define FD_REG_C_DELTA 0x0000002c
/* [0x30]: REG Pulse spacing (sub-cycle fine part) */
#define FD_REG_F_DELTA 0x00000030
/* [0x34]: REG Repeat Count Register */
#define FD_REG_RCR 0x00000034
#endif
This diff is collapsed.
#ifndef __FD_LIB_H
#define __FD_LIB_H
#include <stdint.h>
/* Number of fractional bits in the timestamps/time definitions. Must be consistent with the HDL bitstream. */
#define FDELAY_FRAC_BITS 12
/* fdelay_get_timing_status() return values: */
#define FDELAY_FREE_RUNNING 0x10 /* local oscillator is free running */
#define FDELAY_WR_OFFLINE 0x8 /* attached WR core is offline */
#define FDELAY_WR_READY 0x1 /* attached WR core is synchronized, we can sync the fine delay core anytime */
#define FDELAY_WR_SYNCING 0x2 /* local oscillator is being synchronized with WR clock */
#define FDELAY_WR_SYNCED 0x4 /* we are synced. */
#define FDELAY_WR_NOT_PRESENT 0x20 /* No WR Core present */
/* fdelay_configure_sync() flags */
#define FDELAY_SYNC_LOCAL 0x1 /* use local oscillator */
#define FDELAY_SYNC_WR 0x2 /* use White Rabbit */
/* fdelay_init() flags */
#define FDELAY_RAW_READOUT 0x1
#define FDELAY_PERFORM_LONG_TESTS 0x2
/* Hardware "handle" structure */
typedef struct fdelay_device
{
/* Base address of the FD core (relative to the beginning of local writel/readl address spaces) */
uint32_t base_addr;
/* Bus-specific readl/writel functions - so the same library can be used both with
RawRabbit, VME and Etherbone backends */
void (*writel)(void *priv, uint32_t data, uint32_t addr);
uint32_t (*readl)(void *priv, uint32_t addr);
void *priv_fd; /* pointer to Fine Delay library private data */
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;
uint32_t tsbcr;
} fdelay_raw_time_t;
typedef struct
{
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 */
} fdelay_time_t;
/*
--------------------
PUBLIC API
--------------------
*/
/* Creates a local instance of Fine Delay Core at address base_addr on the SPEC at bus/devfn. Returns 0 on success, negative on error. */
int spec_fdelay_create_bd(fdelay_device_t *dev, int bus, int dev_fn, uint32_t base);
/* A shortcut for test program, parsing the card base/location from command line args */
int spec_fdelay_create(fdelay_device_t *dev, int argc, char *argv[]);
/* Helper functions - converting FD timestamp format from/to plain picoseconds */
fdelay_time_t fdelay_from_picos(const uint64_t ps);
int64_t fdelay_to_picos(const fdelay_time_t t);
/* Enables/disables raw timestamp readout mode (debugging only) */
int fdelay_raw_readout(fdelay_device_t *dev, int raw_moide);
/* Initializes and calibrates the device. 0 = success, negative = error */
int fdelay_init(fdelay_device_t *dev, int init_flags);
/* Disables and releases the resources for a given FD Card */
int fdelay_release(fdelay_device_t *dev);
/* Returns an explaination of the last error occured on device dev (TBI) */
char *fdelay_strerror(fdelay_device_t *dev);
/* Sets the timing reference for the card (ref source). Currently there are two choices:
- FDELAY_SYNC_LOCAL - use local oscillator
- FDELAY_SYNC_WR - use White Rabbit */
int fdelay_set_timing_reference(fdelay_device_t *dev, int ref_source);
/* Polls the current status of the timing source. Returns a combination of
.... SYNCED flags. wait_mask can enable/disable waiting for a change of
a particular flag or set of flags. For example, calling
fdelay_get_timing_status(dev, FDELAY_WR_SYNCED) will wait until a change of
FDELAY_WR_SYNCED bit. */
int fdelay_get_timing_status(fdelay_device_t *dev, int wait_mask);
/* Configures the trigger input (TDC/Delay modes). enable enables the input,
termination switches on/off the built-in 50 Ohm termination resistor */
int fdelay_configure_trigger(fdelay_device_t *dev, int enable, int termination);
/* Configures timestamp buffer capture: enable = TS buffer enabled, channel mask:
channels to time tag (bit 0 = TDC, bits 1..4 = outputs 1..4) */
int fdelay_configure_capture (fdelay_device_t *dev, int enable, int channel_mask);
/* Reads how_many timestamps from the buffer. Blocking */
/* TODO: non-blocking version? */
int fdelay_read (fdelay_device_t *dev, fdelay_time_t *timestamps, int how_many);
/* (delay mode only) Configures output(s) selected in channel_mask to work in delay mode. Delta_ps = spacing between
the rising edges of subsequent pulses. */
int fdelay_configure_delay (fdelay_device_t *dev, int channel_mask, int enable, int64_t delay_ps, int64_t width_ps, int64_t delta_ps, int repeat_count);
/* (pulse mode only) Configures output(s) selected in channel_mask to produce pulse(s) starting at (start) with appropriate width/spacing/repeat_count */
int fdelay_configure_pulse_gen(fdelay_device_t *dev, int channel_mask, int enable, fdelay_time_t start, int64_t width_ps, int64_t delta_ps, int repeat_count);
/* (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);
int fdelay_dmtd_calibration(fdelay_device_t *dev, const char *filename, uint32_t *userTimeout);
int fdelay_write_eeprom_from_file(fdelay_device_t *dev, const char *filename, uint32_t offset);
#endif
/*
FmcDelay1ns4Cha (a.k.a. The Fine Delay Card)
User-space driver/library
Private includes
Tomasz Włostowski/BE-CO-HT, 2011
(c) Copyright CERN 2011
Licensed under LGPL 2.1
*/
#ifndef __FDELAY_PRIVATE_H
#define __FDELAY_PRIVATE_H
#include <stdint.h>
/* SPI Bus chip selects */
#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) */
#define SGPIO_OUTPUT_EN(x) (1<<(6-x)) /* Output driver enable (1 = on) */
#define SGPIO_TRIG_SEL (1<<6) /* TDC trigger select (0 = trigger input, 1 = FPGA) */
#define SGPIO_CAL_EN (1<<7) /* Calibration mode enable (0 = on) */
/* ACAM TDC operation modes */
#define ACAM_RMODE 0
#define ACAM_IMODE 1
/* MCP23S17 register addresses (only ones which are used by the lib) */
#define MCP_IODIR 0x0
#define MCP_IPOL 0x1
#define MCP_OLAT 0x14
#define MCP_IOCON 0x0a
#define MCP_GPIO 0x12
/* Number of fractional bits in the timestamps/time definitions. Must be consistent with the HDL bitstream. */
#define FDELAY_FRAC_BITS 12
/* Fractional bits shifted away when converting the fine (< 8ns) part to fit the range of SY89295 delay line. */
#define FDELAY_SCALER_SHIFT 12
/* Number of delay line taps */
#define FDELAY_NUM_TAPS 1024
/* How many times each calibration measurement will be averaged */
#define FDELAY_CAL_AVG_STEPS 1024
/* Fine Delay Card Magic ID */
#define FDELAY_MAGIC_ID 0xf19ede1a
/* RSTR Register value which triggers a reset of the FD Core */
#define FDELAY_RSTR_TRIGGER 0xdeadbeef
/* Calibration eeprom I2C address */
#define EEPROM_ADDR 0x50
#define EEPROM_CALIB_OFFSET (6*1024)
struct fd_calib {
int64_t frr_poly[3]; /* SY89295 delay/temp poly coeffs */
uint32_t magic; /* magic ID: 0xf19ede1a */
uint32_t zero_offset[4]; /* Output zero offset, fixed point */
uint32_t adsfr_val; /* ADSFR register value */
uint32_t acam_start_offset; /* ACAM Start offset value */
uint32_t atmcr_val; /* ATMCR register value */
uint32_t tdc_zero_offset; /* Zero offset of the TDC, in ps */
/* The user can add a signed offset, in picoseconds */
int32_t tdc_user_offset;
int32_t ch_user_offset[4];
int32_t tdc_flags;
};
struct fd_calib_on_eeprom {
uint32_t hash;
uint16_t size;
uint16_t version;
struct fd_calib calib;
};
/* Internal state of the fine delay card */
struct fine_delay_hw
{
uint32_t base_addr; /* Base address of the core */
uint32_t base_onewire; /* Base address of the core */
uint32_t base_i2c; /* SPI Controller offset */
uint32_t acam_addr; /* Current state of ACAM's address lines */
double acam_bin; /* bin size of the ACAM TDC - calculated for 31.25 MHz reference */
uint32_t frr_offset[4]; /* Offset between the FRR measured at a known temperature at startup and poly-fitted FRR */
uint32_t frr_cur[4]; /* Fine range register for each output, current value (after online temp. compensation) */
int32_t cal_temp; /* SY89295 calibration temperature in 1/16 degC units */
int32_t board_temp; /* Current temperature of the board, unit = 1/16 degC */
int wr_enabled;
int wr_state;
int raw_mode;
int do_long_tests;
struct fd_calib calib;
int64_t input_user_offset, output_user_offset;
};
/* some useful access/declaration macros */
#define fd_writel(data, addr) dev->writel(dev->priv_io, data, (hw->base_addr + (addr)))
#define fd_readl(addr) dev->readl(dev->priv_io, (hw->base_addr + (addr)))
#define fd_decl_private(dev) struct fine_delay_hw *hw = (struct fine_delay_hw *) dev->priv_fd;
#endif
#ifndef __I2C_MASTER_H
#define __I2C_MASTER_H
#include <stdint.h>
#include "fdelay_lib.h"
void mi2c_init(fdelay_device_t *dev);
int eeprom_read(fdelay_device_t *dev, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size);
int eeprom_write(fdelay_device_t *dev, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size);
#endif
#ifndef _LINUX_JHASH_H
#define _LINUX_JHASH_H
#include <stdint.h>
/* jhash.h: Jenkins hash support.
*
* Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net)
*
* http://burtleburtle.net/bob/hash/
*
* These are the credits from Bob's sources:
*
* lookup3.c, by Bob Jenkins, May 2006, Public Domain.
*
* These are functions for producing 32-bit hashes for hash table lookup.
* hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
* are externally useful functions. Routines to test the hash are included
* if SELF_TEST is defined. You can use this free for any purpose. It's in
* the public domain. It has no warranty.
*
* Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
*
* I've modified Bob's hash to be useful in the Linux kernel, and
* any bugs present are my fault.
* Jozsef
*/
static inline uint32_t rol32(uint32_t word, unsigned int shift)
{
return (word << shift) | (word >> (32 - shift));
}
static inline uint32_t ror32(uint32_t word, unsigned int shift)
{
return (word >> shift) | (word << (32 - shift));
}
/* Best hash sizes are of power of two */
#define jhash_size(n) ((uint32_t)1<<(n))
/* Mask the hash value, i.e (value & jhash_mask(n)) instead of (value % n) */
#define jhash_mask(n) (jhash_size(n)-1)
/* __jhash_mix -- mix 3 32-bit values reversibly. */
#define __jhash_mix(a, b, c) \
{ \
a -= c; a ^= rol32(c, 4); c += b; \
b -= a; b ^= rol32(a, 6); a += c; \
c -= b; c ^= rol32(b, 8); b += a; \
a -= c; a ^= rol32(c, 16); c += b; \
b -= a; b ^= rol32(a, 19); a += c; \
c -= b; c ^= rol32(b, 4); b += a; \
}
/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */
#define __jhash_final(a, b, c) \
{ \
c ^= b; c -= rol32(b, 14); \
a ^= c; a -= rol32(c, 11); \
b ^= a; b -= rol32(a, 25); \
c ^= b; c -= rol32(b, 16); \
a ^= c; a -= rol32(c, 4); \
b ^= a; b -= rol32(a, 14); \
c ^= b; c -= rol32(b, 24); \
}
/* An arbitrary initial parameter */
#define JHASH_INITVAL 0xdeadbeef
/* jhash - hash an arbitrary key
* @k: sequence of bytes as key
* @length: the length of the key
* @initval: the previous hash, or an arbitray value
*
* The generic version, hashes an arbitrary sequence of bytes.
* No alignment or length assumptions are made about the input key.
*
* Returns the hash value of the key. The result depends on endianness.
*/
static uint32_t __get_unaligned_cpuint32_t(const void *ptr)
{
return *(uint32_t *)ptr; /* evil! */
}
static inline uint32_t jhash(const void *key, uint32_t length, uint32_t initval)
{
uint32_t a, b, c;
const uint8_t *k = key;
/* Set up the internal state */
a = b = c = JHASH_INITVAL + length + initval;
/* All but the last block: affect some 32 bits of (a,b,c) */
while (length > 12) {
a += __get_unaligned_cpuint32_t(k);
b += __get_unaligned_cpuint32_t(k + 4);
c += __get_unaligned_cpuint32_t(k + 8);
__jhash_mix(a, b, c);
length -= 12;
k += 12;
}
/* Last block: affect all 32 bits of (c) */
/* All the case statements fall through */
switch (length) {
case 12: c += (uint32_t)k[11]<<24;
case 11: c += (uint32_t)k[10]<<16;
case 10: c += (uint32_t)k[9]<<8;
case 9: c += k[8];
case 8: b += (uint32_t)k[7]<<24;
case 7: b += (uint32_t)k[6]<<16;
case 6: b += (uint32_t)k[5]<<8;
case 5: b += k[4];
case 4: a += (uint32_t)k[3]<<24;
case 3: a += (uint32_t)k[2]<<16;
case 2: a += (uint32_t)k[1]<<8;
case 1: a += k[0];
__jhash_final(a, b, c);
case 0: /* Nothing left to add */
break;
}
return c;
}
/* jhash2 - hash an array of uint32_t's
* @k: the key which must be an array of uint32_t's
* @length: the number of uint32_t's in the key
* @initval: the previous hash, or an arbitray value
*
* Returns the hash value of the key.
*/
static inline uint32_t jhash2(const uint32_t *k, uint32_t length, uint32_t initval)
{
uint32_t a, b, c;
/* Set up the internal state */
a = b = c = JHASH_INITVAL + (length<<2) + initval;
/* Handle most of the key */
while (length > 3) {
a += k[0];
b += k[1];
c += k[2];
__jhash_mix(a, b, c);
length -= 3;
k += 3;
}
/* Handle the last 3 uint32_t's: all the case statements fall through */
switch (length) {
case 3: c += k[2];
case 2: b += k[1];
case 1: a += k[0];
__jhash_final(a, b, c);
case 0: /* Nothing left to add */
break;
}
return c;
}
/* jhash_3words - hash exactly 3, 2 or 1 word(s) */
static inline uint32_t jhash_3words(uint32_t a, uint32_t b, uint32_t c, uint32_t initval)
{
a += JHASH_INITVAL;
b += JHASH_INITVAL;
c += initval;
__jhash_final(a, b, c);
return c;
}
static inline uint32_t jhash_2words(uint32_t a, uint32_t b, uint32_t initval)
{
return jhash_3words(a, b, 0, initval);
}
static inline uint32_t jhash_1word(uint32_t a, uint32_t initval)
{
return jhash_3words(a, 0, 0, initval);
}
#endif /* _LINUX_JHASH_H */
#ifndef ONEWIRE_H_INCLUDED
#define ONEWIRE_H_INCLUDED
#include "fdelay_lib.h"
int ds18x_init(fdelay_device_t *dev);
int ds18x_read_temp(fdelay_device_t *dev, int *temp_r);
#endif // ONEWIRE_H_INCLUDED
const struct {int reg; uint8_t val; } ad9516_regs[] = {
{0x0000, 0x99},
{0x0001, 0x00},
{0x0002, 0x10},
{0x0003, 0xC3},
{0x0004, 0x00},
{0x0010, 0x7C},
{0x0011, 0x05},
{0x0012, 0x00},
{0x0013, 0x0C},
{0x0014, 0x12},
{0x0015, 0x00},
{0x0016, 0x05},
{0x0017, 0xb4}, /* PLL_STATUS = Lock Detect */
{0x0018, 0x07},
{0x0019, 0x00},
{0x001A, 0x00},
{0x001B, 0xE0},
{0x001C, 0x02},
{0x001D, 0x00},
{0x001E, 0x00},
{0x001F, 0x0E},
{0x00A0, 0x01},
{0x00A1, 0x00},
{0x00A2, 0x00},
{0x00A3, 0x01},
{0x00A4, 0x00},
{0x00A5, 0x00},
{0x00A6, 0x01},
{0x00A7, 0x00},
{0x00A8, 0x00},
{0x00A9, 0x01},
{0x00AA, 0x00},
{0x00AB, 0x00},
{0x00F0, 0x08},
{0x00F1, 0x08},
{0x00F2, 0x08},
{0x00F3, 0x18}, /* out3 inverted */
{0x00F4, 0x00},
{0x00F5, 0x08},
{0x0140, 0x5A},
{0x0141, 0x5A},
{0x0142, 0x5B},
{0x0143, 0x42},
{0x0190, 0x00},
{0x0191, 0x80},
{0x0192, 0x00},
{0x0193, 0x00},
{0x0194, 0x80},
{0x0195, 0x00},
{0x0196, 0xFF},
{0x0197, 0x00},
{0x0198, 0x00},
{0x0199, 0x33},
{0x019A, 0x00},
{0x019B, 0x11},
{0x019C, 0x20},
{0x019D, 0x00},
{0x019E, 0x00},
{0x019F, 0x00},
{0x01A0, 0x11},
{0x01A1, 0x20},
{0x01A2, 0x00},
{0x01A3, 0x00},
{0x01E0, 0x04}, /* VCODIV = 6 */
{0x01E1, 0x02},
{0x0230, 0x00},
{0x0231, 0x00},
{0x0232, 0x00},
{-1, 0}};
/*
* Public header for the raw I/O interface for PCI or PCI express interfaces
*
* Copyright (C) 2010 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Released according to the GNU GPL, version 2 or any later version.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __RAWRABBIT_H__
#define __RAWRABBIT_H__
#include <linux/types.h>
#include <linux/ioctl.h>
#ifdef __KERNEL__ /* The initial part of the file is driver-internal stuff */
#include <linux/pci.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
#include <linux/firmware.h>
#include <linux/wait.h>
#include <linux/completion.h>
struct rr_devsel;
struct rr_dev {
struct rr_devsel *devsel;
struct pci_driver *pci_driver;
struct pci_device_id *id_table;
struct pci_dev *pdev; /* non-null after pciprobe */
struct mutex mutex;
wait_queue_head_t q;
void *dmabuf;
char *fwname;
struct timespec irqtime;
unsigned long irqcount;
struct completion complete;
struct resource *area[3]; /* bar 0, 2, 4 */
void *remap[3]; /* ioremap of bar 0, 2, 4 */
unsigned long flags;
struct work_struct work;
const struct firmware *fw;
struct completion fw_load;
void (*load_program)(struct rr_dev *); /* lm32 */
int usecount;
#ifdef IS_SPEC_DEMO
struct miscdevice misc;
char miscname[32]; /* "spec-demo-<bus>-<slot> */
struct list_head list;
#endif
};
extern char *rr_fwname; /* module parameter. If "" then defaults apply */
#define RR_FLAG_REGISTERED 0x00000001
#define RR_FLAG_IRQDISABLE 0x00000002
#define RR_FLAG_IRQREQUEST 0x00000002
#define RR_PROBE_TIMEOUT (HZ) /* for pci_register_drv */
/* These two live in ./loader.c */
extern void rr_ask_firmware(struct rr_dev *dev);
extern void rr_load_firmware(struct work_struct *work);
/* And, for the spec only, this is in ./spec-loader.c */
extern void spec_ask_program(struct rr_dev *dev);
#endif /* __KERNEL__ */
/* By default, the driver registers for this vendor/devid */
#define RR_DEFAULT_VENDOR 0x1a39
#define RR_DEFAULT_DEVICE 0x0004
#define RR_DEFAULT_FWNAME "rrabbit-%P-%p@%b"
#define RR_MAX_FWNAME_SIZE 64
#define RR_DEFAULT_BUFSIZE (1<<20) /* 1MB */
#define RR_PLIST_SIZE 4096 /* no PAGE_SIZE in user space */
#define RR_PLIST_LEN (RR_PLIST_SIZE / sizeof(void *))
#define RR_MAX_BUFSIZE (RR_PLIST_SIZE * RR_PLIST_LEN)
/* This structure is used to select the device to be accessed, via ioctl */
struct rr_devsel {
__u16 vendor;
__u16 device;
__u16 subvendor; /* RR_DEVSEL_UNUSED to ignore subvendor/dev */
__u16 subdevice;
__u16 bus; /* RR_DEVSEL_UNUSED to ignore bus and devfn */
__u16 devfn;
};
#define RR_DEVSEL_UNUSED 0xffff
/* Offsets for BAR areas in llseek() and/or ioctl */
#define RR_BAR_0 0x00000000
#define RR_BAR_2 0x20000000
#define RR_BAR_4 0x40000000
#define RR_BAR_BUF 0xc0000000 /* The DMA buffer */
#define RR_IS_DMABUF(addr) ((addr) >= RR_BAR_BUF)
#define __RR_GET_BAR(x) ((x) >> 28)
#define __RR_SET_BAR(x) ((x) << 28)
#define __RR_GET_OFF(x) ((x) & 0x0fffffff)
static inline int rr_is_valid_bar(unsigned long address)
{
int bar = __RR_GET_BAR(address);
return bar == 0 || bar == 2 || bar == 4 || bar == 0x0c;
}
static inline int rr_is_dmabuf_bar(unsigned long address)
{
int bar = __RR_GET_BAR(address);
return bar == 0x0c;
}
struct rr_iocmd {
__u32 address; /* bar and offset */
__u32 datasize; /* 1 or 2 or 4 or 8 */
union {
__u8 data8;
__u16 data16;
__u32 data32;
__u64 data64;
};
};
/* ioctl commands */
#define __RR_IOC_MAGIC '4' /* random or so */
#define RR_DEVSEL _IOW(__RR_IOC_MAGIC, 0, struct rr_devsel)
#define RR_DEVGET _IOR(__RR_IOC_MAGIC, 1, struct rr_devsel)
#define RR_READ _IOWR(__RR_IOC_MAGIC, 2, struct rr_iocmd)
#define RR_WRITE _IOW(__RR_IOC_MAGIC, 3, struct rr_iocmd)
#define RR_IRQWAIT _IO(__RR_IOC_MAGIC, 4)
#define RR_IRQENA _IO(__RR_IOC_MAGIC, 5)
#define RR_GETDMASIZE _IO(__RR_IOC_MAGIC, 6)
/* #define RR_SETDMASIZE _IO(__RR_IOC_MAGIC, 7, unsigned long) */
#define RR_GETPLIST _IO(__RR_IOC_MAGIC, 8) /* returns a whole page */
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
/* Registers from the gennum header files */
enum {
GNGPIO_BASE = 0xA00,
GNGPIO_DIRECTION_MODE = GNGPIO_BASE + 0x4,
GNGPIO_OUTPUT_ENABLE = GNGPIO_BASE + 0x8,
GNGPIO_OUTPUT_VALUE = GNGPIO_BASE + 0xC,
GNGPIO_INPUT_VALUE = GNGPIO_BASE + 0x10,
FCL_BASE = 0xB00,
FCL_CTRL = FCL_BASE,
FCL_STATUS = FCL_BASE + 0x4,
FCL_IODATA_IN = FCL_BASE + 0x8,
FCL_IODATA_OUT = FCL_BASE + 0xC,
FCL_EN = FCL_BASE + 0x10,
FCL_TIMER_0 = FCL_BASE + 0x14,
FCL_TIMER_1 = FCL_BASE + 0x18,
FCL_CLK_DIV = FCL_BASE + 0x1C,
FCL_IRQ = FCL_BASE + 0x20,
FCL_TIMER_CTRL = FCL_BASE + 0x24,
FCL_IM = FCL_BASE + 0x28,
FCL_TIMER2_0 = FCL_BASE + 0x2C,
FCL_TIMER2_1 = FCL_BASE + 0x30,
FCL_DBG_STS = FCL_BASE + 0x34,
FCL_FIFO = 0xE00,
PCI_SYS_CFG_SYSTEM = 0x800
};
#endif /* __RAWRABBIT_H__ */
#ifndef __RR_IO_H
#define __RR_IO_H
#include <stdint.h>
#include <rawrabbit.h>
int rr_bind(int a_fd);
int rr_init(int bus, int devfn);
int rr_writel(uint32_t data, uint32_t addr);
uint32_t rr_readl(uint32_t addr);
int rr_load_bitstream(const void *data, int size8);
int rr_load_bitstream_from_file(const char *file_name);
#endif
OBJS = fdelay_lib.o i2c_master.o onewire.o spec_common.o spec/tools/speclib.o spec/kernel/loader-ll.o fdelay_dmtd_calibration.o
CFLAGS = -I../include -g -Imini_bone -Ispec/tools
ifeq ($(SPEC_SW),)
throw_error:
@echo "SPEC software package location environment variable is not set. Can't compile :("
endif
all: spec lib
spec:
ln -s $(SPEC_SW) spec
lib: $(OBJS)
gcc -shared -o libfinedelay.so $(OBJS)
ar rc libfinedelay.a $(OBJS)
clean:
rm -f *.o libfinedelay.so
/*
FmcDelay1ns4Cha (a.k.a. The Fine Delay Card)
DMTD insertion delay calibration stuff
Short explaination:
We feed the input of the card with a perioid sequence of pulses, of a frequency, say,
1 MHz. The card is programmed to introduce a delay of Td. Then, we sample both the input
and the output of the card with a clock that is slightly offset in frequency wrs to the one that
was used to generate the pulses - in our case it's (1 + 1/16384) * 1 MHz. The resulting waveforms
are of very low frequency, but keep the phase shift of the original signals, scaled by a factor of 16384.
This way we can easily measure the actual insertion delay of the FD and apply a correction factor
for fdelay_configure_output().
Tomasz Włostowski/BE-CO-HT, 2012
(c) Copyright CERN 2012
Licensed under LGPL 2.1
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <math.h>
#include "fd_channel_regs.h"
#include "fd_main_regs.h"
#include "fdelay_lib.h"
#include "fdelay_private.h"
extern void dbg(const char *fmt, ...);
extern int64_t get_tics();
extern void udelay(uint32_t usecs);
uint32_t wait_promptTimeout;
/* WR core shell communication functions */
static void shell_purge(fdelay_device_t *dev)
{
char c='\r';
int i;
int64_t start_tics = get_tics();
for(i=0;i<5;i++)
spec_vuart_tx(dev->priv_io, &c, 1);
while(get_tics() - start_tics < 100000LL)
{
spec_vuart_rx(dev->priv_io, &c, 1);
}
}
/* executes a shell command on the associated WR core */
static int wrc_shell_exec(fdelay_device_t *dev, const char *cmd, char *retval, int64_t timeout)
{
char c;
char buf[16384];
int buf_pos = 0, i;
shell_purge(dev);
spec_vuart_tx(dev->priv_io, (char *)cmd, strlen(cmd));
spec_vuart_tx(dev->priv_io, "\r", 1);
int64_t start_tics = get_tics();
for(;;)
{
if(spec_vuart_rx(dev->priv_io, &c, 1) == 1)
buf[buf_pos++] = c;
if(buf_pos >= sizeof(buf))
{
return -1;
}
if(get_tics() - start_tics > timeout)
break;
}
buf[buf_pos] = 0;
if(retval)
{
int p1 = -1,p2 = -1;
strcpy(retval, "");
/* fprintf(stderr,"BUF_DUMP:\n");
for(i=0;i<buf_pos;i++)
fprintf(stderr,"%d: '%c'\n", i, buf[i]);
fprintf(stderr,"END_BUF_DUMP\n");*/
for(i=buf_pos-1;i>=0; i--) if(buf[i] == '\n' || buf[i] == '\r')
{ p2 = i; break; }
i-=2;
for(;i>=0; i--) if(buf[i] == '\n' || buf[i] == '\r')
{ p1 = i; break; }
if(p1 + 1 == p2)
strcpy(retval, "");
else
strncpy(retval, buf+p1+1, p2-p1);
for(i=0;i<strlen(retval);i++)
if(retval[i] == '\n' || retval[i] == '\r')
retval[i] = 0;
dbg("wr_core exec '%s', retval: '%s'\n", cmd, retval);
}
return 0;
}
#define DMTD_N_AVGS 10 /* number of average samples */
#define DELAY_SETPOINT 500000 /* test delay value */
#define DMTD_PULSE_PERIOD 144
#define DMTD_OUTPUT_PERIOD (16384 * DMTD_PULSE_PERIOD / 2) /* period of the DDMTD output signal in 62.5 MHz clock cycles */
struct dmtd_channel {
int64_t base;
int64_t prev_tag, phase;
int64_t period;
};
#define TAG_BITS 23
static void init_dmtd(struct dmtd_channel *ch, int64_t period)
{
ch->period = period;
ch->prev_tag = -1;
ch->base = 0;
}
static int read_dmtd(fdelay_device_t *dev, struct dmtd_channel *ch, int is_out)
{
fd_decl_private(dev)
uint32_t addr = (is_out ? FD_REG_DMTR_IN : FD_REG_DMTR_OUT);
uint32_t value = fd_readl(addr);
if(value & FD_DMTR_IN_RDY)
{
int64_t tag = (int64_t) (value & ((1<<TAG_BITS) - 1)) + ch->base;
if(ch->prev_tag >= 0 && tag < ch->prev_tag) /* DMTD tag counter has 23 bits. We need to unwrap it */
{
ch->base += (1LL<<TAG_BITS);
tag += (1LL<<TAG_BITS);
}
int64_t epoch = (tag / DMTD_OUTPUT_PERIOD) * DMTD_OUTPUT_PERIOD; /* calculate the offset between the beginning of DDMTD cycle and the current tag */
ch->phase = tag - epoch;
ch->prev_tag = tag;
return 1;
}
return 0;
}
int calibrate_channel(fdelay_device_t *dev, int channel, double *mean, double *std)
{
int64_t samples_in[DMTD_N_AVGS], samples_out[DMTD_N_AVGS], delta[DMTD_N_AVGS];
struct dmtd_channel ch_in, ch_out;
int i, n_in = 0, n_out = 0;
fd_decl_private(dev);
fdelay_configure_trigger(dev, 0, 0);
fd_writel(FD_CALR_PSEL_W(0), FD_REG_CALR);
/* Configure the output to introduce DELAY_SETPOINT delay (but with fixed offset set to 0)*/
hw->calib.zero_offset[channel-1] = 0;
fdelay_configure_output(dev, channel, 1, (int64_t)DELAY_SETPOINT, 200000LL, 0LL, 1);
/* Disable ALL outputs to prevent the calibration pulses from driving whatever
is connected to the board */
if(sgpio_set_pin(dev, SGPIO_OUTPUT_EN(0), 0) < 0)
return -1;
if(sgpio_set_pin(dev, SGPIO_OUTPUT_EN(1), 0) < 0)
return -1;
if(sgpio_set_pin(dev, SGPIO_OUTPUT_EN(2), 0) < 0)
return -1;
if(sgpio_set_pin(dev, SGPIO_OUTPUT_EN(3), 0) < 0)
return -1;
/* Select internal trigger */
if(sgpio_set_pin(dev, SGPIO_TRIG_SEL, 0) < 0)
return -1;
for(i=1;i<=4;i++) /* disable all other channels */
if(i != channel)
fd_writel(0, i * 0x100 + FD_REG_DCR);
fd_readl(FD_REG_DMTR_IN);
fd_readl(FD_REG_DMTR_OUT);
fdelay_configure_trigger(dev, 1, 0);
fd_writel(FD_CALR_PSEL_W(0) | FD_CALR_CAL_DMTD, FD_REG_CALR);
init_dmtd(&ch_in, DMTD_OUTPUT_PERIOD);
init_dmtd(&ch_out, DMTD_OUTPUT_PERIOD);
/* Get DMTD_N_AVGS samples to reduce error */
n_in = n_out = 0;
int64_t ts = get_tics();
while((n_in < DMTD_N_AVGS || n_out < DMTD_N_AVGS) && ((get_tics()-ts) < 1000000))
{
if(read_dmtd(dev, &ch_in, 0))
{
if(n_in < DMTD_N_AVGS)
samples_in[n_in++] = ch_in.phase;
}
if(read_dmtd(dev, &ch_out, 1))
{
if(n_out < DMTD_N_AVGS)
samples_out[n_out++] = ch_out.phase;
}
}
if((get_tics()-ts) >= 1000000)
{
dbg("%s has timed out\n", __FUNCTION__);
return -1;
}
for(i=0;i<DMTD_N_AVGS;i++)
{
delta[i] = samples_out[i] - samples_in[i];
if(delta[i] < 0)
delta[i] += DMTD_OUTPUT_PERIOD;
// printf("in %lld out %lld delta %lld\n", samples_in[i], samples_out[i], delta[i]);
}
double avg = 0, s= 0;
for(i=0;i<DMTD_N_AVGS;i++)
avg+=(double) (delta[i]);
avg/=(double)DMTD_N_AVGS;
double scalefact = (double) (DMTD_PULSE_PERIOD * 16000 / 2) / (double)DMTD_OUTPUT_PERIOD;
*mean = avg * scalefact;
for(i=0;i<DMTD_N_AVGS;i++)
s+=((double)delta[i]-avg) * ((double)delta[i]-avg);
*std = sqrt(s / (double)(DMTD_N_AVGS-1)) * scalefact;
/* Reset to normal trigger and disable input and output */
if(sgpio_set_pin(dev, SGPIO_TRIG_SEL, 1) < 0)
return -1;
fdelay_configure_trigger(dev, 0, 0);
fdelay_configure_output(dev, channel, 0, (int64_t)DELAY_SETPOINT, 200000LL, 0LL, 1);
return 0;
}
int fdelay_dmtd_calibration(fdelay_device_t *dev, const char *filename, uint32_t *userTimeout)
{
char resp[1024];
char c;
int i, error = 0;
fd_decl_private(dev);
wait_promptTimeout = *userTimeout;
int64_t base = 0, prev_tag = -1;
if(spec_load_lm32(dev->priv_io, filename, 0xc0000))
{
dbg("%s: Failed to load LM32 firmware\n", __FUNCTION__);
return -1;
}
//sleep(2);
/* Configure the WR core to produce a proper calibration clock: */
/* Disable PTP and enter free-running master mode */
if(wrc_shell_exec(dev, "ptp stop", resp, 100000LL) < 0)
return -1;
if(wrc_shell_exec(dev, "mode master", resp, 5000000LL) < 0)
return -1;
/* And lock the DMTD oscillator to the FMC clock instead of the SPEC 125 MHz oscillator. Set the FMC VCO DAC to 0
to have some headroom */
if(wrc_shell_exec(dev, "pll sdac 1 0", resp, 100000LL) < 0)
return -1;
if(wrc_shell_exec(dev, "pll init 2 1 1", resp, 100000LL) < 0)
return -1;
/* Wait until the PLL locks... */
int64_t ts = get_tics();
while(1)
{
if(wrc_shell_exec(dev, "pll cl 0", resp, 100000LL) < 0)
return -1;
if(!strcmp(resp, "1"))
break;
if(get_tics() - ts > 10000000LL)
{
dbg("%s has timed out, the PLL doesn't lock\n", __FUNCTION__);
return -1;
}
sleep(1);
}
double mean_out[4], std_out[4];
usleep(500000);
for(i=1;i<=4;i++)
{
dbg("\n\nPerforming DDMTD delay calibration of channel %d\n", i);
if(calibrate_channel(dev, i, &mean_out[i-1], &std_out[i-1]) < 0)
{
dbg("Failed, DMTD not possible for channel %d, DMTD Tag Ready flag is not coming high\n", i);
hw->calib.zero_offset[i-1] = 0;
error = 1;
}
else
{
dbg("Channel %d: delay %.0f ps, std %.0f ps.\n", i, mean_out[i-1], std_out[i-1]);
hw->calib.zero_offset[i-1] = mean_out[i-1] - 500000;
}
}
return error ? -1 : 0;
}
This diff is collapsed.
#include <stdio.h>
#include "fdelay_lib.h"
#include "fdelay_private.h"
#include "fd_main_regs.h"
#define M_SDA_OUT(x) \
{ \
if(x) \
fd_writel(fd_readl(FD_REG_I2CR) | FD_I2CR_SDA_OUT, FD_REG_I2CR); \
else \
fd_writel(fd_readl(FD_REG_I2CR) & (~FD_I2CR_SDA_OUT), FD_REG_I2CR); \
udelay(10); \
}
#define M_SCL_OUT(x) \
{ \
if(x) \
fd_writel(fd_readl(FD_REG_I2CR) | FD_I2CR_SCL_OUT, FD_REG_I2CR); \
else \
fd_writel(fd_readl(FD_REG_I2CR) & (~FD_I2CR_SCL_OUT), FD_REG_I2CR); \
udelay(10); \
}
#define M_SDA_IN ((fd_readl(FD_REG_I2CR) & FD_I2CR_SDA_IN) ? 1 : 0)
static void mi2c_start(fdelay_device_t *dev)
{
fd_decl_private(dev);
M_SDA_OUT(0);
M_SCL_OUT(0);
}
static void mi2c_repeat_start(fdelay_device_t *dev)
{
fd_decl_private(dev);
M_SDA_OUT(1);
M_SCL_OUT(1);
M_SDA_OUT(0);
M_SCL_OUT(0);
}
static void mi2c_stop(fdelay_device_t *dev)
{
fd_decl_private(dev);
M_SDA_OUT(0);
M_SCL_OUT(1);
M_SDA_OUT(1);
}
int mi2c_put_byte(fdelay_device_t *dev, unsigned char data)
{
fd_decl_private(dev);
char i;
unsigned char ack;
for (i=0;i<8;i++, data<<=1)
{
M_SDA_OUT(data&0x80);
M_SCL_OUT(1);
M_SCL_OUT(0);
}
M_SDA_OUT(1);
M_SCL_OUT(1);
ack = M_SDA_IN; /* ack: sda is pulled low ->success. */
M_SCL_OUT(0);
M_SDA_OUT(0);
return ack!=0 ? -1 : 0;
}
void mi2c_get_byte(fdelay_device_t *dev, unsigned char *data, int ack)
{
fd_decl_private(dev);
int i;
unsigned char indata = 0;
/* assert: scl is low */
M_SCL_OUT(0);
M_SDA_OUT(1);
for (i=0;i<8;i++)
{
M_SCL_OUT(1);
indata <<= 1;
if ( M_SDA_IN ) indata |= 0x01;
M_SCL_OUT(0);
}
M_SDA_OUT((ack ? 0 : 1));
M_SCL_OUT(1);
M_SCL_OUT(0);
M_SDA_OUT(0);
*data= indata;
}
void mi2c_init(fdelay_device_t *dev)
{
fd_decl_private(dev);
M_SCL_OUT(1);
M_SDA_OUT(1);
}
void mi2c_scan(fdelay_device_t *dev)
{
int i;
for(i=0;i<256;i+=2)
{
mi2c_start(dev);
if(!mi2c_put_byte(dev,i))
dbg("Found device at 0x%x\n", i>>1);
mi2c_stop(dev);
}
}
int eeprom_read(fdelay_device_t *dev, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size)
{
int i;
unsigned char c;
for(i=0;i<size;i++)
{
mi2c_start(dev);
if(mi2c_put_byte(dev, i2c_addr << 1) < 0)
{
mi2c_stop(dev);
return -1;
}
mi2c_put_byte(dev, (offset >> 8) & 0xff);
mi2c_put_byte(dev, offset & 0xff);
offset++;
mi2c_stop(dev);
mi2c_start(dev);
mi2c_put_byte(dev, (i2c_addr << 1) | 1);
mi2c_get_byte(dev, &c, 0);
//printf("readback: %x\n", c);
*buf++ = c;
mi2c_stop(dev);
}
return size;
}
int eeprom_write(fdelay_device_t *dev, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size)
{
int i, busy;
for(i=0;i<size;i++)
{
mi2c_start(dev);
if(mi2c_put_byte(dev, i2c_addr << 1) < 0)
{
mi2c_stop(dev);
return -1;
}
mi2c_put_byte(dev, (offset >> 8) & 0xff);
mi2c_put_byte(dev, offset & 0xff);
mi2c_put_byte(dev, *buf++);
offset++;
mi2c_stop(dev);
int64_t ts = get_tics();
do /* wait until the chip becomes ready */
{
mi2c_start(dev);
busy = mi2c_put_byte(dev, i2c_addr << 1);
mi2c_stop(dev);
} while(busy && ((get_tics()-ts) < 1000000));
if((get_tics()-ts) >= 1000000)
{
dbg("%s has timed out, the EEPROM doesn't become ready\n", __FUNCTION__);
return -1;
}
}
return size;
}
#include <stdio.h>
#include <stdint.h>
#include "fdelay_lib.h"
#include "fdelay_private.h"
extern int64_t get_tics();
#define R_CSR 0x0
#define R_CDR 0x4
#define CSR_DAT_MSK (1<<0)
#define CSR_RST_MSK (1<<1)
#define CSR_OVD_MSK (1<<2)
#define CSR_CYC_MSK (1<<3)
#define CSR_PWR_MSK (1<<4)
#define CSR_IRQ_MSK (1<<6)
#define CSR_IEN_MSK (1<<7)
#define CSR_SEL_OFS 8
#define CSR_SEL_MSK (0xF<<8)
#define CSR_POWER_OFS 16
#define CSR_POWER_MSK (0xFFFF<<16)
#define CDR_NOR_MSK (0xFFFF<<0)
#define CDR_OVD_OFS 16
#define CDR_OVD_MSK (0xFFFF<<16)
#define ow_writel(data, addr) dev->writel(dev->priv_io, data, (hw->base_onewire + (addr)))
#define ow_readl(addr) dev->readl(dev->priv_io, (hw->base_onewire + (addr)))
#define CLK_DIV_NOR 624/2
#define CLK_DIV_OVD 124/2
static void ow_init(fdelay_device_t *dev)
{
fd_decl_private(dev);
ow_writel(((CLK_DIV_NOR & CDR_NOR_MSK) | (( CLK_DIV_OVD << CDR_OVD_OFS) & CDR_OVD_MSK)), R_CDR);
}
static int ow_reset(fdelay_device_t *dev, int port)
{
fd_decl_private(dev);
uint32_t data = ((port<<CSR_SEL_OFS) & CSR_SEL_MSK) | CSR_CYC_MSK | CSR_RST_MSK;
ow_writel(data, R_CSR);
int64_t ts = get_tics();
while((ow_readl(R_CSR) & CSR_CYC_MSK) && ((get_tics()-ts) < 1000));
if((get_tics()-ts) >= 1000)
{
dbg("%s has timed out, ONEWIRE failure\n", __FUNCTION__);
return 0;
}
uint32_t reg = ow_readl(R_CSR);
return ~reg & CSR_DAT_MSK;
}
static int slot(fdelay_device_t *dev, int port, int bit)
{
fd_decl_private(dev);
uint32_t data, reg;
data = ((port<<CSR_SEL_OFS) & CSR_SEL_MSK) | CSR_CYC_MSK | (bit & CSR_DAT_MSK);
ow_writel(data, R_CSR);
int64_t ts = get_tics();
while((ow_readl(R_CSR) & CSR_CYC_MSK) && ((get_tics()-ts) < 1000));
if((get_tics()-ts) >= 1000)
{
dbg("%s has timed out, ONEWIRE failure\n", __FUNCTION__);
return 0;
}
reg = ow_readl(R_CSR);
return reg & CSR_DAT_MSK;
}
static int read_bit(fdelay_device_t *dev, int port) { return slot(dev, port, 0x1); }
static int write_bit(fdelay_device_t *dev, int port, int bit) { return slot(dev, port, bit); }
int ow_read_byte(fdelay_device_t *dev, int port)
{
int data = 0, i;
for(i=0;i<8;i++)
data |= read_bit(dev, port) << i;
return data;
}
int ow_write_byte(fdelay_device_t *dev, int port, int byte)
{
int data = 0;
int byte_old = byte, i;
for (i=0;i<8;i++)
{
data |= write_bit(dev, port, (byte & 0x1)) << i;
byte >>= 1;
}
return byte_old == data ? 0 : -1;
}
int ow_write_block(fdelay_device_t *dev, int port, uint8_t *block, int len)
{
int i;
for(i=0;i<len;i++)
*block++ = ow_write_byte(dev, port, *block);
return 0;
}
int ow_read_block(fdelay_device_t *dev, int port, uint8_t *block, int len)
{
int i;
for(i=0;i<len;i++)
*block++ = ow_read_byte(dev, port);
return 0;
}
#define ROM_SEARCH 0xF0
#define ROM_READ 0x33
#define ROM_MATCH 0x55
#define ROM_SKIP 0xCC
#define ROM_ALARM_SEARCH 0xEC
#define CONVERT_TEMP 0x44
#define WRITE_SCRATCHPAD 0x4E
#define READ_SCRATCHPAD 0xBE
#define COPY_SCRATCHPAD 0x48
#define RECALL_EEPROM 0xB8
#define READ_POWER_SUPPLY 0xB4
static uint8_t ds18x_id [8];
int ds18x_read_serial(fdelay_device_t *dev, uint8_t *id)
{
int i, failed = 0;
if(!ow_reset(dev, 0))
return -1;
if(ow_write_byte(dev, 0, ROM_READ) < 0)
return -1;
for(i=0;i<8;i++)
{
*id = ow_read_byte(dev, 0);
failed += *id;
id++;
}
if(!failed)
return -1;
else
return 0;
}
static int ds18x_access(fdelay_device_t *dev, uint8_t *id)
{
int i;
if(!ow_reset(dev, 0))
return -1;
if(ow_write_byte(dev, 0, ROM_MATCH) < 0)
return -1;
for(i=0;i<8;i++)
if(ow_write_byte(dev, 0, id[i]) < 0)
return -1;
return 0;
}
int ds18x_read_temp(fdelay_device_t *dev, int *temp_r)
{
int i, failed = 0;
uint8_t data[9];
if(ds18x_access(dev, ds18x_id) < 0)
return -1;
if(ow_write_byte(dev, 0, READ_SCRATCHPAD) < 0)
return -1;
for(i=0;i<9;i++)
{
data[i] = ow_read_byte(dev, 0);
failed += data[i];
}
if(!failed)
return -1;
int temp = ((int)data[1] << 8) | ((int)data[0]);
if(temp & 0x1000)
temp = -0x10000 + temp;
if(ds18x_access(dev, ds18x_id) < 0)
return -1;
if(ow_write_byte(dev, 0, CONVERT_TEMP) < 0)
return -1;
if(temp_r) *temp_r = temp;
return 0;
}
int ds18x_init(fdelay_device_t *dev)
{
ow_init(dev);
if(ds18x_read_serial(dev, ds18x_id) < 0)
return -1;
dbg("Found DS18xx sensor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
ds18x_id[0], ds18x_id[1], ds18x_id[2], ds18x_id[3],
ds18x_id[4], ds18x_id[5], ds18x_id[6], ds18x_id[7]);
return ds18x_read_temp(dev, NULL);
}
This diff is collapsed.
DIRS = kernel tools
all clean:
for d in $(DIRS); do $(MAKE) -C $$d $@ || exit 1; done
*.ko
Module.symvers
modules.order
*.mod.c
.*.cmd
.tmp_versions
.*.o.d
\ No newline at end of file
LINUX ?= /lib/modules/$(shell uname -r)/build
obj-m = spec.o
obj-m += spec-wr-nic.o
obj-m += spec-fine-delay.o
spec-objs = spec-core.o loader-ll.o
all modules:
$(MAKE) -C $(LINUX) M=$(shell /bin/pwd) modules
install modules_install:
$(MAKE) -C $(LINUX) M=$(shell /bin/pwd) modules_install
clean:
rm -rf *.o *~ .*.cmd *.ko *.mod.c .tmp_versions Module.symvers \
Module.markers modules.order
This diff is collapsed.
/*
* This header differentiates between kernel-mode and user-mode compilation,
* as loader-ll.c is meant to be used in both contexts.
*/
#ifndef __iomem
#define __iomem /* nothing, for user space */
#endif
extern int loader_low_level(
int fd, /* This is ignored in kernel space */
void __iomem *bar4, /* This is ignored in user space */
const void *data,
int size8);
/* The following part implements a different access rule for user and kernel */
#ifdef __LOADER_LL_C__
#ifdef __KERNEL__
#include <asm/io.h>
//#include <linux/kernel.h> /* for printk */
static inline void lll_write(int fd, void __iomem *bar4, u32 val, int reg)
{
writel(val, bar4 + reg);
}
static inline u32 lll_read(int fd, void __iomem *bar4, int reg)
{
return readl(bar4 + reg);
}
#else /* ! __KERNEL__ */
#include <stdio.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <errno.h>
static inline void lll_write(int fd, void __iomem *bar4, uint32_t val, int reg)
{
struct rr_iocmd iocmd = {
.datasize = 4,
.address = reg | __RR_SET_BAR(4),
};
iocmd.data32 = val;
if (ioctl(fd, RR_WRITE, &iocmd) < 0) perror("ioctl");
return;
}
static inline uint32_t lll_read(int fd, void __iomem *bar4, int reg)
{
struct rr_iocmd iocmd = {
.datasize = 4,
.address = reg | __RR_SET_BAR(4),
};
if (ioctl(fd, RR_READ, &iocmd) < 0) perror("ioctl");
return iocmd.data32;
}
#define KERN_ERR /* nothing */
#define printk(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
#endif
#endif /* __LOADER_LL_C__ */
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (C) 2010-2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Released according to the GNU GPL, version 2 or any later version.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/io.h>
#include <asm/atomic.h>
#include <asm/unaligned.h>
#include "spec.h"
static int wrn_init(void)
{
}
static void wrn_exit(void)
{
}
module_init(wrn_init);
module_exit(wrn_exit);
MODULE_LICENSE("GPL");
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
PYRO - Python Remote Objects
This software is copyright (c) by Irmen de Jong (irmen@razorvine.net).
This software is released under the MIT software license.
This license, including disclaimer, is available in the 'LICENSE' file.
Please give me credit if you use this software.
The manual, including installation instructions, is in the docs/ directory.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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