Commit b7e85777 authored by Maciej Lipinski's avatar Maciej Lipinski

Adding fmc delay software files (requested by Eva to include binaries)

parent 3a6bd00b
fmc_delay @ b5c7ac0b
Subproject commit b5c7ac0bd61db02dd2c37e9c8d21752f6b761812
#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 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
/*
Register definitions for slave core: Fine Delay Main WB Slave
* File : fd_main_regs.h
* Author : auto-generated by wbgen2 from fd_main_wishbone_slave.wb
* Created : Wed Apr 11 11:05:22 2012
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE fd_main_wishbone_slave.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_FD_MAIN_WISHBONE_SLAVE_WB
#define __WBGEN2_REGDEFS_FD_MAIN_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: Reset Register */
/* definitions for field: State of the reset Line of the FMC Card in reg: Reset Register */
#define FD_RSTR_RST_FMC_MASK WBGEN2_GEN_MASK(0, 1)
#define FD_RSTR_RST_FMC_SHIFT 0
#define FD_RSTR_RST_FMC_W(value) WBGEN2_GEN_WRITE(value, 0, 1)
#define FD_RSTR_RST_FMC_R(reg) WBGEN2_GEN_READ(reg, 0, 1)
/* definitions for field: State of the reset of the Fine Delay HDL Core in reg: Reset Register */
#define FD_RSTR_RST_CORE_MASK WBGEN2_GEN_MASK(1, 1)
#define FD_RSTR_RST_CORE_SHIFT 1
#define FD_RSTR_RST_CORE_W(value) WBGEN2_GEN_WRITE(value, 1, 1)
#define FD_RSTR_RST_CORE_R(reg) WBGEN2_GEN_READ(reg, 1, 1)
/* definitions for field: Reset magic value in reg: Reset Register */
#define FD_RSTR_LOCK_MASK WBGEN2_GEN_MASK(16, 16)
#define FD_RSTR_LOCK_SHIFT 16
#define FD_RSTR_LOCK_W(value) WBGEN2_GEN_WRITE(value, 16, 16)
#define FD_RSTR_LOCK_R(reg) WBGEN2_GEN_READ(reg, 16, 16)
/* definitions for register: ID Register */
/* definitions for register: Global Control Register */
/* definitions for field: Bypass Hardware TDC/Delay Controller in reg: Global Control Register */
#define FD_GCR_BYPASS WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Enable trigger input in reg: Global Control Register */
#define FD_GCR_INPUT_EN WBGEN2_GEN_MASK(1, 1)
/* definitions for field: PLL Locked in reg: Global Control Register */
#define FD_GCR_DDR_LOCKED WBGEN2_GEN_MASK(2, 1)
/* definitions for field: Mezzanice Present in reg: Global Control Register */
#define FD_GCR_FMC_PRESENT WBGEN2_GEN_MASK(3, 1)
/* definitions for register: Timing Control Register */
/* definitions for field: DMTD Clock Status in reg: Timing Control Register */
#define FD_TCR_DMTD_STAT WBGEN2_GEN_MASK(0, 1)
/* definitions for field: WR Timing Enable in reg: Timing Control Register */
#define FD_TCR_WR_ENABLE WBGEN2_GEN_MASK(1, 1)
/* definitions for field: WR Timing Locked in reg: Timing Control Register */
#define FD_TCR_WR_LOCKED WBGEN2_GEN_MASK(2, 1)
/* definitions for field: WR Core Present in reg: Timing Control Register */
#define FD_TCR_WR_PRESENT WBGEN2_GEN_MASK(3, 1)
/* definitions for field: WR Core Time Ready in reg: Timing Control Register */
#define FD_TCR_WR_READY WBGEN2_GEN_MASK(4, 1)
/* definitions for field: WR Core Link Up in reg: Timing Control Register */
#define FD_TCR_WR_LINK WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Capture Current Time in reg: Timing Control Register */
#define FD_TCR_CAP_TIME WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Set Current Time in reg: Timing Control Register */
#define FD_TCR_SET_TIME WBGEN2_GEN_MASK(7, 1)
/* definitions for register: Time Register - TAI seconds (MSB) */
/* definitions for register: Time Register - TAI seconds (LSB) */
/* definitions for register: Time Register - sub-second 125 MHz clock cycles */
/* definitions for register: TDC Data Register */
/* definitions for register: TDC control/status reg */
/* definitions for field: Start TDC write in reg: TDC control/status reg */
#define FD_TDCSR_WRITE WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Start TDC read in reg: TDC control/status reg */
#define FD_TDCSR_READ WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Empty flag in reg: TDC control/status reg */
#define FD_TDCSR_EMPTY WBGEN2_GEN_MASK(2, 1)
/* definitions for field: Start enable in reg: TDC control/status reg */
#define FD_TDCSR_STOP_EN WBGEN2_GEN_MASK(3, 1)
/* definitions for field: Start disable in reg: TDC control/status reg */
#define FD_TDCSR_START_DIS WBGEN2_GEN_MASK(4, 1)
/* definitions for field: Stop enable in reg: TDC control/status reg */
#define FD_TDCSR_START_EN WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Stop disable in reg: TDC control/status reg */
#define FD_TDCSR_STOP_DIS WBGEN2_GEN_MASK(6, 1)
/* definitions for field: write 1: Pulse the Alutrigger line in reg: TDC control/status reg */
#define FD_TDCSR_ALUTRIG WBGEN2_GEN_MASK(7, 1)
/* definitions for register: Calibration register */
/* definitions for field: Triggers calibration pulses in reg: Calibration register */
#define FD_CALR_CAL_PULSE WBGEN2_GEN_MASK(0, 1)
/* definitions for field: PPS Calibration output enable in reg: Calibration register */
#define FD_CALR_CAL_PPS WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Triggers calibration pulses in reg: Calibration register */
#define FD_CALR_CAL_DMTD WBGEN2_GEN_MASK(2, 1)
/* definitions for field: Enable pulse generation in reg: Calibration register */
#define FD_CALR_PSEL_MASK WBGEN2_GEN_MASK(3, 4)
#define FD_CALR_PSEL_SHIFT 3
#define FD_CALR_PSEL_W(value) WBGEN2_GEN_WRITE(value, 3, 4)
#define FD_CALR_PSEL_R(reg) WBGEN2_GEN_READ(reg, 3, 4)
/* definitions for field: DMTD Feedback Channel Select in reg: Calibration register */
#define FD_CALR_DMTD_FBSEL WBGEN2_GEN_MASK(7, 1)
/* definitions for field: DMTD Tag in reg: Calibration register */
#define FD_CALR_DMTD_TAG_MASK WBGEN2_GEN_MASK(8, 23)
#define FD_CALR_DMTD_TAG_SHIFT 8
#define FD_CALR_DMTD_TAG_W(value) WBGEN2_GEN_WRITE(value, 8, 23)
#define FD_CALR_DMTD_TAG_R(reg) WBGEN2_GEN_READ(reg, 8, 23)
/* definitions for field: DMTD Tag Ready in reg: Calibration register */
#define FD_CALR_DMTD_TAG_RDY WBGEN2_GEN_MASK(31, 1)
/* definitions for register: Softpll Register */
/* definitions for field: Frequency/Phase tag in reg: Softpll Register */
#define FD_SPLLR_TAG_MASK WBGEN2_GEN_MASK(0, 20)
#define FD_SPLLR_TAG_SHIFT 0
#define FD_SPLLR_TAG_W(value) WBGEN2_GEN_WRITE(value, 0, 20)
#define FD_SPLLR_TAG_R(reg) WBGEN2_GEN_READ(reg, 0, 20)
/* definitions for field: Tag Ready in reg: Softpll Register */
#define FD_SPLLR_TAG_RDY WBGEN2_GEN_MASK(20, 1)
/* definitions for field: Freq/Phase mode select in reg: Softpll Register */
#define FD_SPLLR_MODE WBGEN2_GEN_MASK(21, 1)
/* definitions for register: Softpll DAC Register */
/* definitions for field: DAC Value in reg: Softpll DAC Register */
#define FD_SDACR_DAC_VAL_MASK WBGEN2_GEN_MASK(0, 16)
#define FD_SDACR_DAC_VAL_SHIFT 0
#define FD_SDACR_DAC_VAL_W(value) WBGEN2_GEN_WRITE(value, 0, 16)
#define FD_SDACR_DAC_VAL_R(reg) WBGEN2_GEN_READ(reg, 0, 16)
/* definitions for register: Acam to Delay line fractional part Scale Factor Register */
/* definitions for register: Acam Timestamp Merging Control Register */
/* definitions for field: Wraparound Coarse Threshold in reg: Acam Timestamp Merging Control Register */
#define FD_ATMCR_C_THR_MASK WBGEN2_GEN_MASK(0, 4)
#define FD_ATMCR_C_THR_SHIFT 0
#define FD_ATMCR_C_THR_W(value) WBGEN2_GEN_WRITE(value, 0, 4)
#define FD_ATMCR_C_THR_R(reg) WBGEN2_GEN_READ(reg, 0, 4)
/* definitions for field: Wraparound Fine Threshold in reg: Acam Timestamp Merging Control Register */
#define FD_ATMCR_F_THR_MASK WBGEN2_GEN_MASK(4, 23)
#define FD_ATMCR_F_THR_SHIFT 4
#define FD_ATMCR_F_THR_W(value) WBGEN2_GEN_WRITE(value, 4, 23)
#define FD_ATMCR_F_THR_R(reg) WBGEN2_GEN_READ(reg, 4, 23)
/* definitions for register: Acam Start Offset Register */
/* definitions for field: Start Offset in reg: Acam Start Offset Register */
#define FD_ASOR_OFFSET_MASK WBGEN2_GEN_MASK(0, 23)
#define FD_ASOR_OFFSET_SHIFT 0
#define FD_ASOR_OFFSET_W(value) WBGEN2_GEN_WRITE(value, 0, 23)
#define FD_ASOR_OFFSET_R(reg) WBGEN2_GEN_READ(reg, 0, 23)
/* definitions for register: Raw Input Events Counter Register */
/* definitions for register: Tagged Input Events Counter Register */
/* definitions for register: Input Event Processing Delay Register */
/* definitions for field: Reset stats in reg: Input Event Processing Delay Register */
#define FD_IEPD_RST_STAT WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Processing delay in reg: Input Event Processing Delay Register */
#define FD_IEPD_PDELAY_MASK WBGEN2_GEN_MASK(1, 8)
#define FD_IEPD_PDELAY_SHIFT 1
#define FD_IEPD_PDELAY_W(value) WBGEN2_GEN_WRITE(value, 1, 8)
#define FD_IEPD_PDELAY_R(reg) WBGEN2_GEN_READ(reg, 1, 8)
/* definitions for register: SPI Control Register */
/* definitions for field: Data in reg: SPI Control Register */
#define FD_SCR_DATA_MASK WBGEN2_GEN_MASK(0, 24)
#define FD_SCR_DATA_SHIFT 0
#define FD_SCR_DATA_W(value) WBGEN2_GEN_WRITE(value, 0, 24)
#define FD_SCR_DATA_R(reg) WBGEN2_GEN_READ(reg, 0, 24)
/* definitions for field: Select DAC in reg: SPI Control Register */
#define FD_SCR_SEL_DAC WBGEN2_GEN_MASK(24, 1)
/* definitions for field: Select PLL in reg: SPI Control Register */
#define FD_SCR_SEL_PLL WBGEN2_GEN_MASK(25, 1)
/* definitions for field: Select GPIO in reg: SPI Control Register */
#define FD_SCR_SEL_GPIO WBGEN2_GEN_MASK(26, 1)
/* definitions for field: Ready flag in reg: SPI Control Register */
#define FD_SCR_READY WBGEN2_GEN_MASK(27, 1)
/* definitions for field: Clock Polarity in reg: SPI Control Register */
#define FD_SCR_CPOL WBGEN2_GEN_MASK(28, 1)
/* definitions for field: Transfer Start in reg: SPI Control Register */
#define FD_SCR_START WBGEN2_GEN_MASK(29, 1)
/* definitions for register: Reference Clock Rate Register */
/* definitions for register: Timestamp Buffer Control Register */
/* definitions for field: Channel Mask in reg: Timestamp Buffer Control Register */
#define FD_TSBCR_CHAN_MASK_MASK WBGEN2_GEN_MASK(0, 5)
#define FD_TSBCR_CHAN_MASK_SHIFT 0
#define FD_TSBCR_CHAN_MASK_W(value) WBGEN2_GEN_WRITE(value, 0, 5)
#define FD_TSBCR_CHAN_MASK_R(reg) WBGEN2_GEN_READ(reg, 0, 5)
/* definitions for field: Buffer enable in reg: Timestamp Buffer Control Register */
#define FD_TSBCR_ENABLE WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Buffer purge in reg: Timestamp Buffer Control Register */
#define FD_TSBCR_PURGE WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Reset TS Sequence Numbers in reg: Timestamp Buffer Control Register */
#define FD_TSBCR_RST_SEQ WBGEN2_GEN_MASK(7, 1)
/* definitions for field: Buffer full in reg: Timestamp Buffer Control Register */
#define FD_TSBCR_FULL WBGEN2_GEN_MASK(8, 1)
/* definitions for field: Buffer empty in reg: Timestamp Buffer Control Register */
#define FD_TSBCR_EMPTY WBGEN2_GEN_MASK(9, 1)
/* definitions for field: Buffer entries count in reg: Timestamp Buffer Control Register */
#define FD_TSBCR_COUNT_MASK WBGEN2_GEN_MASK(10, 12)
#define FD_TSBCR_COUNT_SHIFT 10
#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 register: Timestamp Buffer Interrupt Register */
/* definitions for field: IRQ timeout [milliseconds] in reg: Timestamp Buffer Interrupt Register */
#define FD_TSBIR_TIMEOUT_MASK WBGEN2_GEN_MASK(0, 10)
#define FD_TSBIR_TIMEOUT_SHIFT 0
#define FD_TSBIR_TIMEOUT_W(value) WBGEN2_GEN_WRITE(value, 0, 10)
#define FD_TSBIR_TIMEOUT_R(reg) WBGEN2_GEN_READ(reg, 0, 10)
/* definitions for field: Interrupt threshold in reg: Timestamp Buffer Interrupt Register */
#define FD_TSBIR_THRESHOLD_MASK WBGEN2_GEN_MASK(10, 12)
#define FD_TSBIR_THRESHOLD_SHIFT 10
#define FD_TSBIR_THRESHOLD_W(value) WBGEN2_GEN_WRITE(value, 10, 12)
#define FD_TSBIR_THRESHOLD_R(reg) WBGEN2_GEN_READ(reg, 10, 12)
/* definitions for register: Timestamp Buffer Readout Seconds Register (MSB) */
/* definitions for register: Timestamp Buffer Readout Seconds Register (LSB) */
/* definitions for register: Timestamp Buffer Readout Cycles Register */
/* definitions for register: Timestamp Buffer Readout Fine / Channel / Seq ID Register */
/* definitions for field: Channel ID in reg: Timestamp Buffer Readout Fine / Channel / Seq ID Register */
#define FD_TSBR_FID_CHANNEL_MASK WBGEN2_GEN_MASK(0, 4)
#define FD_TSBR_FID_CHANNEL_SHIFT 0
#define FD_TSBR_FID_CHANNEL_W(value) WBGEN2_GEN_WRITE(value, 0, 4)
#define FD_TSBR_FID_CHANNEL_R(reg) WBGEN2_GEN_READ(reg, 0, 4)
/* definitions for field: Fine Value [in phase units] in reg: Timestamp Buffer Readout Fine / Channel / Seq ID Register */
#define FD_TSBR_FID_FINE_MASK WBGEN2_GEN_MASK(4, 12)
#define FD_TSBR_FID_FINE_SHIFT 4
#define FD_TSBR_FID_FINE_W(value) WBGEN2_GEN_WRITE(value, 4, 12)
#define FD_TSBR_FID_FINE_R(reg) WBGEN2_GEN_READ(reg, 4, 12)
/* definitions for field: Timestamp Sequence ID in reg: Timestamp Buffer Readout Fine / Channel / Seq ID Register */
#define FD_TSBR_FID_SEQID_MASK WBGEN2_GEN_MASK(16, 16)
#define FD_TSBR_FID_SEQID_SHIFT 16
#define FD_TSBR_FID_SEQID_W(value) WBGEN2_GEN_WRITE(value, 16, 16)
#define FD_TSBR_FID_SEQID_R(reg) WBGEN2_GEN_READ(reg, 16, 16)
/* definitions for register: I2C bitbanged IO register */
/* definitions for field: SCL Line out in reg: I2C bitbanged IO register */
#define FD_I2CR_SCL_OUT WBGEN2_GEN_MASK(0, 1)
/* definitions for field: SDA Line out in reg: I2C bitbanged IO register */
#define FD_I2CR_SDA_OUT WBGEN2_GEN_MASK(1, 1)
/* definitions for field: SCL Line in in reg: I2C bitbanged IO register */
#define FD_I2CR_SCL_IN WBGEN2_GEN_MASK(2, 1)
/* definitions for field: SDA Line in in reg: I2C bitbanged IO register */
#define FD_I2CR_SDA_IN WBGEN2_GEN_MASK(3, 1)
/* definitions for register: Test/Debug register 1 */
/* definitions for field: VCXO Frequency in reg: Test/Debug register 1 */
#define FD_TDER1_VCXO_FREQ_MASK WBGEN2_GEN_MASK(0, 32)
#define FD_TDER1_VCXO_FREQ_SHIFT 0
#define FD_TDER1_VCXO_FREQ_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define FD_TDER1_VCXO_FREQ_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: Test/Debug register 1 */
/* definitions for field: Peltier PWM drive in reg: Test/Debug register 1 */
#define FD_TDER2_PELT_DRIVE_MASK WBGEN2_GEN_MASK(0, 32)
#define FD_TDER2_PELT_DRIVE_SHIFT 0
#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: Interrupt disable register */
/* definitions for field: TS Buffer not empty. in reg: Interrupt disable register */
#define FD_EIC_IDR_TS_BUF_NOTEMPTY WBGEN2_GEN_MASK(0, 1)
/* definitions for field: DMTD Softpll interrupt in reg: Interrupt disable register */
#define FD_EIC_IDR_DMTD_SPLL WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Sync Status Changed in reg: Interrupt disable register */
#define FD_EIC_IDR_SYNC_STATUS WBGEN2_GEN_MASK(2, 1)
/* definitions for register: Interrupt enable register */
/* definitions for field: TS Buffer not empty. in reg: Interrupt enable register */
#define FD_EIC_IER_TS_BUF_NOTEMPTY WBGEN2_GEN_MASK(0, 1)
/* definitions for field: DMTD Softpll interrupt in reg: Interrupt enable register */
#define FD_EIC_IER_DMTD_SPLL WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Sync Status Changed in reg: Interrupt enable register */
#define FD_EIC_IER_SYNC_STATUS WBGEN2_GEN_MASK(2, 1)
/* definitions for register: Interrupt mask register */
/* definitions for field: TS Buffer not empty. in reg: Interrupt mask register */
#define FD_EIC_IMR_TS_BUF_NOTEMPTY WBGEN2_GEN_MASK(0, 1)
/* definitions for field: DMTD Softpll interrupt in reg: Interrupt mask register */
#define FD_EIC_IMR_DMTD_SPLL WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Sync Status Changed in reg: Interrupt mask register */
#define FD_EIC_IMR_SYNC_STATUS WBGEN2_GEN_MASK(2, 1)
/* definitions for register: Interrupt status register */
/* definitions for field: TS Buffer not empty. in reg: Interrupt status register */
#define FD_EIC_ISR_TS_BUF_NOTEMPTY WBGEN2_GEN_MASK(0, 1)
/* definitions for field: DMTD Softpll interrupt in reg: Interrupt status register */
#define FD_EIC_ISR_DMTD_SPLL WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Sync Status Changed in reg: Interrupt status register */
#define FD_EIC_ISR_SYNC_STATUS WBGEN2_GEN_MASK(2, 1)
/* [0x0]: REG Reset Register */
#define FD_REG_RSTR 0x00000000
/* [0x4]: REG ID Register */
#define FD_REG_IDR 0x00000004
/* [0x8]: REG Global Control Register */
#define FD_REG_GCR 0x00000008
/* [0xc]: REG Timing Control Register */
#define FD_REG_TCR 0x0000000c
/* [0x10]: REG Time Register - TAI seconds (MSB) */
#define FD_REG_TM_SECH 0x00000010
/* [0x14]: REG Time Register - TAI seconds (LSB) */
#define FD_REG_TM_SECL 0x00000014
/* [0x18]: REG Time Register - sub-second 125 MHz clock cycles */
#define FD_REG_TM_CYCLES 0x00000018
/* [0x1c]: REG TDC Data Register */
#define FD_REG_TDR 0x0000001c
/* [0x20]: REG TDC control/status reg */
#define FD_REG_TDCSR 0x00000020
/* [0x24]: REG Calibration register */
#define FD_REG_CALR 0x00000024
/* [0x28]: REG Softpll Register */
#define FD_REG_SPLLR 0x00000028
/* [0x2c]: REG Softpll DAC Register */
#define FD_REG_SDACR 0x0000002c
/* [0x30]: REG Acam to Delay line fractional part Scale Factor Register */
#define FD_REG_ADSFR 0x00000030
/* [0x34]: REG Acam Timestamp Merging Control Register */
#define FD_REG_ATMCR 0x00000034
/* [0x38]: REG Acam Start Offset Register */
#define FD_REG_ASOR 0x00000038
/* [0x3c]: REG Raw Input Events Counter Register */
#define FD_REG_IECRAW 0x0000003c
/* [0x40]: REG Tagged Input Events Counter Register */
#define FD_REG_IECTAG 0x00000040
/* [0x44]: REG Input Event Processing Delay Register */
#define FD_REG_IEPD 0x00000044
/* [0x48]: REG SPI Control Register */
#define FD_REG_SCR 0x00000048
/* [0x4c]: REG Reference Clock Rate Register */
#define FD_REG_RCRR 0x0000004c
/* [0x50]: REG Timestamp Buffer Control Register */
#define FD_REG_TSBCR 0x00000050
/* [0x54]: REG Timestamp Buffer Interrupt Register */
#define FD_REG_TSBIR 0x00000054
/* [0x58]: REG Timestamp Buffer Readout Seconds Register (MSB) */
#define FD_REG_TSBR_SECH 0x00000058
/* [0x5c]: REG Timestamp Buffer Readout Seconds Register (LSB) */
#define FD_REG_TSBR_SECL 0x0000005c
/* [0x60]: REG Timestamp Buffer Readout Cycles Register */
#define FD_REG_TSBR_CYCLES 0x00000060
/* [0x64]: REG Timestamp Buffer Readout Fine / Channel / Seq ID Register */
#define FD_REG_TSBR_FID 0x00000064
/* [0x68]: REG I2C bitbanged IO register */
#define FD_REG_I2CR 0x00000068
/* [0x6c]: REG Test/Debug register 1 */
#define FD_REG_TDER1 0x0000006c
/* [0x70]: REG Test/Debug register 1 */
#define FD_REG_TDER2 0x00000070
/* [0x80]: REG Interrupt disable register */
#define FD_REG_EIC_IDR 0x00000080
/* [0x84]: REG Interrupt enable register */
#define FD_REG_EIC_IER 0x00000084
/* [0x88]: REG Interrupt mask register */
#define FD_REG_EIC_IMR 0x00000088
/* [0x8c]: REG Interrupt status register */
#define FD_REG_EIC_ISR 0x0000008c
#endif
#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 /* attached WR core is offline */
#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. */
/* fdelay_configure_sync() flags */
#define FDELAY_SYNC_LOCAL 0x1 /* use local oscillator */
#define FDELAY_SYNC_WR 0x2 /* use White Rabbit */
/* Hardware "handle" structure */
typedef struct fdelay_device
{
/* Base address of the FD core */
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;
int32_t coarse;
int32_t frac;
uint16_t seq_id;
int channel;
} fdelay_time_t;
/*
--------------------
PUBLIC API
--------------------
*/
fdelay_device_t *fdelay_create_rawrabbit(int fd, uint32_t base_addr);
fdelay_device_t *fdelay_create_minibone(char *iface, char *mac_addr, uint32_t base_addr);
fdelay_time_t fdelay_from_picos(const uint64_t ps);
int64_t fdelay_to_picos(const fdelay_time_t t);
int fdelay_init(fdelay_device_t *dev);
int fdelay_release(fdelay_device_t *dev);
int fdelay_read(fdelay_device_t *dev, fdelay_time_t *timestamps, int how_many);
int fdelay_configure_trigger(fdelay_device_t *dev, int enable, int termination);
int fdelay_configure_output(fdelay_device_t *dev, int channel, int enable, int64_t delay_ps, int64_t width_ps, int64_t delta_ps, int rep_count);
int fdelay_configure_sync(fdelay_device_t *dev, int mode);
int fdelay_update_sync_status(fdelay_device_t *dev);
int fdelay_set_time(fdelay_device_t *dev, const fdelay_time_t t);
int fdelay_configure_pulse_gen(fdelay_device_t *dev, int channel, int enable, fdelay_time_t t_start, int64_t width_ps, int64_t delta_ps, int rep_count);
int fdelay_channel_triggered(fdelay_device_t *dev, int channel);
int fdelay_get_time(fdelay_device_t *dev, fdelay_time_t *t);
#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 */
/* 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
/* ACAM Calibration parameters */
struct fine_delay_calibration {
uint32_t magic; /* magic ID: 0xf19ede1a */
uint32_t zero_offset[4]; /* Output zero offset, in nsec << FDELAY_FRAC_BITS */
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 picoseconds */
int64_t frr_poly[3]; /* SY89295 delay/temperature polynomial coefficients */
} __attribute__((packed));
/* 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;
struct fine_delay_calibration calib;
};
/* 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 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
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
all: testprog lib testprog2 testprog3 testprog4
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
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
clean:
rm -f libfinedelay.so $(OBJS_LIB)
\ No newline at end of file
/*
FmcDelay1ns4Cha (a.k.a. The Fine Delay Card)
User-space driver/library - bus API creation functions
Tomasz Włostowski/BE-CO-HT, 2011
(c) Copyright CERN 2011
Licensed under LGPL 2.1
*/
#include <stdio.h>
#include <stdlib.h>
#include "rr_io.h"
#include "minibone_lib.h"
#include "fdelay_lib.h"
static void my_rr_writel(void *priv, uint32_t data, uint32_t addr)
{
rr_writel(data, addr);
}
static uint32_t my_rr_readl(void *priv, uint32_t addr)
{
uint32_t d = rr_readl(addr);
return d;
}
static void my_mb_writel(void *priv, uint32_t data, uint32_t addr)
{
mbn_writel(priv, data, addr >> 2);
}
static uint32_t my_mb_readl(void *priv, uint32_t addr)
{
uint32_t d = mbn_readl(priv, addr >> 2);
return d;
}
fdelay_device_t *fdelay_create_rawrabbit(int fd, uint32_t base_addr)
{
fdelay_device_t *dev = malloc(sizeof(fdelay_device_t));
rr_bind(fd);
dev->writel = my_rr_writel;
dev->readl = my_rr_readl;
dev->base_addr = base_addr;
return dev;
}
fdelay_device_t *fdelay_create_minibone(char *iface, char *mac_addr, uint32_t base_addr)
{
void *handle;
uint8_t target_mac[6];
fdelay_device_t *dev = malloc(sizeof(fdelay_device_t));
sscanf(mac_addr, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &target_mac[0], &target_mac[1], &target_mac[2], &target_mac[3], &target_mac[4], &target_mac[5]);
handle = mbn_open(iface, target_mac);
if(handle == NULL)
return NULL;
// dbg("%s: remote @ %s [%02x:%02x:%02x:%02x:%02x:%02x], base 0x%08x\n",__FUNCTION__, iface,
// target_mac[0], target_mac[1], target_mac[2], target_mac[3], target_mac[4], target_mac[5], base_addr);
dev->writel = my_mb_writel;
dev->readl = my_mb_readl;
dev->base_addr = base_addr;
dev->priv_io = handle;
return dev;
}
#include <stdio.h>
#include <stdint.h>
#include "fdelay_lib.h"
#include "fdelay_private.h"
#include "fd_main_regs.h"
#include "onewire.h"
#include "rr_io.h"
typedef struct {
float kp, ki, err, pwm, setpoint, i, bias;
} pi_t;
pi_t pi_state = {15.0, 5.0, 0, 0, 20, 0, 2048};
void pi_update(fdelay_device_t *dev, float temp)
{
fd_decl_private(dev);
pi_state.err = temp - pi_state.setpoint;
pi_state.i += pi_state.err;
pi_state.pwm = pi_state.bias + pi_state.kp * pi_state.err + pi_state.ki * pi_state.i;
dbg("t %.1f err:%.1f DRIVE: %d\n", temp, pi_state.err, (int)pi_state.pwm);
fd_writel(FD_I2CR_DBGOUT_W((int)pi_state.pwm), FD_REG_I2CR);
}
extern int64_t get_tics();
static int64_t last_tics = 0;
#define TEMP_REG_PERIOD 1000000LL
int pi_set_temp(fdelay_device_t *dev, float new_temp)
{
int temp;
float temp_f;
if(get_tics() - last_tics < TEMP_REG_PERIOD)
return 0;
last_tics = get_tics();
if(ds18x_read_temp(dev, &temp) < 0)
return 0;
temp_f = (float)temp / 16.0;
pi_state.setpoint = new_temp;
pi_update(dev, temp_f);
dbg("Temperature: %.1f degC err %.1f\n", temp_f, pi_state.err);
return fabs(pi_state.err) < 0.1 ? 1: 0;
}
void my_writel(void *priv, uint32_t data, uint32_t addr)
{
rr_writel(data, addr);
}
uint32_t my_readl(void *priv, uint32_t addr)
{
uint32_t d = rr_readl(addr);
return d;
}
main()
{
fdelay_device_t *dev = malloc(sizeof(fdelay_device_t));
rr_init(RR_DEVSEL_UNUSED, RR_DEVSEL_UNUSED);
dev->writel = my_writel;
dev->readl = my_readl;
dev->base_addr = 0x80000;
if(fdelay_init(dev) < 0)
return -1;
float t_min = 40.0, t_max = 80.0, t_cur;
t_cur = t_min;
for(;;)
{
if(pi_set_temp(dev, t_cur))
{
fd_decl_private(dev);
calibrate_outputs(dev);
fprintf(stderr, "> %.1f %d %d %d %d\n", t_cur, hw->frr_cur[0],
hw->frr_cur[1], hw->frr_cur[2], hw->frr_cur[3]);
t_cur += 1.0;
if(t_cur > t_max)
break;
}
usleep(10000);
}
}
#include <stdio.h>
#include "fdelay_lib.h"
#include "fdelay_private.h"
#include "rr_io.h"
#include "i2c_master.h"
void my_writel(void *priv, uint32_t data, uint32_t addr)
{
rr_writel(data, addr);
}
uint32_t my_readl(void *priv, uint32_t addr)
{
uint32_t d = rr_readl(addr);
return d;
}
main()
{
fdelay_device_t dev;
struct fine_delay_calibration cal;
rr_init(RR_DEVSEL_UNUSED, RR_DEVSEL_UNUSED);
dev.writel = my_writel;
dev.readl = my_readl;
dev.base_addr = 0x84000;
if(fdelay_init(&dev) < 0)
return -1;
cal.magic = 0xf19ede1a;
cal.zero_offset[0] = 63000;
cal.zero_offset[1] = 63000;
cal.zero_offset[2] = 63000;
cal.zero_offset[3] = 63000;
cal.tdc_zero_offset = 35600;
cal.frr_poly[0] = -165202LL;
cal.frr_poly[1] = -29825595LL;
cal.frr_poly[2] = 3801939743082LL;
cal.tdc_zero_offset = 35600;
cal.atmcr_val = 2 | (1000 << 4);
cal.adsfr_val = 56648;
cal.acam_start_offset = 10000;
printf("Writing EEPROM...");
eeprom_write(&dev, EEPROM_ADDR, 0, &cal, sizeof(struct fine_delay_calibration));
printf(" done.\n");
}
/*
FmcDelay1ns4Cha (a.k.a. The Fine Delay Card)
User-space driver/library
Tomasz Włostowski/BE-CO-HT, 2011
(c) Copyright CERN 2011
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 "pll_config.h"
#include "acam_gpx.h"
#include "fdelay_lib.h"
#include "fdelay_private.h"
#include "spll_defs.h"
#include "spll_common.h"
#include "spll_helper.h"
#include "onewire.h"
static int acam_test_bus(fdelay_device_t *dev);
#define TEST_PRESENCE 0
#define TEST_FIRMWARE 1
#define TEST_DELAY_LINE 2
#define TEST_SPI 3
#define TEST_SENSORS 4
#define TEST_ACAM_IF 5
/*
----------------------
Some utility functions
----------------------
*/
char fail_test_msg[1024];
int fail_test_id = -1;
static void fail(int test_id, const char *fmt, ...)
{
va_list ap;
fail_test_id = test_id;
va_start(ap, fmt);
vsprintf(fail_test_msg,fmt,ap);
va_end(ap);
}
static int extra_debug = 1;
void fdelay_show_test_results()
{
if(fail_test_id >= 0)
{
fprintf(stderr,"\n\n\n ***** FAILED TEST: %d (%s) ****** \n", fail_test_id, fail_test_msg);
}
}
void dbg(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if(extra_debug)
vfprintf(stderr,fmt,ap);
va_end(ap);
}
/* Returns the numer of microsecond timer ticks */
int64_t get_tics()
{
struct timezone tz= {0,0};
struct timeval tv;
gettimeofday(&tv, &tz);
return (int64_t)tv.tv_sec * 1000000LL + (int64_t) tv.tv_usec;
}
/* Microsecond-accurate delay */
void udelay(uint32_t usecs)
{
int64_t ts = get_tics();
while(get_tics() - ts < (int64_t)usecs);
}
/* Card reset. When mode == RESET_HW, resets the FMC hardware by asserting the reset line in the FMC
connector, if mode == RESET_CORE, the FPGA Fine Delay core is reset. Since HW reset operation also
reinitializes the PLL, the HW reset must be followed by a reinitialization of the FD Core. */
#define FD_RESET_HW 1
#define FD_RESET_CORE 0
static void fd_do_reset(fdelay_device_t *dev, int mode)
{
fd_decl_private(dev) ;
if(mode == FD_RESET_HW) {
fd_writel(FD_RSTR_LOCK_W(0xdead) | FD_RSTR_RST_CORE_MASK, FD_REG_RSTR);
udelay(10000);
fd_writel(FD_RSTR_LOCK_W(0xdead) | FD_RSTR_RST_CORE_MASK | FD_RSTR_RST_FMC_MASK, FD_REG_RSTR);
udelay(600000); /* Leave the TPS3307 supervisor some time to de-assert the master reset line */
} else if (mode == FD_RESET_CORE)
{
fd_writel(FD_RSTR_LOCK_W(0xdead) | FD_RSTR_RST_FMC_MASK, FD_REG_RSTR);
udelay(1000);
fd_writel(FD_RSTR_LOCK_W(0xdead) | FD_RSTR_RST_FMC_MASK | FD_RSTR_RST_CORE_MASK, FD_REG_RSTR);
udelay(1000);
}
}
/*
----------------------------------
Simple SPI Master driver
----------------------------------
*/
/* Initializes the SPI Controller */
static void oc_spi_init(fdelay_device_t *dev)
{
fd_decl_private(dev)
}
/* Sends (num_bits) from (in) to slave at CS line (ss), storint the readback data in (*out) */
static void oc_spi_txrx(fdelay_device_t *dev, int ss, int num_bits, uint32_t in, uint32_t *out)
{
fd_decl_private(dev);
uint32_t scr = 0, r;
scr = FD_SCR_DATA_W(in)| FD_SCR_CPOL;
if(ss == CS_PLL)
scr |= FD_SCR_SEL_PLL;
else if(ss == CS_GPIO)
scr |= FD_SCR_SEL_GPIO;
else if(ss == CS_DAC)
scr |= FD_SCR_SEL_DAC;
fd_writel(scr, FD_REG_SCR);
fd_writel(scr | FD_SCR_START, FD_REG_SCR);
while(! (fd_readl(FD_REG_SCR) & FD_SCR_READY));
scr = fd_readl(FD_REG_SCR);
r = FD_SCR_DATA_R(scr);
if(out) *out=r;
udelay(100);
}
/*
-----------------
AD9516 PLL Driver
-----------------
*/
/* Writes an AD9516 register */
static inline void ad9516_write_reg(fdelay_device_t *dev, uint16_t reg, uint8_t val)
{
oc_spi_txrx(dev, CS_PLL, 24, ((uint32_t)(reg & 0xfff) << 8) | val, NULL);
}
/* Reads a register from AD9516 */
static inline uint8_t ad9516_read_reg(fdelay_device_t *dev, uint16_t reg)
{
uint32_t rval;
oc_spi_txrx(dev, CS_PLL, 24, ((uint32_t)(reg & 0xfff) << 8) | (1<<23), &rval);
return rval & 0xff;
}
/* Initializes the AD9516 PLL by loading a pre-defined register set and waiting until the PLL has locked */
static int ad9516_init(fdelay_device_t *dev)
{
fd_decl_private(dev)
int i;
const int64_t lock_timeout = 10000000LL;
int64_t start_tics;
dbg("%s: Initializing AD9516 PLL...\n", __FUNCTION__);
ad9516_write_reg(dev, 0, 0x99);
ad9516_write_reg(dev, 0x232, 1);
/* Check if the chip is present by reading its ID register */
if(ad9516_read_reg(dev, 0x3) != 0xc3)
{
dbg("%s: AD9516 PLL not responding.\n", __FUNCTION__);
fail(TEST_SPI, "Broken SPI connection to AD9516 PLL");
return -1;
}
/* Load the regs */
for(i=0;ad9516_regs[i].reg >=0 ;i++)
ad9516_write_reg (dev, ad9516_regs[i].reg, ad9516_regs[i].val);
ad9516_write_reg(dev, 0x232, 1);
/* Wait until the PLL has locked */
start_tics = get_tics();
for(;;)
{
if(ad9516_read_reg(dev, 0x1f) & 1)
break;
if(get_tics() - start_tics > lock_timeout)
{
dbg("%s: AD9516 PLL does not lock.\n", __FUNCTION__);
return -1;
}
udelay(100);
}
/* Synchronize the phase of all clock outputs (this is critical for the accuracy!) */
ad9516_write_reg(dev, 0x230, 1);
ad9516_write_reg(dev, 0x232, 1);
ad9516_write_reg(dev, 0x230, 0);
ad9516_write_reg(dev, 0x232, 1);
dbg("%s: AD9516 locked.\n", __FUNCTION__);
return 0;
}
static int test_pll_dac(fdelay_device_t *dev)
{
fd_decl_private(dev);
int f_hi, f_lo;
double range;
int i=0;
dbg("Testing DAC/VCXO... ");
oc_spi_txrx(dev, CS_DAC, 24, 0, NULL); /* Drive the DAC to 0 */
udelay(1000000);
f_lo = fd_readl(FD_REG_TDER1) & 0x7fffffff;
oc_spi_txrx(dev, CS_DAC, 24, 0xffff, NULL); /* Drive the DAC to +Vref */
udelay(1000000);
f_hi = fd_readl(FD_REG_TDER1) & 0x7fffffff;
range = (double)abs(f_hi - f_lo) / (double)f_lo * 1e6;
dbg("tuning range: %.1f ppm.\n", range);
if(range < 10.1)
{
fail(TEST_SPI, "Too little VCXO tuning range. Either a broken VCXO or (more likely) broken SPI connection to the DAC.");
return -1;
}
return 0;
}
/*
----------------------------
MCP23S17 SPI I/O Port Driver
----------------------------
*/
/* Writes MCP23S17 register */
static inline void mcp_write(fdelay_device_t *dev, uint8_t reg, uint8_t val)
{
oc_spi_txrx(dev, CS_GPIO, 24, 0x4e0000 | (((uint32_t)reg)<<8) | (uint32_t)val, NULL);
}
/* Reads MCP23S17 register */
static uint8_t mcp_read(fdelay_device_t *dev, uint8_t reg)
{
uint32_t rval;
oc_spi_txrx(dev, CS_GPIO, 24, 0x4f0000 | (((uint32_t)reg)<<8), &rval);
return rval & 0xff;
}
static int sgpio_init(fdelay_device_t *dev)
{
int failed = 0;
mcp_write(dev, MCP_IOCON, 0);
/* try to read and write a register to test the SPI connection */
mcp_write(dev, MCP_IPOL, 0xaa);
if(mcp_read(dev, MCP_IPOL) != 0xaa)
failed = 1;
mcp_write(dev, MCP_IPOL, 0);
if(mcp_read(dev, MCP_IPOL) != 0)
failed = 1;
fail(TEST_SPI, "Failed to access MCP23S17. Broken SPI connection?");
return failed ? - 1: 0;
}
/* Sets the direction (0 = input, non-zero = output) of a particular MCP23S17 GPIO pin */
static void sgpio_set_dir(fdelay_device_t *dev, int pin, int dir)
{
uint8_t iodir = (MCP_IODIR) + (pin & 0x100 ? 1 : 0);
uint8_t x;
x = mcp_read(dev, iodir);
if(dir) x &= ~(pin); else x |= (pin);
mcp_write(dev, iodir, x);
}
/* Sets the value on a given MCP23S17 GPIO pin */
static void sgpio_set_pin(fdelay_device_t *dev, int pin, int val)
{
uint8_t gpio = (MCP_OLAT) + (pin & 0x100 ? 1 : 0);
uint8_t x;
x = mcp_read(dev, gpio);
if(!val) x &= ~(pin); else x |= (pin);
mcp_write(dev, gpio, x);
}
/*
----------------------------------------
ACAM Time To Digital Converter functions
----------------------------------------
*/
/* Sets the address on ACAM's address bus to addr using the SPI GPIO expander */
static inline void acam_set_address(fdelay_device_t *dev, uint8_t addr)
{
fd_decl_private(dev);
/* A hack to speed up calibration - avoid setting the same address several times */
if(addr != hw->acam_addr)
{
mcp_write(dev, MCP_IODIR + 1, 0);
mcp_write(dev, MCP_OLAT + 1, addr & 0xf);
hw->acam_addr = addr;
}
}
/* Reads a register from the ACAM TDC. As for the function above, GCR.BYPASS must be enabled */
static uint32_t acam_read_reg(fdelay_device_t *dev, uint8_t reg)
{
fd_decl_private(dev)
acam_set_address(dev, reg);
fd_writel(FD_TDCSR_READ, FD_REG_TDCSR);
return fd_readl(FD_REG_TDR) & 0xfffffff;
}
/* Writes a particular ACAM register. Works only if (GCR.BYPASS == 1) - i.e. when
the ACAM is controlled from the host instead of the delay core. */
static void acam_write_reg(fdelay_device_t *dev, uint8_t reg, uint32_t data)
{
fd_decl_private(dev)
acam_set_address(dev, reg);
fd_writel(data & 0xfffffff, FD_REG_TDR);
fd_writel(FD_TDCSR_WRITE, FD_REG_TDCSR);
}
/* Calculates the parameters of the ACAM PLL (hsdiv and refdiv)
for a given bin size and reference clock frequency. Returns the closest
achievable bin size. */
static double acam_calc_pll(int *hsdiv, int *refdiv, double bin, double clock_freq)
{
int h;
int r;
double best_err = 100000;
double best_bin;
/* Try all possible divider settings */
for(h=1;h<=255;h++)
for(r=0;r<=7;r++)
{
double b = ((1.0/clock_freq) * 1e12) * pow(2.0, (double) r) / (216.0 * (double)h);
if(fabs(bin - b) < best_err)
{
best_err=fabs(bin-b);
best_bin = b;
*hsdiv= h;
*refdiv = r;
}
}
dbg("%s: requested bin=%.02fps best=%.02fps error=%.02f%%\n", __FUNCTION__, bin, best_bin, (best_err/bin) * 100.0);
dbg("%s: hsdiv=%d refdiv=%d\n", __FUNCTION__, *hsdiv, *refdiv);
return best_bin;
}
/* Returns non-zero if the ACAM's internal PLL is locked */
static inline int acam_pll_locked(fdelay_device_t *dev)
{
uint32_t r12 = acam_read_reg(dev, 12);
return !(r12 & AR12_NotLocked);
}
static int test_addr_bit(fdelay_device_t *dev, int addr1, int addr2, int addr_bit, int data_bit)
{
int failed = 0;
acam_write_reg(dev, addr1, acam_read_reg(dev, addr1) & ~(1<<data_bit)); // set the data bit to 0
acam_write_reg(dev, addr2, acam_read_reg(dev, addr2) | (1<<data_bit)); // set the data bit to 1
if(acam_read_reg(dev, addr1) & (1<<data_bit) || !(acam_read_reg(dev, addr2) & (1<<data_bit)))
failed= 1;
/* the other way around */
acam_write_reg(dev, addr1, acam_read_reg(dev, addr1) | (1<<data_bit));
acam_write_reg(dev, addr2, acam_read_reg(dev, addr2) & ~(1<<data_bit));
if(!(acam_read_reg(dev, addr1) & (1<<data_bit)) || acam_read_reg(dev, addr2) & (1<<data_bit))
failed= 1;
if(failed)
{
dbg("Bit failure on ACAM_A[%d]\n",addr_bit);
fail(TEST_ACAM_IF, "Bit failure on ACAM_A[%d]", addr_bit);
return -1;
}
return 0;
}
static int acam_test_bus(fdelay_device_t *dev)
{
int i, failed = 0;
dbg("Testing ACAM Bus...\n");
for(i=0;i<28;i++)
{
acam_write_reg(dev, 5, (1<<i));
acam_read_reg(dev, 0);
uint32_t rb = acam_read_reg(dev, 5);
acam_write_reg(dev, 5, ~(1<<i));
acam_read_reg(dev, 0);
uint32_t rb2 = acam_read_reg(dev, 5);
if(rb != (1<<i) || rb2 != (~(1<<i) & 0xfffffff))
{
dbg("Bit failure on ACAM_D[%d]: %x shouldbe %x \n", i, rb, (1<<i));
fail(TEST_ACAM_IF, "Bit failure on ACAM_D[%d]: %x shouldbe %x ", i, rb, (1<<i));
return -1;
}
}
failed |= test_addr_bit(dev, 0, 1, 0, 1);
failed |= test_addr_bit(dev, 1, 3, 1, 3);
failed |= test_addr_bit(dev, 0, 4, 2, 1);
failed |= test_addr_bit(dev, 3, 11, 3, 16);
return failed;
}
/* Configures the ACAM TDC to work in a particular mode. Currently there are two modes
supported: R-Mode for the normal operation (delay/timestamper) and I-Mode for the purpose
of calibrating the fine delay lines. */
static int acam_configure(fdelay_device_t *dev, int mode)
{
fd_decl_private(dev)
int hsdiv, refdiv;
int64_t start_tics;
const int64_t lock_timeout = 2000000LL;
hw->acam_bin = acam_calc_pll(&hsdiv, &refdiv, 80.9553, 31.25e6) / 3.0;
/* Disable TDC inputs prior to configuring */
fd_writel(FD_TDCSR_STOP_DIS | FD_TDCSR_START_DIS, FD_REG_TDCSR);
if(mode == ACAM_RMODE)
{
acam_write_reg(dev, 0, AR0_ROsc | AR0_RiseEn0 | AR0_RiseEn1 | AR0_HQSel );
acam_write_reg(dev, 1, AR1_Adj(0, 0) |
AR1_Adj(1, 2) |
AR1_Adj(2, 6) |
AR1_Adj(3, 0) |
AR1_Adj(4, 2) |
AR1_Adj(5, 6) |
AR1_Adj(6, 0));
acam_write_reg(dev, 2, AR2_RMode | AR2_Adj(7, 2) | AR2_Adj(8, 6));
acam_write_reg(dev, 3, 0);
acam_write_reg(dev, 4, AR4_EFlagHiZN);
acam_write_reg(dev, 5, AR5_StartRetrig |AR5_StartOff1(hw->calib.acam_start_offset) | AR5_MasterAluTrig);
acam_write_reg(dev, 6, AR6_Fill(200) | AR6_PowerOnECL);
acam_write_reg(dev, 7, AR7_HSDiv(hsdiv) | AR7_RefClkDiv(refdiv) | AR7_ResAdj | AR7_NegPhase);
acam_write_reg(dev, 11, 0x7ff0000);
acam_write_reg(dev, 12, 0x0000000);
acam_write_reg(dev, 14, 0);
/* Reset the ACAM after the configuration */
acam_write_reg(dev, 4, AR4_EFlagHiZN | AR4_MasterReset | AR4_StartTimer(0));
} else if (mode == ACAM_IMODE)
{
acam_write_reg(dev, 0, AR0_TRiseEn(0) | AR0_HQSel | AR0_ROsc);
acam_write_reg(dev, 2, AR2_IMode);
acam_write_reg(dev, 5, AR5_StartOff1(3000) | AR5_MasterAluTrig);
acam_write_reg(dev, 6, 0);
acam_write_reg(dev, 7, AR7_HSDiv(hsdiv) | AR7_RefClkDiv(refdiv) | AR7_ResAdj | AR7_NegPhase);
acam_write_reg(dev, 11, 0x7ff0000);
acam_write_reg(dev, 12, 0x0000000);
acam_write_reg(dev, 14, 0);
/* Reset the ACAM after the configuration */
acam_write_reg(dev, 4, AR4_EFlagHiZN | AR4_MasterReset | AR4_StartTimer(0));
} else
return -1; /* Unsupported mode? */
int i;
dbg("%s: Waiting for ACAM ring oscillator lock...\n", __FUNCTION__);
start_tics = get_tics();
for(;;)
{
if(acam_pll_locked(dev))
break;
if(get_tics() - start_tics > lock_timeout)
{
dbg("%s: ACAM PLL does not lock.\n", __FUNCTION__);
fail(TEST_ACAM_IF, "ACAM PLL does not lock.");
return -1;
}
usleep(10000);
}
acam_set_address(dev, 8); /* Permamently select FIFO1 register for readout */
return 0;
}
/*
---------------------
Calibration functions
---------------------
*/
#define chan_writel(data, addr) fd_writel((data), channel * 0x100 + (addr))
#define chan_readl(addr) fd_readl(channel * 0x100 + (addr))
/* Measures the the FPGA-generated TDC start and the output of one of the fine delay chips (channel)
at a pre-defined number of taps (fine). Retuns the delay in picoseconds. The measurement is repeated
and averaged (n_avgs) times. Also, the standard deviation of the result can be written to (sdev)
if it's not NULL. */
static double measure_output_delay(fdelay_device_t *dev, int channel, int fine, int n_avgs, double *sdev)
{
fd_decl_private(dev)
double acc = 0.0, std = 0.0;
int i;
/* Mapping between the channel of the delay card and the stop inputs of the ACAM */
int chan_to_acam[5] = {0, 1, 2, 3, 4};
/* Mapping between the channel number and the time tag FIFOs of the ACAM */
int chan_to_fifo[5] = {0, 8, 8, 8, 8};
double rec[1024];
/* Disable the output for the channel being calibrated */
sgpio_set_pin(dev, SGPIO_OUTPUT_EN(channel), 0);
/* Enable the stop input in the ACAM corresponding to the channel being calibrated */
acam_write_reg(dev, 0, AR0_TRiseEn(0) | AR0_TRiseEn(chan_to_acam[channel]) | AR0_HQSel | AR0_ROsc);
/* Program the output delay line setpoint */
chan_writel( fine, FD_REG_FRR);
chan_writel( FD_DCR_ENABLE | FD_DCR_MODE | FD_DCR_UPDATE, FD_REG_DCR);
chan_writel( FD_DCR_FORCE_DLY | FD_DCR_ENABLE, FD_REG_DCR);
/* Set the calibration pulse mask to genrate calibration pulses only on one channel at a time.
This minimizes the crosstalk in the output buffer which can severely decrease the accuracy
of calibration measurements */
fd_writel( FD_CALR_PSEL_W(1<<(channel-1)), FD_REG_CALR);
udelay(1);
/* Do n_avgs single measurements and average */
for(i=0;i<n_avgs;i++)
{
uint32_t fr;
/* Re-arm the ACAM (it's working in a single-shot mode) */
fd_writel( FD_TDCSR_ALUTRIG, FD_REG_TDCSR);
udelay(1);
/* Produce a calibration pulse on the TDC start and the appropriate output channel */
fd_writel( FD_CALR_CAL_PULSE | FD_CALR_PSEL_W((1<<(channel-1))), FD_REG_CALR);
udelay(1);
/* read the tag, convert to picoseconds and average */
fr = acam_read_reg(dev, chan_to_fifo[channel]);
double tag = (double)((fr >> 0) & 0x1ffff) * hw->acam_bin * 3.0;
// dbg("Tag %.1f\n", tag);
acc += tag;
rec[i] = tag;
}
/* Calculate standard dev and average value */
acc /= (double) n_avgs;
for(i=0;i<n_avgs;i++)
std += (rec[i] - acc) * (rec[i] - acc);
if(sdev) *sdev = sqrt(std /(double) n_avgs);
chan_writel( 0, FD_REG_DCR);
return acc;
}
static void measure_linearity(double *x, int n, double *inl, double *dnl)
{
double slope = (x[n-1] - x[0]) / (double)(n-1);
int i;
*inl = 0;
*dnl = 0;
for(i=0;i<n;i++)
{
double d = fabs(x[i] - (((double)i) * slope + x[0]));
if(*inl < d)
*inl = d;
if(i>0)
{
d=fabs(x[i]-x[i-1]-slope);
if(d>*dnl)
*dnl = d;
}
}
}
/* Measures the transfer function of the fine delay line (i.e. delay vs number of taps) and checks
its linearity, performing an indirect check of the delay lines' and TDC signal connections. */
#define MAX_DNL 20
#define MAX_INL 60
static int test_delay_transfer_function(fdelay_device_t *dev)
{
double inl, dnl;
int lin_fail = 0;
fd_decl_private(dev)
int channel, i;
double bias, x, meas[4][FDELAY_NUM_TAPS], sdev[4][FDELAY_NUM_TAPS];
fd_writel( FD_GCR_BYPASS, FD_REG_GCR);
acam_configure(dev, ACAM_IMODE);
fd_writel( FD_TDCSR_START_EN | FD_TDCSR_STOP_EN, FD_REG_TDCSR);
for(channel = 1; channel <= 4; channel++)
{
dbg("calibrating channel %d\n", channel);
bias = measure_output_delay(dev, channel, 0, FDELAY_CAL_AVG_STEPS, &sdev[0][channel-1]);
meas[channel-1][0] = 0.0;
for(i=FDELAY_NUM_TAPS-1;i>=0;i--)
{
x = measure_output_delay(dev, channel, i,
FDELAY_CAL_AVG_STEPS, &sdev[channel-1][i]);
meas[channel-1][i] = x - bias;
}
measure_linearity(meas[channel-1], FDELAY_NUM_TAPS-1, &inl, &dnl);
dbg("Linearity: INL = %.1f ps, DNL = %.1f ps\n", inl, dnl);
if(inl > MAX_INL || dnl > MAX_DNL)
lin_fail=1;
}
if(lin_fail)
{
dbg("Linearity check failed.\n");
fail(TEST_DELAY_LINE, "Maximum INL/DNL exceeded, indicating a wrong connection of the delay chip and/or the TDC calibration signals");
return -1;
}
return 0;
/* FILE *f=fopen("t_func.dat","w");
for(i=0;i<FDELAY_NUM_TAPS;i++)
{
fprintf(f, "%d %.0f %.0f %.0f %.0f %.0f %.0f %.0f %.0f\n", i,
meas[i][0], meas[i][1], meas[i][2], meas[i][3],
sdev[i][0], sdev[i][1], sdev[i][2], sdev[i][3]);
}
fclose(f);*/
}
/* Finds the preset (i.e. the numer of taps) of the output delay line in (channel)
at which it introduces exactly 8 ns more than when it's programmed to 0 taps.
Uses a binary search algorithm to speed up the calibration (assuming that the
line is monotonous). */
static int find_8ns_tap(fdelay_device_t *dev, int channel)
{
int l = 0, r=FDELAY_NUM_TAPS-1;
dbg("Calibrating: %d\n", channel);
/* Measure the delay at zero setting, so it can be further subtracted to get only the
delay part introduced by the delay line (ingoring the TDC, FPGA and routing delays). */
double bias = measure_output_delay(dev, channel, 0, FDELAY_CAL_AVG_STEPS, NULL);
while(abs(l-r)>1)
{
int mid = (l+r) / 2;
double dly = measure_output_delay(dev, channel, mid, FDELAY_CAL_AVG_STEPS, NULL) - bias;
if(dly < 8000.0) l = mid; else r = mid;
}
return l;
}
/* Evaluates 2nd order polynomial. Coefs have 32 fractional bits. */
static int32_t eval_poly(int64_t *coef, int32_t x)
{
int32_t y;
y= (coef[0] * (int64_t)x * (int64_t)x + coef[1] * (int64_t) x + coef[2]) >> 32;
return (int32_t) y;
}
/* Performs the startup calibration of the output delay lines. */
int calibrate_outputs(fdelay_device_t *dev)
{
fd_decl_private(dev)
int i, channel, temp;
#ifdef PERFORM_LONG_TESTS
if(test_delay_transfer_function(dev) < 0)
return -1;
#endif
fd_writel( FD_GCR_BYPASS, FD_REG_GCR);
acam_configure(dev, ACAM_IMODE);
fd_writel( FD_TDCSR_START_EN | FD_TDCSR_STOP_EN, FD_REG_TDCSR);
for(channel = 1; channel <= 4; channel++)
{
while(ds18x_read_temp(dev, &temp) < 0)
usleep(100000);
int cal_measd = find_8ns_tap(dev, channel);
int cal_fitted = eval_poly(hw->calib.frr_poly, temp);
dbg("%s: CH%d: 8ns @ %d (fitted %d, offset %d, temperature %d.%1d)\n", __FUNCTION__, channel, cal_measd, cal_fitted, cal_measd-cal_fitted, temp);
hw->frr_cur[channel-1] = cal_measd;
hw->frr_offset[channel-1] = cal_measd - cal_fitted;
}
return 0;
}
/* TODO: run in a timer context every few seconds instead of the main program loop */
void fdelay_update_calibration(fdelay_device_t *dev)
{
fd_decl_private(dev);
int channel, temp;
ds18x_read_temp(dev, &temp);
for(channel = 1; channel <= 4; channel++)
{
int cal_fitted = eval_poly(hw->calib.frr_poly, temp) + hw->frr_offset[channel-1];
dbg("%s: CH%d: FRR = %d\n", __FUNCTION__, channel, cal_fitted);
hw->frr_cur[channel-1] = cal_fitted;
chan_writel(hw->frr_cur[channel-1], FD_REG_FRR);
}
}
#if 0
void poll_stats()
{
int raw = fd_readl(FD_REG_IECRAW);
int tagged = fd_readl(FD_REG_IECTAG);
int pd = fd_readl(FD_REG_IEPD) & 0xff;
if(events_raw != raw || events_tagged != tagged || pd != tag_delay)
{
events_raw = raw;
events_tagged = tagged;
tag_delay = pd;
// if(events_raw != events_tagged) printf("ERROR: raw %d vs tagged %d\n", raw,tagged);
// printf("NewStats: raw %d tagged %d pdelay %d nsec\n", raw, tagged ,(pd+3)*8);
}
}
#endif
static int read_calibration_eeprom(fdelay_device_t *dev, struct fine_delay_calibration *d_cal)
{
struct fine_delay_calibration cal;
mi2c_init(dev);
if(eeprom_read(dev, EEPROM_ADDR, 0, (uint8_t *) &cal, sizeof(struct fine_delay_calibration)) != sizeof(struct fine_delay_calibration))
{
dbg("Can't read calibration EEPROM.\n");
return -1;
}
if(cal.magic != FDELAY_MAGIC_ID)
{
dbg("EEPROM doesn't contain valid calibration block.\n");
return 0;
}
memcpy(d_cal, &cal, sizeof(cal));
return 1;
}
/*
-------------------------------------
Public API
-------------------------------------
*/
/* Initialize & self-calibrate the Fine Delay card */
int fdelay_init(fdelay_device_t *dev)
{
int i, rv;
struct fine_delay_hw *hw;
fdelay_time_t t_zero;
dbg("Init: dev %x\n", dev);
hw = (struct fine_delay_hw *) malloc(sizeof(struct fine_delay_hw));
if(! hw)
return -1;
dev->priv_fd = (void *) hw;
hw->base_addr = dev->base_addr;
hw->base_i2c = 0x100;
hw->base_onewire = dev->base_addr + 0x500;
hw->wr_enabled = 0;
hw->wr_state = FDELAY_FREE_RUNNING;
hw->acam_addr = 0xff;
dbg("%s: Initializing the Fine Delay Card\n", __FUNCTION__);
/* Read the Identification register and check if we are talking to a proper Fine Delay HDL Core */
if(fd_readl(FD_REG_IDR) != FDELAY_MAGIC_ID)
{
fail(TEST_FIRMWARE, "Core not responding. Firmware loaded incorrectly?");
dbg("%s: invalid core signature. Are you sure you have loaded the FPGA with the Fine Delay firmware?\n", __FUNCTION__);
return -1;
}
if(! (fd_readl(FD_REG_GCR) & FD_GCR_FMC_PRESENT))
{
fail(TEST_PRESENCE, "FMC Card not detected in the slot. Maybe a fault on PRSNT_L line?");
dbg("%s: FMC Presence line not active. Is the FMC correctly inserted into the carrier?\n", __FUNCTION__);
return -1;
}
rv = read_calibration_eeprom(dev, &hw->calib);
if(rv < 0)
{
fail(TEST_SPI, "FMC EEPROM not detected.");
return -1;
} else if(!rv)
{
int i;
dbg("%s: Calibration EEPROM does not contain a valid calibration block. Using default calibration values\n", __FUNCTION__);
hw->calib.frr_poly[0] = -165202LL;
hw->calib.frr_poly[1] = -29825595LL;
hw->calib.frr_poly[2] = 3801939743082LL;
hw->calib.tdc_zero_offset = 35600;
hw->calib.atmcr_val = 2 | (1000 << 4);
hw->calib.adsfr_val = 56648;
hw->calib.acam_start_offset = 10000;
for(i=0;i<4;i++)
hw->calib.zero_offset[i] = 50000;
}
/* Reset the FMC hardware. */
fd_do_reset(dev, FD_RESET_HW);
/* Initialize the clock system - AD9516 PLL */
oc_spi_init(dev);
if(sgpio_init(dev) < 0)
return -1;
if(ad9516_init(dev) < 0)
return -1;
if(ds18x_init(dev) < 0)
{
fail(TEST_SPI, "DS18x sensor not detected.");
dbg("DS18x sensor not detected. Bah!\n");
return -1;
}
int temp;
ds18x_read_temp(dev, &temp);
dbg("Device temperature: %d\n", temp);
/* Configure default states of the SPI GPIO pins */
sgpio_set_dir(dev, SGPIO_TRIG_SEL, 1);
sgpio_set_pin(dev, SGPIO_TRIG_SEL, 1);
for(i=1;i<=4;i++)
{
sgpio_set_pin(dev, SGPIO_OUTPUT_EN(i), 0);
sgpio_set_dir(dev, SGPIO_OUTPUT_EN(i), 1);
}
sgpio_set_dir(dev, SGPIO_TERM_EN, 1);
sgpio_set_pin(dev, SGPIO_TERM_EN, 0);
/* Reset the FD core once we have proper reference/TDC clocks */
fd_do_reset(dev, FD_RESET_CORE);
while(! (fd_readl(FD_REG_GCR) & FD_GCR_DDR_LOCKED))
udelay(1);
fd_do_reset(dev, FD_RESET_CORE);
/* Disable the delay generator core, so we can access the ACAM from the host, both for
initialization and calibration */
fd_writel( FD_GCR_BYPASS, FD_REG_GCR);
#ifdef PERFORM_LONG_TESTS
if(test_pll_dac(dev) < 0)
return -1;
#endif
/* Test if ACAM addr/data lines are OK */
if(acam_test_bus(dev) < 0)
return -1;
/* Calibrate the output delay lines */
if(calibrate_outputs(dev) < 0)
return -1;
/* Switch to the R-MODE (more precise) */
acam_configure(dev, ACAM_RMODE);
/* Switch the ACAM to be driven by the delay core instead of the host */
fd_writel( 0, FD_REG_GCR);
/* Clear and disable the timestamp readout buffer */
fd_writel( FD_TSBCR_PURGE | FD_TSBCR_RST_SEQ, FD_REG_TSBCR);
/* Program the ACAM-specific timestamper registers using pre-defined calibration values:
- bin -> internal timebase scalefactor (ADSFR),
- Start offset (must be consistent with the value written to the ACAM reg 4)
- timestamp merging control register (ATMCR) */
fd_writel( hw->calib.adsfr_val, FD_REG_ADSFR);
fd_writel( 3 * hw->calib.acam_start_offset, FD_REG_ASOR);
fd_writel( hw->calib.atmcr_val, FD_REG_ATMCR);
t_zero.utc = 0;
t_zero.coarse = 0;
fdelay_set_time(dev, t_zero);
/* Enable input */
udelay(1);
fd_writel(FD_GCR_INPUT_EN, FD_REG_GCR);
/* Enable output driver */
// sgpio_set_pin(dev, SGPIO_DRV_OEN, 1);
dbg("FD initialized\n");
return 0;
}
/* Configures the trigger input. Enable enables the input, termination selects the impedance
of the trigger input (0 == 2kohm, 1 = 50 ohm) */
int fdelay_configure_trigger(fdelay_device_t *dev, int enable, int termination)
{
fd_decl_private(dev)
if(termination)
{
dbg("%s: 50-ohm terminated mode\n", __FUNCTION__);
sgpio_set_pin(dev,SGPIO_TERM_EN,1);
} else {
dbg("%s: high impedance mode\n", __FUNCTION__);
sgpio_set_pin(dev,SGPIO_TERM_EN,0);
};
if(enable)
{
fd_writel(fd_readl(FD_REG_GCR) | FD_GCR_INPUT_EN, FD_REG_GCR);
} else
fd_writel(fd_readl(FD_REG_GCR) & (~FD_GCR_INPUT_EN) , FD_REG_GCR);
return 0;
}
/* Converts a positive time interval expressed in picoseconds to the timestamp format used in the Fine Delay core */
fdelay_time_t fdelay_from_picos(const uint64_t ps)
{
fdelay_time_t t;
uint64_t tmp = ps;
t.frac = (tmp % 8000ULL) * (uint64_t)(1<<FDELAY_FRAC_BITS) / 8000ULL;
tmp -= (tmp % 8000ULL);
tmp /= 8000ULL;
t.coarse = tmp % 125000000ULL;
tmp -= (tmp % 125000000ULL);
tmp /= 125000000ULL;
t.utc = tmp;
return t;
}
/* Substract two timestamps */
static fdelay_time_t ts_sub(fdelay_time_t a, fdelay_time_t b)
{
a.frac -= b.frac;
if(a.frac < 0)
{
a.frac += 4096;
a.coarse--;
}
a.coarse -= b.coarse;
if(a.coarse < 0)
{
a.coarse += 125000000;
a.utc --;
}
return a;
}
/* Add two timestamps */
static fdelay_time_t ts_add(fdelay_time_t a, fdelay_time_t b)
{
a.frac += b.frac;
if(a.frac >= (1<<FDELAY_FRAC_BITS))
{
a.frac -= (1<<FDELAY_FRAC_BITS);
a.coarse++;
}
a.coarse += b.coarse;
if(b.coarse >= 125000000)
{
a.coarse -= 125000000;
a.utc ++;
}
return a;
}
/* Converts a Fine Delay time stamp to plain picoseconds */
int64_t fdelay_to_picos(const fdelay_time_t t)
{
int64_t tp = (((int64_t)t.frac * 8000LL) >> FDELAY_FRAC_BITS) + ((int64_t) t.coarse * 8000LL) + ((int64_t)t.utc * 1000000000000LL);
return tp;
}
static int poll_rbuf(fdelay_device_t *dev)
{
fd_decl_private(dev)
if((fd_readl(FD_REG_TSBCR) & FD_TSBCR_EMPTY) == 0)
return 1;
return 0;
}
/* TODO: chan_mask */
int fdelay_configure_readout(fdelay_device_t *dev, int enable)
{
fd_decl_private(dev)
if(enable)
{
fd_writel( FD_TSBCR_PURGE | FD_TSBCR_RST_SEQ, FD_REG_TSBCR);
fd_writel( FD_TSBCR_CHAN_MASK_W(1) | FD_TSBCR_ENABLE, FD_REG_TSBCR);
} else
fd_writel( FD_TSBCR_PURGE | FD_TSBCR_RST_SEQ, FD_REG_TSBCR);
return 0;
}
/* Reads up to (how_many) timestamps from the FD ring buffer and stores them in (timestamps).
Returns the number of read timestamps. */
int fdelay_read(fdelay_device_t *dev, fdelay_time_t *timestamps, int how_many)
{
fd_decl_private(dev)
int n_read = 0;
// dbg("tsbcr %x\n", fd_readl(FD_REG_TSBCR));
while(poll_rbuf(dev))
{
fdelay_time_t ts;
uint32_t seq_frac;
if(!how_many) break;
ts.utc = ((int64_t) (fd_readl(FD_REG_TSBR_SECH) & 0xff) << 32) | fd_readl(FD_REG_TSBR_SECL);
ts.coarse = fd_readl(FD_REG_TSBR_CYCLES) & 0xfffffff;
// dbg("Coarse %d\n", ts.coarse);
seq_frac = fd_readl(FD_REG_TSBR_FID);
ts.frac = FD_TSBR_FID_FINE_R(seq_frac);
ts.seq_id = FD_TSBR_FID_SEQID_R(seq_frac);
ts.channel = FD_TSBR_FID_CHANNEL_R(seq_frac);
*timestamps++ = ts_sub(ts, fdelay_from_picos(hw->calib.tdc_zero_offset));
how_many--;
n_read++;
}
// printf("read %d\n", how_many, n_read);
return n_read;
}
/* Configures the output channel (channel) to produce pulses delayed from the trigger by (delay_ps).
The output pulse width is proviced in (width_ps) parameter. */
int fdelay_configure_output(fdelay_device_t *dev, int channel, int enable, int64_t delay_ps, int64_t width_ps, int64_t delta_ps, int rep_count)
{
fd_decl_private(dev)
uint32_t base = (channel-1) * 0x20;
uint32_t dcr;
fdelay_time_t start, end, delta;
if(channel < 1 || channel > 4)
return -1;
delay_ps -= hw->calib.zero_offset[channel-1];
start = fdelay_from_picos(delay_ps);
end = fdelay_from_picos(delay_ps + width_ps);
delta = fdelay_from_picos(delta_ps);
// printf("Start: %lld: %d:%d\n", start.utc, start.coarse, start.frac);
chan_writel(hw->frr_cur[channel-1], FD_REG_FRR);
chan_writel(start.utc >> 32, FD_REG_U_STARTH);
chan_writel(start.utc & 0xffffffff, FD_REG_U_STARTL);
chan_writel(start.coarse, FD_REG_C_START);
chan_writel(start.frac, FD_REG_F_START);
chan_writel(end.utc >> 32, FD_REG_U_ENDH);
chan_writel(end.utc & 0xffffffff, FD_REG_U_ENDL);
chan_writel(end.coarse, FD_REG_C_END);
chan_writel(end.frac, FD_REG_F_END);
chan_writel(delta.utc & 0xf, FD_REG_U_DELTA);
chan_writel(delta.coarse, FD_REG_C_DELTA);
chan_writel(delta.frac, FD_REG_F_DELTA);
// chan_writel(0, FD_REG_RCR);
chan_writel(FD_RCR_REP_CNT_W(rep_count) | (rep_count < 0 ? FD_RCR_CONT : 0), FD_REG_RCR);
dcr = 0;
/* For narrowly spaced pulses, we don't have enough time to reload the tap number into the corresponding
SY89295 - therefore, the width/spacing resolution is limited to 4 ns. */
if((delta_ps - width_ps) < 200000 || (width_ps < 200000))
dcr = FD_DCR_NO_FINE;
chan_writel(dcr | FD_DCR_UPDATE, FD_REG_DCR);
chan_writel(dcr | FD_DCR_ENABLE, FD_REG_DCR);
sgpio_set_pin(dev, SGPIO_OUTPUT_EN(channel), enable ? 1 : 0);
return 0;
}
/* Configures the output channel (channel) to produce pulses delayed from the trigger by (delay_ps).
The output pulse width is proviced in (width_ps) parameter. */
int fdelay_configure_pulse_gen(fdelay_device_t *dev, int channel, int enable, fdelay_time_t t_start, int64_t width_ps, int64_t delta_ps, int rep_count)
{
fd_decl_private(dev)
uint32_t base = (channel-1) * 0x20;
uint32_t dcr;
fdelay_time_t start, end, delta;
if(channel < 1 || channel > 4)
return -1;
start = t_start;
end = fdelay_from_picos(fdelay_to_picos(start) + width_ps - 4000);
delta = fdelay_from_picos(delta_ps);
//start = t_start;
//end = ts_add(start, fdelay_from_picos(width_ps));
//delta = fdelay_from_picos(delta_ps);
//printf("Start: %lld: %d:%d\n", start.utc, start.coarse, start.frac);
//printf("width: %lld delta: %lld rep: %d\n", width_ps, delta_ps, rep_count);
chan_writel(hw->frr_cur[channel-1], FD_REG_FRR);
chan_writel(start.utc >> 32, FD_REG_U_STARTH);
chan_writel(start.utc & 0xffffffff, FD_REG_U_STARTL);
chan_writel(start.coarse, FD_REG_C_START);
chan_writel(start.frac, FD_REG_F_START);
chan_writel(end.utc >> 32, FD_REG_U_ENDH);
chan_writel(end.utc & 0xffffffff, FD_REG_U_ENDL);
chan_writel(end.coarse, FD_REG_C_END);
chan_writel(end.frac, FD_REG_F_END);
chan_writel(delta.utc & 0xf, FD_REG_U_DELTA);
chan_writel(delta.coarse, FD_REG_C_DELTA);
chan_writel(delta.frac, FD_REG_F_DELTA);
// chan_writel(0, FD_REG_RCR);
chan_writel(FD_RCR_REP_CNT_W(rep_count < 0 ? 0 :rep_count-1) | (rep_count < 0 ? FD_RCR_CONT : 0), FD_REG_RCR);
dcr = FD_DCR_MODE;
/* For narrowly spaced pulses, we don't have enough time to reload the tap number into the corresponding
SY89295 - therefore, the width/spacing resolution is limited to 4 ns. */
if((delta_ps - width_ps) < 200000 || (width_ps < 200000))
dcr |= FD_DCR_NO_FINE;
chan_writel(dcr | FD_DCR_UPDATE, FD_REG_DCR);
chan_writel(dcr | FD_DCR_ENABLE, FD_REG_DCR);
chan_writel(dcr | FD_DCR_ENABLE | FD_DCR_PG_ARM, FD_REG_DCR);
sgpio_set_pin(dev, SGPIO_OUTPUT_EN(channel), enable ? 1 : 0);
return 0;
}
int fdelay_channel_triggered(fdelay_device_t *dev, int channel)
{
fd_decl_private(dev)
return chan_readl(FD_REG_DCR) & FD_DCR_PG_TRIG ? 1: 0;
}
/* Todo: write get_time() */
int fdelay_set_time(fdelay_device_t *dev, const fdelay_time_t t)
{
fd_decl_private(dev)
uint32_t tcr;
uint32_t gcr;
fd_writel(0, FD_REG_GCR);
fd_writel(t.utc >> 32, FD_REG_TM_SECH);
fd_writel(t.utc & 0xffffffff, FD_REG_TM_SECL);
fd_writel(t.coarse, FD_REG_TM_CYCLES);
tcr = fd_readl(FD_REG_TCR);
fd_writel(tcr | FD_TCR_SET_TIME, FD_REG_TCR);
return 0;
}
/* Todo: write get_time() */
int fdelay_get_time(fdelay_device_t *dev, fdelay_time_t *t)
{
fd_decl_private(dev)
uint32_t tcr;
tcr = fd_readl(FD_REG_TCR);
fd_writel(tcr | FD_TCR_CAP_TIME, FD_REG_TCR);
t->utc = fd_readl(FD_REG_TM_SECL);
t->coarse = fd_readl(FD_REG_TM_CYCLES);
return 0;
}
#if 0
/* To be rewritten to use interrupts and new WR FSM (see TCR register description).
Use the API provided in fdelay_lib.h */
int fdelay_configure_sync(fdelay_device_t *dev, int mode)
{
fd_decl_private(dev)
if(mode == FDELAY_SYNC_LOCAL)
{
fd_writel(0, FD_REG_GCR);
// fd_writel(FD_GCR_CSYNC_INT, FD_REG_GCR);
hw->wr_enabled = 0;
} else {
fd_writel(0, FD_REG_GCR);
hw->wr_enabled = 1;
hw->wr_state = FDELAY_WR_OFFLINE;
}
}
int fdelay_get_sync_status(fdelay_device_t *dev)
{
fd_decl_private(dev)
if(!hw->wr_enabled) return FDELAY_FREE_RUNNING;
switch(hw->wr_state)
{
case FDELAY_WR_OFFLINE:
if(fd_readl(FD_REG_GCR) & FD_GCR_WR_READY)
{
dbg("-> WR Core synced\n");
hw->wr_state = FDELAY_WR_READY;
}
break;
case FDELAY_WR_READY:
fd_writel(FD_GCR_WR_LOCK_EN, FD_REG_GCR);
hw->wr_state = FDELAY_WR_SYNCING;
break;
case FDELAY_WR_SYNCING:
if(fd_readl(FD_REG_GCR) & FD_GCR_WR_LOCKED)
{
fd_writel(FD_GCR_WR_LOCK_EN | FD_GCR_CSYNC_WR, FD_REG_GCR);
fd_writel(FD_GCR_WR_LOCK_EN , FD_REG_GCR);
fd_writel(FD_GCR_WR_LOCK_EN | FD_GCR_INPUT_EN, FD_REG_GCR);
hw->wr_state = FDELAY_WR_SYNCED;
}
break;
case FDELAY_WR_SYNCED:
if((fd_readl(FD_REG_GCR) & FD_GCR_WR_LOCKED) == 0)
hw->wr_state = FDELAY_WR_OFFLINE;
break;
}
return hw->wr_state;
}
#endif
# if 0
/* We might implement SPLL-based DMTD calibration, but not now - don't include in the driver */
int fd_update_spll(fdelay_device_t *dev)
{
struct spll_helper_state pll;
fd_decl_private(dev)
int i =0;
helper_start(dev, &pll);
fd_writel(FD_CALR_CAL_DMTD, FD_REG_CALR);
sgpio_set_pin(dev, SGPIO_TRIG_SEL, 0);
for(;;)
{
helper_update(&pll);
//if(pll.prelock.ld.locked)
// dbg("LOCK!");
}
}
#endif
#include <stdio.h>
#include "fdelay_lib.h"
int spec_fdelay_init(int argc, char *argv[], fdelay_device_t *dev);
main(int argc, char *argv[])
{
fdelay_device_t dev;
fdelay_time_t t_cur, t_start;
if(spec_fdelay_init(argc, argv, &dev) < 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_start.coarse = t_cur.coarse;
t_start.utc = t_cur.utc+1;
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 */
while(!fdelay_channel_triggered(&dev, 1) || fdelay_channel_triggered(&dev, 2))
usleep(10000); /* wait until both outputs have triggered*/;
return 0;
}
#include <stdio.h>
#include "fdelay_lib.h"
#include "rr_io.h"
void my_writel(void *priv, uint32_t data, uint32_t addr)
{
rr_writel(data, addr);
}
uint32_t my_readl(void *priv, uint32_t addr)
{
uint32_t d = rr_readl(addr);
return d;
}
main()
{
fdelay_device_t dev;
rr_init();
dev.writel = my_writel;
dev.readl = my_readl;
dev.base_addr = 0x84000;
if(fdelay_init(&dev) < 0)
return -1;
fdelay_configure_trigger(&dev, 1,1);
fdelay_configure_output(&dev,1,1,500000, 100000, 100000, 0);
fdelay_configure_output(&dev,2,1,500000, 100000, 100000, 0);
fdelay_configure_output(&dev,3,1,500000, 100000, 100000, 0);
fdelay_configure_output(&dev,4,1,500000, 100000, 100000, 0);
fdelay_configure_readout(&dev, 1);
// fd_update_spll(&dev);
int64_t prev = 0, dp, pmin=10000000000LL,pmax=0;
#if 0
for(;;)
{
fdelay_time_t ts;
if(fdelay_read(&dev, &ts, 1) == 1)
{
int64_t ts_p = fdelay_to_picos(ts), d;
d=ts_p - prev;
if(prev > 0)
{
if(d<pmin) pmin=d;
if(d>pmax) pmax=d;
fprintf(stderr,"Got it %lld:%d:%d delta %lld span %lld\n", ts.utc, ts.coarse, ts.frac, d, pmax-pmin);
}
prev = ts_p;
}
}
#endif
}
#include <stdio.h>
#include "fdelay_lib.h"
#include "rr_io.h"
int spec_fdelay_init(int argc, char *argv[], fdelay_device_t *dev);
main(int argc, char *argv[])
{
fdelay_device_t dev;
fdelay_time_t t_cur, t_start;
if(spec_fdelay_init(argc, argv, &dev) < 0)
{
fdelay_show_test_results();
return -1;
}
fdelay_configure_trigger(&dev, 1,1);
fdelay_configure_output(&dev,1,1,500000, 100000, 100000, 0);
fdelay_configure_output(&dev,2,1,500000, 100000, 100000, 0);
fdelay_configure_output(&dev,3,1,500000, 100000, 100000, 0);
fdelay_configure_output(&dev,4,1,500000, 100000, 100000, 0);
fdelay_configure_readout(&dev, 1);
// fd_update_spll(&dev);
int64_t prev = 0, dp, pmin=10000000000LL,pmax=0;
#if 0
for(;;)
{
fdelay_time_t ts;
if(fdelay_read(&dev, &ts, 1) == 1)
{
int64_t ts_p = fdelay_to_picos(ts), d;
d=ts_p - prev;
if(prev > 0)
{
if(d<pmin) pmin=d;
if(d>pmax) pmax=d;
fprintf(stderr,"Got it %lld:%d:%d delta %lld span %lld\n", ts.utc, ts.coarse, ts.frac, d, pmax-pmin);
}
prev = ts_p;
}
}
#endif
for(;;)
{
fdelay_update_calibration(&dev);
sleep(1);
}
}
#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))
printf("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);
do /* wait until the chip becomes ready */
{
mi2c_start(dev);
busy = mi2c_put_byte(dev, i2c_addr << 1);
mi2c_stop(dev);
} while(busy);
}
return size;
}
OBJS = minibone_lib.o ptpd_netif.o
all: $(OBJS)
gcc -o m $(OBJS)
\ No newline at end of file
/* MiniBone library. BUGGY CRAP CODE INTENDED FOR TESTING ONLY! */
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/time.h>
#include "ptpd_netif.h"
#define F_SEL(x) (x & 0xf)
#define F_ERROR (1<<1)
#define F_READBACK (1<<0)
#define F_WRITE (1<<4)
#define RX_TIMEOUT 10
#define MBN_ETHERTYPE 0xa0a0
struct mbn_packet {
uint16_t flags ;
uint32_t a_d;
uint32_t d;
} __attribute__((packed));
struct mb_device {
mac_addr_t dest;
uint16_t ethertype;
wr_socket_t *sock;
int tx_packets, rx_packets, tx_retries, rx_retries;
};
typedef struct
{
uint64_t start_tics;
uint64_t timeout;
} timeout_t ;
static uint64_t get_tics()
{
struct timezone tz = {0, 0};
struct timeval tv;
gettimeofday(&tv, &tz);
return (uint64_t) tv.tv_sec * 1000000ULL + (uint64_t) tv.tv_usec;
}
static inline int tmo_init(timeout_t *tmo, uint32_t milliseconds)
{
tmo->start_tics = get_tics();
tmo->timeout = (uint64_t) milliseconds * 1000ULL;
return 0;
}
static inline int tmo_restart(timeout_t *tmo)
{
tmo->start_tics = get_tics();
return 0;
}
static inline int tmo_expired(timeout_t *tmo)
{
return (get_tics() - tmo->start_tics > tmo->timeout);
}
void *mbn_open(const char *if_name, mac_addr_t target)
{
struct mb_device *dev = malloc(sizeof(struct mb_device));
wr_sockaddr_t saddr;
if(!dev)
return NULL;
memset(dev, 0, sizeof(struct mb_device));
memcpy(dev->dest, target, 6);
strcpy(saddr.if_name, if_name);
memcpy(saddr.mac, target, 6);
saddr.ethertype = htons(MBN_ETHERTYPE);
saddr.family = PTPD_SOCK_RAW_ETHERNET;
dev->sock = ptpd_netif_create_socket(PTPD_SOCK_RAW_ETHERNET, 0, &saddr);
if(!dev->sock)
{
free(dev);
return NULL;
}
return (void *)dev;
}
static int mbn_send(void *priv, uint8_t *data, int size)
{
struct mb_device *dev = (struct mb_device *)priv;
wr_sockaddr_t to;
memcpy(to.mac, dev->dest, 6);
to.ethertype = MBN_ETHERTYPE;
return ptpd_netif_sendto(dev->sock, &to, (void*)data, size, NULL);
}
static int mbn_recv(void *handle, uint8_t *data, int size, int timeout)
{
struct mb_device *dev = (struct mb_device *)handle;
wr_sockaddr_t from;
timeout_t rx_tmo;
tmo_init(&rx_tmo, timeout);
do {
int n = ptpd_netif_recvfrom(dev->sock, &from, (void*)data, size, NULL);
if(n > 0 && from.ethertype == MBN_ETHERTYPE && !memcmp(from.mac, dev->dest, 6))
{
dev->rx_packets++;
return n;
}
// dev->rx_retries++;
} while(!tmo_expired(&rx_tmo));
return 0;
}
void mbn_writel(void *handle, uint32_t d, uint32_t a)
{
struct mb_device *dev = (struct mb_device *)handle;
int n_retries = 3;
struct mbn_packet pkt;
while(n_retries--)
{
pkt.flags = htons(F_SEL(0xf) | F_WRITE);
pkt.a_d= htonl(a);
pkt.d=htonl(d);
mbn_send(handle, (uint8_t *)&pkt, sizeof(pkt));
int n = mbn_recv(handle, (uint8_t *)&pkt, sizeof(pkt), RX_TIMEOUT);
pkt.flags = ntohs(pkt.flags);
if(n == sizeof(pkt) && ! (!(pkt.flags && F_READBACK) && !(pkt.flags & F_ERROR)))
{
int i;
fprintf(stderr,"\nBadPacket: ");
for(i=0;i<n; i++) fprintf(stderr,"%02x ", *(uint8_t*) (&pkt + i));
fprintf(stderr,"\n");
} if(n == sizeof(pkt) && !(pkt.flags && F_READBACK) && !(pkt.flags & F_ERROR))
{
int i;
// fprintf(stderr,"GoodFlags: %x\n", pkt.flags);
/*fprintf(stderr,"\nGoodPacket: ");
for(i=0;i<n; i++) fprintf(stderr,"%02x ", *(uint8_t*) (&pkt + i));
fprintf(stderr,"\n");*/
dev->tx_packets++;
return ;
}
dev->tx_retries++;
}
fprintf(stderr, "No ack.\n");
}
uint32_t mbn_readl(void *handle, uint32_t a)
{
int n_retries = 3;
struct mb_device *dev = (struct mb_device *)handle;
struct mbn_packet pkt;
pkt.flags = htons(F_SEL(0xf));
pkt.a_d= htonl(a);
while(n_retries--)
{
mbn_send(handle, (uint8_t *)&pkt, sizeof(pkt));
int n = mbn_recv(handle, (uint8_t *)&pkt, sizeof(pkt), RX_TIMEOUT);
pkt.flags = ntohs(pkt.flags);
if(n == sizeof(pkt) && (pkt.flags & F_READBACK) && !(pkt.flags & F_ERROR))
{
return ntohl(pkt.a_d);
}
dev->tx_retries++;
}
fprintf(stderr, "No ack.\n");
}
void mbn_stats(void *handle)
{
struct mb_device *dev = (struct mb_device *)handle;
fprintf(stderr,"Sent: %d [retries: %d], rcvd: %d [retries: %d]\n", dev->tx_packets, dev->tx_retries, dev->rx_packets, dev->rx_retries);
}
void mbn_close(void *handle)
{
struct mb_device *dev = (struct mb_device *)handle;
ptpd_netif_close_socket(dev->sock);
}
\ No newline at end of file
/* MiniBone library. BUGGY CRAP CODE INTENDED FOR TESTING ONLY! */
#ifndef __MINIBONE_LIB_H
#define __MINIBONE_LIB_H
#include <stdint.h>
void *mbn_open(const char *if_name, uint8_t target_mac[]);
void mbn_writel(void *handle, uint32_t d, uint32_t a);
uint32_t mbn_readl(void *handle, uint32_t a);
void mbn_close(void *handle);
#endif
// Supports only raw ethernet now.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <linux/errqueue.h>
#include <linux/sockios.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#include <fcntl.h>
#include <errno.h>
#include <asm/socket.h>
#include "ptpd_netif.h"
#ifdef NETIF_VERBOSE
#define netif_dbg(...) printf(__VA_ARGS__)
#else
#define netif_dbg(...)
#endif
#define ETHER_MTU 1518
#define DMTD_UPDATE_INTERVAL 100
struct scm_timestamping {
struct timespec systime;
struct timespec hwtimetrans;
struct timespec hwtimeraw;
};
PACKED struct etherpacket {
struct ethhdr ether;
char data[ETHER_MTU];
};
struct tx_timestamp {
int valid;
wr_timestamp_t ts;
uint32_t tag;
uint64_t t_acq;
};
struct my_socket {
int fd;
wr_sockaddr_t bind_addr;
mac_addr_t local_mac;
int if_index;
// parameters for linearization of RX timestamps
uint32_t clock_period;
uint32_t phase_transition;
uint32_t dmtd_phase;
};
struct nasty_hack{
char if_name[20];
int clockedAsPrimary;
};
#ifdef MACIEK_HACKs
struct nasty_hack locking_hack;
#endif
wr_socket_t *ptpd_netif_create_socket(int sock_type, int flags,
wr_sockaddr_t *bind_addr)
{
struct my_socket *s;
struct sockaddr_ll sll;
struct ifreq f;
int fd;
// fprintf(stderr,"CreateSocket!\n");
if(sock_type != PTPD_SOCK_RAW_ETHERNET)
return NULL;
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if(fd < 0)
{
perror("socket()");
return NULL;
}
fcntl(fd, F_SETFL, O_NONBLOCK);
// Put the controller in promiscious mode, so it receives everything
strcpy(f.ifr_name, bind_addr->if_name);
if(ioctl(fd, SIOCGIFFLAGS,&f) < 0) { perror("ioctl()"); return NULL; }
f.ifr_flags |= IFF_PROMISC;
if(ioctl(fd, SIOCSIFFLAGS,&f) < 0) { perror("ioctl()"); return NULL; }
// Find the inteface index
strcpy(f.ifr_name, bind_addr->if_name);
ioctl(fd, SIOCGIFINDEX, &f);
sll.sll_ifindex = f.ifr_ifindex;
sll.sll_family = AF_PACKET;
sll.sll_protocol = htons(bind_addr->ethertype);
sll.sll_halen = 6;
memcpy(sll.sll_addr, bind_addr->mac, 6);
if(bind(fd, (struct sockaddr *)&sll, sizeof(struct sockaddr_ll)) < 0)
{
close(fd);
perror("bind()");
return NULL;
}
s=calloc(sizeof(struct my_socket), 1);
s->if_index = f.ifr_ifindex;
// get interface MAC address
if (ioctl(fd, SIOCGIFHWADDR, &f) < 0) {
perror("ioctl()"); return NULL;
}
memcpy(s->local_mac, f.ifr_hwaddr.sa_data, 6);
memcpy(&s->bind_addr, bind_addr, sizeof(wr_sockaddr_t));
s->fd = fd;
return (wr_socket_t*)s;
}
int ptpd_netif_close_socket(wr_socket_t *sock)
{
struct my_socket *s = (struct my_socket *) sock;
if(!s)
return 0;
close(s->fd);
return 0;
}
int ptpd_netif_sendto(wr_socket_t *sock, wr_sockaddr_t *to, void *data,
size_t data_length, wr_timestamp_t *tx_ts)
{
struct etherpacket pkt;
struct my_socket *s = (struct my_socket *)sock;
struct sockaddr_ll sll;
int rval;
wr_timestamp_t ts;
if(s->bind_addr.family != PTPD_SOCK_RAW_ETHERNET)
return -ENOTSUP;
if(data_length > ETHER_MTU-8) return -EINVAL;
memset(&pkt, 0, sizeof(struct etherpacket));
memcpy(pkt.ether.h_dest, to->mac, 6);
memcpy(pkt.ether.h_source, s->local_mac, 6);
pkt.ether.h_proto =htons(to->ethertype);
memcpy(pkt.data, data, data_length);
size_t len = data_length + sizeof(struct ethhdr);
if(len < 72)
len = 72;
memset(&sll, 0, sizeof(struct sockaddr_ll));
sll.sll_ifindex = s->if_index;
sll.sll_family = AF_PACKET;
sll.sll_protocol = htons(to->ethertype);
sll.sll_halen = 6;
// fprintf(stderr,"fd %d ifi %d ethertype %d\n", s->fd,
// s->if_index, to->ethertype);
rval = sendto(s->fd, &pkt, len, 0, (struct sockaddr *)&sll,
sizeof(struct sockaddr_ll));
return rval;
}
int ptpd_netif_recvfrom(wr_socket_t *sock, wr_sockaddr_t *from, void *data,
size_t data_length, wr_timestamp_t *rx_timestamp)
{
struct my_socket *s = (struct my_socket *)sock;
struct etherpacket pkt;
struct msghdr msg;
struct iovec entry;
struct sockaddr_ll from_addr;
struct {
struct cmsghdr cm;
char control[1024];
} control;
struct cmsghdr *cmsg;
struct scm_timestamping *sts = NULL;
size_t len = data_length + sizeof(struct ethhdr);
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &entry;
msg.msg_iovlen = 1;
entry.iov_base = &pkt;
entry.iov_len = len;
msg.msg_name = (caddr_t)&from_addr;
msg.msg_namelen = sizeof(from_addr);
msg.msg_control = &control;
msg.msg_controllen = sizeof(control);
int ret = recvmsg(s->fd, &msg, MSG_DONTWAIT);
if(ret < 0 && errno==EAGAIN) return 0; // would be blocking
if(ret == -EAGAIN) return 0;
if(ret <= 0) return ret;
memcpy(data, pkt.data, ret - sizeof(struct ethhdr));
from->ethertype = ntohs(pkt.ether.h_proto);
memcpy(from->mac, pkt.ether.h_source, 6);
memcpy(from->mac_dest, pkt.ether.h_dest, 6);
return ret - sizeof(struct ethhdr);
}
// Network API for WR-PTPd
#ifndef __PTPD_NETIF_H
#define __PTPD_NETIF_H
#include <stdio.h>
//#include <inttypes.h>
#define PTPD_SOCK_RAW_ETHERNET 1
#define PTPD_SOCK_UDP 2
#define PTPD_FLAGS_MULTICAST 0x1
// error codes (to be extended)
#define PTPD_NETIF_READY 1
#define PTPD_NETIF_OK 0
#define PTPD_NETIF_ERROR -1
#define PTPD_NETIF_NOT_READY -2
#define PTPD_NETIF_NOT_FOUND -3
// GCC-specific
#define PACKED __attribute__((packed))
#define PHYS_PORT_ANY (0xffff)
#define PTPD_NETIF_TX 1
#define PTPD_NETIF_RX 2
#define IFACE_NAME_LEN 16
#define SLAVE_PRIORITY_0 0
#define SLAVE_PRIORITY_1 1
#define SLAVE_PRIORITY_2 2
#define SLAVE_PRIORITY_3 3
#define SLAVE_PRIORITY_4 4
// Some system-independent definitions
typedef uint8_t mac_addr_t[6];
typedef uint32_t ipv4_addr_t;
// WhiteRabbit socket - it's void pointer as the real socket structure is private and probably platform-specific.
typedef void *wr_socket_t;
// Socket address for ptp_netif_ functions
typedef struct {
// Network interface name (eth0, ...)
char if_name[IFACE_NAME_LEN];
// Socket family (RAW ethernet/UDP)
int family;
// MAC address
mac_addr_t mac;
// Destination MASC address, filled by recvfrom() function on interfaces bound to multiple addresses
mac_addr_t mac_dest;
// IP address
ipv4_addr_t ip;
// UDP port
uint16_t port;
// RAW ethertype
uint16_t ethertype;
// physical port to bind socket to
uint16_t physical_port;
} wr_sockaddr_t;
typedef struct {
uint32_t v[4];
} wr_picoseconds_t;
// Precise WhiteRabbit timestamp
// TS[picoseconds] = utc * 1e12 + nsec * 1e3 + phase;
PACKED struct _wr_timestamp {
// UTC time value (seconds)
int64_t utc;
// Nanoseconds
int32_t nsec;
// Phase (in picoseconds), linearized for receive timestamps, zero for send timestamps
int32_t phase; // phase(picoseconds)
int32_t raw_phase;
int32_t raw_nsec;
int32_t raw_ahead;
//int cntr_ahead;
};
typedef struct _wr_timestamp wr_timestamp_t;
/* OK. These functions we'll develop along with network card driver. You can write your own UDP-based stubs for testing purposes. */
// Initialization of network interface:
// - opens devices
// - does necessary ioctls()
// - initializes connection with the mighty HAL daemon
int ptpd_netif_init();
// Creates UDP or Ethernet RAW socket (determined by sock_type) bound to bind_addr. If PTPD_FLAG_MULTICAST is set, the socket is
// automatically added to multicast group. User can specify physical_port field to bind the socket to specific switch port only.
wr_socket_t *ptpd_netif_create_socket(int sock_type, int flags, wr_sockaddr_t *bind_addr);
// Sends a UDP/RAW packet (data, data_length) to address provided in wr_sockaddr_t.
// For raw frames, mac/ethertype needs to be provided, for UDP - ip/port.
// Every transmitted frame has assigned a tag value, stored at tag parameter. This value is later used
// for recovering the precise transmit timestamp. If user doesn't need it, tag parameter can be left NULL.
int ptpd_netif_sendto(wr_socket_t *sock, wr_sockaddr_t *to, void *data, size_t data_length, wr_timestamp_t *tx_ts);
// Receives an UDP/RAW packet. Data is written to (data) and length is returned. Maximum buffer length can be specified
// by data_length parameter. Sender information is stored in structure specified in 'from'. All RXed packets are timestamped and the timestamp
// is stored in rx_timestamp (unless it's NULL).
int ptpd_netif_recvfrom(wr_socket_t *sock, wr_sockaddr_t *from, void *data, size_t data_length, wr_timestamp_t *rx_timestamp);
// Closes the socket.
int ptpd_netif_close_socket(wr_socket_t *sock);
int ptpd_netif_poll(wr_socket_t*);
int ptpd_netif_get_hw_addr(wr_socket_t *sock, mac_addr_t *mac);
/*
* Function start HW locking of freq on WR Slave
* return:
* PTPD_NETIF_ERROR - locking not started
* PTPD_NETIF_OK - locking started
*/
int ptpd_netif_locking_enable(int txrx, const char *ifaceName, int priority);
/*
*
* return:
*
* PTPD_NETIF_OK - locking started
*/
int ptpd_netif_locking_disable(int txrx, const char *ifaceName, int priority);
int ptpd_netif_locking_poll(int txrx, const char *ifaceName, int priority);
/*
* Function turns on calibration (measurement of delay)
* Tx or Rx depending on the txrx param
* return:
* PTPD_NETIF_NOT_READY - if there is calibratin going on on another port
* PTPD_NETIF_OK - calibration started
*/
int ptpd_netif_calibrating_enable(int txrx, const char *ifaceName);
/*
* Function turns off calibration (measurement of delay)
* Tx or Rx depending on the txrx param
* return:
* PTPD_NETIF_ERROR - if there is calibratin going on on another port
* PTPD_NETIF_OK - calibration started
*/
int ptpd_netif_calibrating_disable(int txrx, const char *ifaceName);
/*
* Function checks if Rx/Tx (depending on the param) calibration is finished
* if finished, returns measured delay in delta
* return:
*
* PTPD_NETIF_OK - locking started
*/
int ptpd_netif_calibrating_poll(int txrx, const char *ifaceName, uint64_t *delta);
/*
* Function turns on calibration pattern.
* return:
* PTPD_NETIF_NOT_READY - if WRSW is busy with calibration on other switch or error occured
* PTPD_NETIF_OK - calibration started
*/
int ptpd_netif_calibration_pattern_enable(const char *ifaceName, unsigned int calibrationPeriod, unsigned int calibrationPattern, unsigned int calibrationPatternLen);
/*
* Function turns off calibration pattern
* return:
* PTPD_NETIF_ERROR - turning off not successful
* PTPD_NETIF_OK - turning off successful
*/
int ptpd_netif_calibration_pattern_disable(const char *ifaceName);
/*
* Function read calibration data if it's available, used at the beginning of PTPWRd to check if
* HW knows already the interface's deltax, and therefore no need for calibration
* return:
* PTPD_NETIF_NOT_FOUND - if deltas are not known
* PTPD_NETIF_OK - if deltas are known, in such case, deltaTx and deltaRx have valid data
*/
int ptpd_netif_read_calibration_data(const char *ifaceName, uint64_t *deltaTx, uint64_t *deltaRx);
#define MACIEK_TMP
#ifdef MACIEK_TMP
int ptpd_netif_select(wr_socket_t*);
int ptpd_netif_get_hw_addr(wr_socket_t *sock, mac_addr_t *mac);
#endif
/*
* Function reads state of the given port (interface in our case), if the port is up, everything is OK, otherwise ERROR
* return:
* PTPD_NETIF_ERROR - if the port is down
* PTPD_NETIF_OK - if the port is up
*/
int ptpd_netif_get_port_state(const char *ifaceName);
/*
* Function looks for a port (interface) for the port number 'number'
* it will return in the argument ifname the port name
* return:
* PTPD_NETIF_ERROR - port not found
* PTPD_NETIF_OK - if the port found
*/
int ptpd_netif_get_ifName(char *ifname, int number);
/* Returns the millisecond "tics" counter value */
uint64_t ptpd_netif_get_msec_tics();
/*
* Function detects external source lock,
*
* return:
* HEXP_EXTSRC_STATUS_LOCKED 0
* HEXP_LOCK_STATUS_BUSY 1
* HEXP_EXTSRC_STATUS_NOSRC 2
*/
int ptpd_netif_extsrc_detection();
#endif
#include <stdio.h>
#include <stdint.h>
#include "fdelay_lib.h"
#include "fdelay_private.h"
#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);
while(ow_readl(R_CSR) & CSR_CYC_MSK);
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;
data = ((port<<CSR_SEL_OFS) & CSR_SEL_MSK) | CSR_CYC_MSK | (bit & CSR_DAT_MSK);
ow_writel(data, R_CSR);
while(ow_readl(R_CSR) & CSR_CYC_MSK);
uint32_t 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;
if(!ow_reset(dev, 0))
return -1;
ow_write_byte(dev, 0, ROM_READ);
for(i=0;i<8;i++)
{
*id = ow_read_byte(dev, 0);
id++;
}
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;
}
int ds18x_read_temp(fdelay_device_t *dev, int *temp_r)
{
int i;
uint8_t data[9];
if(ds18x_access(dev, ds18x_id) < 0)
return -1;
ow_write_byte(dev, 0, READ_SCRATCHPAD);
for(i=0;i<9;i++) data[i] = ow_read_byte(dev, 0);
int temp = ((int)data[1] << 8) | ((int)data[0]);
if(temp & 0x1000)
temp = -0x10000 + temp;
ds18x_access(dev, ds18x_id);
ow_write_byte(dev, 0, CONVERT_TEMP);
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);
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <rawrabbit.h>
#include "rr_io.h"
#define DEVNAME "/dev/rawrabbit"
static int fd;
int rr_bind(int a_fd)
{
fd = a_fd;
return 0;
}
int rr_init(int bus, int devfn)
{
struct rr_devsel devsel;
int ret = -EINVAL;
devsel.bus = bus;
devsel.devfn = devfn;
devsel.subvendor = RR_DEVSEL_UNUSED;
devsel.vendor = 0x10dc;//RR_DEVSEL_UNUSED;
devsel.device = 0x18d; //RR_DEVSEL_UNUSED;
devsel.subdevice = RR_DEVSEL_UNUSED;
fd = open(DEVNAME, O_RDWR);
if (fd < 0) {
return -1;
}
if (ioctl(fd, RR_DEVSEL, &devsel) < 0) {
return -EIO;
}
return 0;
}
int rr_writel(uint32_t data, uint32_t addr)
{
struct rr_iocmd iocmd;
iocmd.datasize = 4;
iocmd.address = addr;
iocmd.address |= __RR_SET_BAR(0);
iocmd.data32 = data;
ioctl(fd, RR_WRITE, &iocmd);
}
uint32_t rr_readl(uint32_t addr)
{
struct rr_iocmd iocmd;
iocmd.datasize = 4;
iocmd.address = addr;
iocmd.address |= __RR_SET_BAR(0);
ioctl(fd, RR_READ, &iocmd);
return iocmd.data32;
}
static void gennum_writel(uint32_t data, uint32_t addr)
{
struct rr_iocmd iocmd;
iocmd.datasize = 4;
iocmd.address = addr;
iocmd.address |= __RR_SET_BAR(4);
iocmd.data32 = data;
ioctl(fd, RR_WRITE, &iocmd);
}
static uint32_t gennum_readl(uint32_t addr)
{
struct rr_iocmd iocmd;
iocmd.datasize = 4;
iocmd.address = addr;
iocmd.address |= __RR_SET_BAR(4);
ioctl(fd, RR_READ, &iocmd);
return iocmd.data32;
}
static inline int64_t get_tics()
{
struct timezone tz= {0,0};
struct timeval tv;
gettimeofday(&tv, &tz);
return (int64_t)tv.tv_sec * 1000000LL + (int64_t) tv.tv_usec;
}
/* These must be set to choose the FPGA configuration mode */
#define GPIO_BOOTSEL0 15
#define GPIO_BOOTSEL1 14
static inline uint8_t reverse_bits8(uint8_t x)
{
x = ((x >> 1) & 0x55) | ((x & 0x55) << 1);
x = ((x >> 2) & 0x33) | ((x & 0x33) << 2);
x = ((x >> 4) & 0x0f) | ((x & 0x0f) << 4);
return x;
}
static uint32_t unaligned_bitswap_le32(const uint32_t *ptr32)
{
static uint32_t tmp32;
static uint8_t *tmp8 = (uint8_t *) &tmp32;
static uint8_t *ptr8;
ptr8 = (uint8_t *) ptr32;
*(tmp8 + 0) = reverse_bits8(*(ptr8 + 0));
*(tmp8 + 1) = reverse_bits8(*(ptr8 + 1));
*(tmp8 + 2) = reverse_bits8(*(ptr8 + 2));
*(tmp8 + 3) = reverse_bits8(*(ptr8 + 3));
return tmp32;
}
static inline void gpio_out(int fd, const uint32_t addr, const int bit, const int value)
{
uint32_t reg;
reg = gennum_readl(addr);
if(value)
reg |= (1<<bit);
else
reg &= ~(1<<bit);
gennum_writel(reg, addr);
}
/*
* Unfortunately, most of the following is from fcl_gn4124.cpp, for which
* the license terms are at best ambiguous.
*/
int loader_low_level(int fd, const void *data, int size8)
{
int size32 = (size8 + 3) >> 2;
const uint32_t *data32 = data;
int ctrl = 0, i, done = 0, wrote = 0;
/* configure Gennum GPIO to select GN4124->FPGA configuration mode */
gpio_out(fd, GNGPIO_DIRECTION_MODE, GPIO_BOOTSEL0, 0);
gpio_out(fd, GNGPIO_DIRECTION_MODE, GPIO_BOOTSEL1, 0);
gpio_out(fd, GNGPIO_OUTPUT_ENABLE, GPIO_BOOTSEL0, 1);
gpio_out(fd, GNGPIO_OUTPUT_ENABLE, GPIO_BOOTSEL1, 1);
gpio_out(fd, GNGPIO_OUTPUT_VALUE, GPIO_BOOTSEL0, 1);
gpio_out(fd, GNGPIO_OUTPUT_VALUE, GPIO_BOOTSEL1, 0);
gennum_writel( 0x00, FCL_CLK_DIV);
gennum_writel( 0x40, FCL_CTRL); /* Reset */
i = gennum_readl( FCL_CTRL);
if (i != 0x40) {
printf("%s: %i: error\n", __func__, __LINE__);
return -EIO;
}
gennum_writel( 0x00, FCL_CTRL);
gennum_writel( 0x00, FCL_IRQ); /* clear pending irq */
switch(size8 & 3) {
case 3: ctrl = 0x116; break;
case 2: ctrl = 0x126; break;
case 1: ctrl = 0x136; break;
case 0: ctrl = 0x106; break;
}
gennum_writel( ctrl, FCL_CTRL);
gennum_writel( 0x00, FCL_CLK_DIV); /* again? maybe 1 or 2? */
gennum_writel( 0x00, FCL_TIMER_CTRL); /* "disable FCL timr fun" */
gennum_writel( 0x10, FCL_TIMER_0); /* "pulse width" */
gennum_writel( 0x00, FCL_TIMER_1);
/*
* Set delay before data and clock is applied by FCL
* after SPRI_STATUS is detected being assert.
*/
gennum_writel( 0x08, FCL_TIMER2_0); /* "delay before data/clk" */
gennum_writel( 0x00, FCL_TIMER2_1);
gennum_writel( 0x17, FCL_EN); /* "output enable" */
ctrl |= 0x01; /* "start FSM configuration" */
gennum_writel( ctrl, FCL_CTRL);
while(size32 > 0)
{
/* Check to see if FPGA configuation has error */
i = gennum_readl( FCL_IRQ);
if ( (i & 8) && wrote) {
done = 1;
printf("%s: %i: done after %i\n", __func__, __LINE__,
wrote);
} else if ( (i & 0x4) && !done) {
printf("%s: %i: error after %i\n", __func__, __LINE__,
wrote);
return -EIO;
}
/* Wait until at least 1/2 of the fifo is empty */
while (gennum_readl( FCL_IRQ) & (1<<5))
;
/* Write a few dwords into FIFO at a time. */
for (i = 0; size32 && i < 32; i++) {
gennum_writel( unaligned_bitswap_le32(data32),
FCL_FIFO);
data32++; size32--; wrote++;
}
}
gennum_writel( 0x186, FCL_CTRL); /* "last data written" */
/* Checking for the "interrupt" condition is left to the caller */
return wrote;
}
int rr_load_bitstream_from_file(const char *file_name)
{
uint8_t *buf;
FILE *f;
uint32_t size;
f=fopen(file_name,"rb");
if(!f) return -1;
fseek(f, 0, SEEK_END);
size = ftell(f);
buf = malloc(size);
if(!buf)
{
fclose(f);
return -1;
}
fseek(f, 0, SEEK_SET);
fread(buf, 1, size, f);
fclose(f);
int rval = loader_low_level(0, buf, size);
free(buf);
return rval;
}
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "fdelay_lib.h"
#include "rr_io.h"
void spec_writel(void *priv, uint32_t data, uint32_t addr)
{
rr_writel(data, addr);
}
uint32_t spec_readl(void *priv, uint32_t addr)
{
uint32_t d = rr_readl(addr);
return d;
}
int spec_fdelay_init(int argc, char *argv[], fdelay_device_t *dev)
{
int bus = RR_DEVSEL_UNUSED, devfn = RR_DEVSEL_UNUSED;
int opt = 0;
char fw_name[1024];
strcpy(fw_name, "spec_top.bin");
while ((opt = getopt(argc, argv, "hb:d:f:")) != -1) {
switch (opt) {
case 'h':
printf("Usage: %s [-b PCI_bus] [-d PCI dev/func] [-f firmware file]\n", argv[0]);
printf("By default, the first detected SPEC is initialized with 'spec_top.bin' firmware\n");
return 0;
case 'b':
sscanf(optarg, "%x", &bus);
break;
case 'd':
sscanf(optarg, "%x", &devfn);
break;
case 'f':
strcpy(fw_name, optarg);
break;
}
}
if(rr_init(bus, devfn) < 0)
{
fprintf(stderr, "Failed to initialize rawrabbit.\n");
return -1;
}
dev->writel = spec_writel;
dev->readl = spec_readl;
dev->base_addr = 0x84000;
if(rr_load_bitstream_from_file(fw_name) < 0)
{
fprintf(stderr,"Failed to load FPGA bitstream.\n");
return -1;
}
if(fdelay_init(dev) < 0)
return -1;
return 0;
}
#include <stdio.h>
#include "board.h"
#include "hw/softpll_regs.h"
#include "irq.h"
static volatile struct SPLL_WB *SPLL = (volatile struct SPLL_WB *) BASE_SOFTPLL;
/* The includes below contain code (not only declarations) to enable the compiler
to inline functions where necessary and save some CPU cycles */
#include "spll_defs.h"
#include "spll_common.h"
#include "spll_helper.h"
volatile int irq_count = 0,eee,yyy;
struct spll_helper_state helper;
void _irq_entry()
{
volatile uint32_t trr;
int src = -1, tag;
if(! (SPLL->CSR & SPLL_TRR_CSR_EMPTY))
{
trr = SPLL->TRR_R0;
src = SPLL_TRR_R0_CHAN_ID_R(trr);
tag = SPLL_TRR_R0_VALUE_R(trr);
eee = tag;
}
helper_update(&helper, tag, src);
yyy=helper.phase.pi.y;
irq_count++;
clear_irq();
}
void spll_init()
{
volatile int dummy;
disable_irq();
SPLL->CSR= 0 ;
SPLL->OCER = 0;
SPLL->RCER = 0;
SPLL->DEGLITCH_THR = 2000;
while(! (SPLL->TRR_CSR & SPLL_TRR_CSR_EMPTY)) dummy = SPLL->TRR_R0;
dummy = SPLL->PER_HPLL;
SPLL->EIC_IER = 1;
}
void spll_test()
{
int i = 0;
volatile int dummy;
spll_init();
helper_start(&helper, 6);
enable_irq();
for(;;)
{
mprintf("cnt %d serr %d src %d y %d d %d\n", irq_count, eee, serr, yyy, delta);
}
}
\ No newline at end of file
/*
White Rabbit Softcore PLL (SoftPLL) - common definitions
*/
/* PI regulator state */
typedef struct {
int ki, kp; /* integral and proportional gains (1<<PI_FRACBITS == 1.0f) */
int integrator; /* current integrator value */
int bias; /* DC offset always added to the output */
int anti_windup; /* when non-zero, anti-windup is enabled */
int y_min; /* min/max output range, used by claming and antiwindup algorithms */
int y_max;
int x,y; /* Current input and output value */
} spll_pi_t;
/* Processes a single sample (x) using PI controller (pi). Returns the value (y) which should
be used to drive the actuator. */
static inline int pi_update(spll_pi_t *pi, int x)
{
int i_new, y;
pi->x = x;
i_new = pi->integrator + x;
y = ((i_new * pi->ki + x * pi->kp) >> PI_FRACBITS) + pi->bias;
/* clamping (output has to be in <y_min, y_max>) and anti-windup:
stop the integretor if the output is already out of range and the output
is going further away from y_min/y_max. */
if(y < pi->y_min)
{
y = pi->y_min;
if((pi->anti_windup && (i_new > pi->integrator)) || !pi->anti_windup)
pi->integrator = i_new;
} else if (y > pi->y_max) {
y = pi->y_max;
if((pi->anti_windup && (i_new < pi->integrator)) || !pi->anti_windup)
pi->integrator = i_new;
} else
pi->integrator = i_new;
pi->y = y;
return y;
}
/* initializes the PI controller state. Currently almost a stub. */
static inline void pi_init(spll_pi_t *pi)
{
pi->integrator = 0;
}
/* lock detector state */
typedef struct {
int lock_cnt;
int lock_samples;
int delock_samples;
int threshold;
int locked;
} spll_lock_det_t;
/* Lock detector state machine. Takes an error sample (y) and checks if it's withing an acceptable range
(i.e. <-ld.threshold, ld.threshold>. If it has been inside the range for (ld.lock_samples) cyckes, the
FSM assumes the PLL is locked. */
static inline int ld_update(spll_lock_det_t *ld, int y)
{
if (abs(y) <= ld->threshold)
{
if(ld->lock_cnt < ld->lock_samples)
ld->lock_cnt++;
if(ld->lock_cnt == ld->lock_samples)
ld->locked = 1;
} else {
if(ld->lock_cnt > ld->delock_samples)
ld->lock_cnt--;
if(ld->lock_cnt == ld->delock_samples)
{
ld->lock_cnt= 0;
ld->locked = 0;
}
}
return ld->locked;
}
static void ld_init(spll_lock_det_t *ld)
{
ld->locked = 0;
ld->lock_cnt = 0;
}
/*
White Rabbit Softcore PLL (SoftPLL) - common definitions
*/
#include <stdio.h>
/* Reference clock frequency */
#define CLOCK_FREQ 125000000
/* Bit size of phase tags generated by the DMTDs. Used to sign-extend the tags. */
#define TAG_BITS 20
/* Helper PLL N divider (1/2**N is the frequency offset) */
#define HPLL_N 14
/* Fractional bits in PI controller coefficients */
#define PI_FRACBITS 12
/* State of the Helper PLL producing a clock (clk_dmtd_i) which is
slightly offset in frequency from the recovered/reference clock (clk_rx_i or clk_ref_i), so the
Main PLL can use it to perform linear phase measurements. This structure keeps the state of the pre-locking
stage */
struct spll_helper_prelock_state {
spll_pi_t pi;
spll_lock_det_t ld;
int f_setpoint;
int ref_select;
fdelay_device_t *dev;
};
volatile int serr;
void helper_prelock_init(struct spll_helper_prelock_state *s)
{
/* Frequency branch PI controller */
s->pi.y_min = 5;
s->pi.y_max = 65530;
s->pi.anti_windup = 0;
s->pi.kp = 28*32*16;
s->pi.ki = 50*32*16;
s->pi.bias = 32000;
/* Freqency branch lock detection */
s->ld.threshold = 2;
s->ld.lock_samples = 1000;
s->ld.delock_samples = 990;
s->f_setpoint = 131072 / (1<<HPLL_N);
pi_init(&s->pi);
ld_init(&s->ld);
}
void helper_prelock_enable(struct spll_helper_prelock_state *state, int ref_channel, int enable)
{
fdelay_device_t *dev = state->dev;
fd_decl_private(dev);
fd_writel(0, FD_REG_SPLLR);
}
#define SPLL_LOCKED 1
#define SPLL_LOCKING 0
int helper_prelock_update(struct spll_helper_prelock_state *s, int tag)
{
fdelay_device_t *dev = s->dev;
fd_decl_private(dev);
int y;
volatile uint32_t per = fd_readl(FD_REG_SPLLR);
short err = (short) (tag & 0xffff);
serr = (int)err;
err -= s->f_setpoint;
y = pi_update(&s->pi, err);
fd_writel(y, FD_REG_SDACR);
if(ld_update(&s->ld, err))
return SPLL_LOCKED;
return SPLL_LOCKING;
}
struct spll_helper_phase_state {
spll_pi_t pi;
spll_lock_det_t ld;
int p_setpoint, tag_d0;
int ref_src;
fdelay_device_t *dev;
};
void helper_phase_init(struct spll_helper_phase_state *s)
{
/* Phase branch PI controller */
s->pi.y_min = 5;
s->pi.y_max = 65530;
s->pi.kp = (int)(2.0 * 32.0 * 16.0);
s->pi.ki = (int)(0.05 * 32.0 * 3.0);
s->pi.anti_windup = 0;
s->pi.bias = 32000;
/* Phase branch lock detection */
s->ld.threshold = 500;
s->ld.lock_samples = 10000;
s->ld.delock_samples = 9900;
s->ref_src = 6;
s->p_setpoint = -1;
pi_init(&s->pi);
ld_init(&s->ld);
}
void helper_phase_enable(struct spll_helper_phase_state *state, int ref_channel, int enable)
{
fdelay_device_t *dev = state->dev;
fd_decl_private(dev);
fd_writel(FD_SPLLR_MODE, FD_REG_SPLLR);
}
volatile int delta;
int helper_phase_update(struct spll_helper_phase_state *s, int tag, int source)
{
fdelay_device_t *dev = s->dev;
fd_decl_private(dev);
int err, y;
serr = source;
// if(source == s->ref_src)
{
if(s->p_setpoint < 0)
{
s->p_setpoint = tag;
return;
}
err = tag - s->p_setpoint;
delta = tag - s->tag_d0;
s->tag_d0 = tag;
s->p_setpoint += (1<<HPLL_N);
if(s->p_setpoint > (1<<TAG_BITS))
s->p_setpoint -= (1<<TAG_BITS);
y = pi_update(&s->pi, err);
//printf("t %d sp %d\n", tag, s->p_setpoint);
fd_writel(y, FD_REG_SDACR);
if(ld_update(&s->ld, err))
{
return SPLL_LOCKED;
};
}
return SPLL_LOCKING;
}
#define HELPER_PRELOCKING 1
#define HELPER_PHASE 2
#define HELPER_LOCKED 3
struct spll_helper_state {
struct spll_helper_prelock_state prelock;
struct spll_helper_phase_state phase;
int state;
int ref_channel;
};
void helper_start(fdelay_device_t *dev, struct spll_helper_state *s)
{
s->state = HELPER_PRELOCKING;
s->ref_channel = 0;
s->prelock.dev = dev;
s->phase.dev = dev;
helper_prelock_init(&s->prelock);
helper_phase_init(&s->phase);
helper_prelock_enable(&s->prelock, 0, 1);
}
void helper_update(struct spll_helper_state *s)
{
fdelay_device_t *dev = s->prelock.dev;
fd_decl_private(dev);
uint32_t spllr = fd_readl(FD_REG_SPLLR);
if(! (spllr & FD_SPLLR_TAG_RDY))
return;
int tag = FD_SPLLR_TAG_R(spllr);
switch(s->state)
{
case HELPER_PRELOCKING:
if(helper_prelock_update(&s->prelock, tag) == SPLL_LOCKED)
{
s->state = HELPER_PHASE;
helper_prelock_enable(&s->prelock, 0, 0);
s->phase.pi.bias = s->prelock.pi.y;
helper_phase_enable(&s->phase, 0, 1);
}
break;
case HELPER_PHASE:
helper_phase_update(&s->phase, tag, 0);
break;
}
}
#!/usr/bin/python
import sys
import PyQt4
import PyQt4.QtGui
import PyQt4.QtCore
import PyQt4.uic
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from fdelay_lib import FineDelay
FormClass = PyQt4.uic.loadUiType('fd_demo.ui')[0]
class MainWindow(QMainWindow, FormClass):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
# self.setWindowTitle("ion")
def channel_update(channel):
print("UpdateCh: %d" % channel)
en = ch_enable[channel-1].checkState();
dly = int(ch_nsec[channel-1].value() * 1000 + (ch_sec[channel-1].value() * 1000000000000))
w = int(ch_width[channel-1].value() * 1000)
card.conf_output(channel, en, dly, w)
def trigger_update():
card.conf_trigger(m.en_trigger.checkState(), m.en_term.checkState())
def on_ts_enable_disable():
print("ontsen")
card.conf_readout(m.en_ts.checkState())
prev_ts = 0
def on_ts_clear():
print("ontabclear")
poll_timer.stop()
for i in range(0, m.ts_table.rowCount()):
m.ts_table.removeRow(i)
prev_ts = 0
poll_timer.start()
def poll_timer_cb():
buf = card.read_ts()
for ts in buf:
global prev_ts
row = m.ts_table.rowCount()
m.ts_table.insertRow(row)
m.ts_table.setItem(row, 0, QTableWidgetItem("%d"%ts.seq_id))
m.ts_table.setItem(row, 1, QTableWidgetItem("%d"%ts.utc))
m.ts_table.setItem(row, 2, QTableWidgetItem("%.3f"%ts.nsecs()))
m.ts_table.setItem(row, 3, QTableWidgetItem("%.3f"%(ts.nsecs_full()-prev_ts)))
prev_ts = ts.nsecs_full()
# i = QTableWidgetItem()
m.ts_table.scrollToBottom()
m.wr_status.setText(card.get_sync_status())
def on_chk_wr():
if(m.wr_checkbox.checkState()):
card.conf_sync(card.SYNC_WR)
else:
card.conf_sync(card.SYNC_LOCAL)
if __name__ == "__main__":
app = QApplication(sys.argv)
location = "local/0x84000"
m = MainWindow()
m.show()
m.setWindowTitle("Fine Delay Demo @ %s" % location)
card = FineDelay(location)
m.wr_status.setText("")
ch_enable = [m.en_ch1, m.en_ch2, m.en_ch3, m.en_ch4];
ch_nsec = [m.nsec_ch1, m.nsec_ch2, m.nsec_ch3, m.nsec_ch4];
ch_sec = [m.sec_ch1, m.sec_ch2, m.sec_ch3, m.sec_ch4];
ch_width = [m.width_ch1, m.width_ch2, m.width_ch3, m.width_ch4];
for i in range(1,5):
channel_update(i)
ch_enable[0].stateChanged.connect(lambda :channel_update(1))
ch_enable[1].stateChanged.connect(lambda :channel_update(2))
ch_enable[2].stateChanged.connect(lambda :channel_update(3))
ch_enable[3].stateChanged.connect(lambda :channel_update(4))
ch_nsec[0].valueChanged.connect(lambda :channel_update(1))
ch_nsec[1].valueChanged.connect(lambda :channel_update(2))
ch_nsec[2].valueChanged.connect(lambda :channel_update(3))
ch_nsec[3].valueChanged.connect(lambda :channel_update(4))
ch_sec[0].valueChanged.connect(lambda :channel_update(1))
ch_sec[1].valueChanged.connect(lambda :channel_update(2))
ch_sec[2].valueChanged.connect(lambda :channel_update(3))
ch_sec[3].valueChanged.connect(lambda :channel_update(4))
ch_width[0].valueChanged.connect(lambda :channel_update(1))
ch_width[1].valueChanged.connect(lambda :channel_update(2))
ch_width[2].valueChanged.connect(lambda :channel_update(3))
ch_width[3].valueChanged.connect(lambda :channel_update(4))
m.en_trigger.stateChanged.connect(lambda :trigger_update())
m.en_term.stateChanged.connect(lambda :trigger_update())
m.en_ts.stateChanged.connect(on_ts_enable_disable)
m.wr_checkbox.stateChanged.connect(on_chk_wr)
m.btn_clear.clicked.connect(on_ts_clear)
trigger_update();
on_ts_enable_disable()
m.ts_table.clearContents()
# m.ts_table
poll_timer = QTimer()
poll_timer.setInterval(200)
poll_timer.timeout.connect(poll_timer_cb)
poll_timer.start()
app.exec_()
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MyDialog</class>
<widget class="QDialog" name="MyDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>649</width>
<height>352</height>
</rect>
</property>
<property name="windowTitle">
<string>Fine Delay Demo</string>
</property>
<widget class="QTabWidget" name="tabWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>631</width>
<height>331</height>
</rect>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_delay">
<attribute name="title">
<string>Delay</string>
</attribute>
<widget class="QGroupBox" name="groupBox">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>591</width>
<height>161</height>
</rect>
</property>
<property name="title">
<string>Outputs</string>
</property>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>470</x>
<y>10</y>
<width>91</width>
<height>16</height>
</rect>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Pulse width</string>
</property>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>30</y>
<width>581</width>
<height>128</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>OUT1:</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="en_ch1">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="sec_ch1">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>s</string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>120.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="nsec_ch1">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>ns</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>500.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="width_ch1">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>ns</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>200.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>200.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>OUT2:</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="en_ch2">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="sec_ch2">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>s</string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>120.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="nsec_ch2">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>ns</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>500.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="width_ch2">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>ns</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>200.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>200.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_5">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>OUT3:</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="en_ch3">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="sec_ch3">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>s</string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>120.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="nsec_ch3">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>ns</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>500.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>500.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="width_ch3">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>ns</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>200.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>200.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_6">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>OUT4:</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="en_ch4">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="sec_ch4">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>s</string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>120.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="nsec_ch4">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>ns</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>500.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="width_ch4">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>ns</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>200.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>200.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>260</x>
<y>10</y>
<width>91</width>
<height>16</height>
</rect>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Delay setting</string>
</property>
</widget>
</widget>
<widget class="QGroupBox" name="groupBox_2">
<property name="geometry">
<rect>
<x>10</x>
<y>180</y>
<width>481</width>
<height>51</height>
</rect>
</property>
<property name="title">
<string>Trigger</string>
</property>
<widget class="QCheckBox" name="en_trigger">
<property name="geometry">
<rect>
<x>20</x>
<y>20</y>
<width>111</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>Enabled</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
<widget class="QCheckBox" name="en_term">
<property name="geometry">
<rect>
<x>160</x>
<y>20</y>
<width>191</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>50 Ohm termination</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</widget>
<widget class="QGroupBox" name="groupBox_3">
<property name="geometry">
<rect>
<x>10</x>
<y>240</y>
<width>481</width>
<height>51</height>
</rect>
</property>
<property name="title">
<string>Sync Status</string>
</property>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>381</width>
<height>31</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="wr_checkbox">
<property name="text">
<string>Use White Rabbit</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_13">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>WR Status:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="wr_status">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>STATUS</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
<widget class="QWidget" name="tab_ts">
<attribute name="title">
<string>Timestamper</string>
</attribute>
<widget class="QCheckBox" name="en_ts">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>231</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>Enable timestamping</string>
</property>
</widget>
<widget class="QPushButton" name="btn_clear">
<property name="geometry">
<rect>
<x>520</x>
<y>10</y>
<width>80</width>
<height>24</height>
</rect>
</property>
<property name="text">
<string>Clear</string>
</property>
</widget>
<widget class="QTableWidget" name="ts_table">
<property name="geometry">
<rect>
<x>10</x>
<y>40</y>
<width>611</width>
<height>251</height>
</rect>
</property>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>150</number>
</attribute>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>150</number>
</attribute>
<column>
<property name="text">
<string>ID</string>
</property>
</column>
<column>
<property name="text">
<string>Seconds</string>
</property>
</column>
<column>
<property name="text">
<string>Nanoseconds</string>
</property>
</column>
<column>
<property name="text">
<string>Delta</string>
</property>
</column>
</widget>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>
#!/usr/bin/python
from ctypes import *
import sys
import re
import os
sys.path.append('../../../common/')
from ptsexcept import *
class fd_timestamp(Structure):
_fields_ = [("utc", c_ulonglong),
("coarse", c_ulong),
("frac", c_ulong),
("seq_id", c_ushort),
("channel", c_int)]
def nsecs(self):
return (float(self.frac) * 8000.0 / 4096.0 + float(self.coarse) * 8000.0) / 1000.0;
def nsecs_full(self):
return (float(self.frac) * 8000.0 / 4096.0 + float(self.coarse) * 8000.0) / 1000.0 + float(self.utc) * 1000000000.0;
def __str__(self):
return "%d:%d" % (self.utc, self.nsecs())
class FineDelay:
GNUM_CSR_ADDR = 0x0
BASE_ADDR = 0x84000
FREE_RUNNING = 0x10
WR_OFFLINE = 0x8
WR_READY = 0x1
WR_SYNCING = 0x2
WR_SYNCED = 0x4
SYNC_LOCAL = 0x1
SYNC_WR = 0x2
def __init__(self, fd):
cwd = os.path.dirname(__file__)
self.fdelay = CDLL(cwd+'/../lib/libfinedelay.so')
self.handle = c_voidp(self.fdelay.fdelay_create_rawrabbit(c_int(fd), c_ulong(self.BASE_ADDR)));
"""
s = re.split("\/", dev_path)
self.fdelay = CDLL('../lib/libfinedelay.so')
if(s[0] == "local"):
print("Initializing local at %x" % int(s[1], 16))
self.handle = c_voidp(self.fdelay.fdelay_create_rawrabbit(int(s[1],16)));
elif(s[0] == "minibone"):
print("Initializing minibone at %s [%s]\n" %( s[1], s[2]))
self.handle = c_voidp(self.fdelay.fdelay_create_minibone(c_char_p(s[1]), c_char_p(s[2]), int(s[3], 16)));
"""
print "Initialising Fine Delay board..."
print self.handle
if(self.fdelay.fdelay_init(self.handle) < 0):
print ("Init failed..");
# sys.exit(-1)
def conf_trigger(self, enable, termination):
self.fdelay.fdelay_configure_trigger(self.handle, c_int(enable), c_int(termination))
def conf_output(self, channel, enable, delay, width):
self.fdelay.fdelay_configure_output(self.handle, c_int(channel), c_int(enable), c_ulonglong(delay), c_ulonglong(width))
def conf_readout(self, enable):
self.fdelay.fdelay_configure_readout(self.handle, enable)
def conf_sync(self, mode):
self.fdelay.fdelay_configure_sync(self.handle, mode)
def conf_pulsegen(self, channel, enable, t_start_utc, t_start_coarse, width, delta, count):
t = fd_timestamp(utc=c_ulonglong(t_start_utc), coarse=c_ulong(t_start_coarse))
#print "channel:%d enable:%d start_t:%d width:%d delta:%d count:%d"%(channel, enable, t.utc, width, delta, count)
self.fdelay.fdelay_configure_pulse_gen(self.handle, c_int(channel), c_int(enable), t,
c_ulonglong(width), c_ulonglong(delta), c_int(count))
def set_time(self, utc, coarse):
t = fd_timestamp(utc=c_ulonglong(utc), coarse=c_ulong(coarse))
self.fdelay.fdelay_set_time(self.handle, t)
def get_time(self):
t = fd_timestamp()
self.fdelay.fdelay_get_time(self.handle, byref(t))
return t
def get_sync_status(self):
htab = { self.FREE_RUNNING : "oscillator free-running",
self.WR_OFFLINE : "WR core offline",
self.WR_READY : "WR core ready",
self.WR_SYNCING : "Syncing local clock with WR",
self.WR_SYNCED : "Synced with WR" }
# status = c_int(self.fdelay.fdelay_get_sync_status(self.handle));
# print("GetSyncStatus %x" % status.value);
return "none"; #htab[status.value]
def read_ts(self):
buf = (fd_timestamp * 256)();
ptr = pointer(buf)
n = self.fdelay.fdelay_read(self.handle, ptr, 256)
arr = [];
for i in range(0,n):
arr.append(buf[i])
return arr
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