Skip to content
Snippets Groups Projects
Commit 43b162fb authored by Rolf Bork's avatar Rolf Bork
Browse files

RT code modified to properly support system that uses a 1PPS

signal on last channel of first ADC for time synchonization.
parent 0d91a937
No related branches found
No related tags found
No related merge requests found
......@@ -100,8 +100,6 @@ fe_start_controller( void* arg )
static int cpuClock[ CPU_TIMER_CNT ]; /// @param cpuClock[] Code timing
/// diag variables
int sync21ppsCycles =
0; /// @param sync32ppsCycles Number of attempts to sync to 1PPS
volatile RFM_FE_COMMS* pEpicsComms; /// @param *pEpicsComms Pointer to EPICS
/// shared memory space
int status; /// @param status Typical function return value
......@@ -122,7 +120,6 @@ fe_start_controller( void* arg )
int diagWord =
0; /// @param diagWord Code diagnostic bit pattern returned to EPICS
int system = 0;
int sync21pps = 0; /// @param sync21pps Code startup sync to 1PPS flag
int syncSource =
SYNC_SRC_NONE; /// @param syncSource Code startup synchronization source
int mxStat = 0; /// @param mxStat Net diags when myrinet express is used
......@@ -141,9 +138,11 @@ fe_start_controller( void* arg )
double adcval[ MAX_ADC_MODULES ][ MAX_ADC_CHN_PER_MOD ];
adcInfo_t* padcinfo;
int expect_delays = 0;
#ifdef DIAG_TEST
int delay_cycles = 0;
int delay_cycles = 0;
#ifdef NO_DAC_PRELOAD
int dac_preload = 0;
#else
int dac_preload = 1;
#endif
/// **********************************************************************************************\n
......@@ -353,6 +352,10 @@ fe_start_controller( void* arg )
/// \> Find the code syncrhonization source. \n
/// - Standard aLIGO Sync source is the Timing Distribution System (TDS)
/// (SYNC_SRC_TDS).
#ifdef ONE_PPS_TEST
// Only used to test 1pps synch on test system
syncSource = SYNC_SRC_1PPS;
#endif
switch ( syncSource )
{
/// \>\> For SYNC_SRC_TDS, initialize system for synchronous start on 1PPS
......@@ -375,8 +378,6 @@ fe_start_controller( void* arg )
gsc18ao8Enable( &cdsPciModules );
gsc20ao8Enable( &cdsPciModules );
gsc16ao16Enable( &cdsPciModules );
// Set synched flag so later code will not check for 1PPS
sync21pps = 1;
udelay( MAX_UDELAY );
udelay( MAX_UDELAY );
/// - ---- Preload DAC FIFOS\n
......@@ -385,14 +386,12 @@ fe_start_controller( void* arg )
/// \n
/// - --------- DAC timing diags will later check FIFO sizes to verify
/// synchrounous timing.
#ifndef NO_DAC_PRELOAD
status = iop_dac_preload( dacPtr );
#endif
if(dac_preload)
status = iop_dac_preload( dacPtr );
/// - ---- Start the timing clocks\n
/// - --------- Send start command to TDS receiver.\n
/// - --------- TDS receiver will begin sending 64KHz clocks synchronous to
/// next 1PPS mark.
// CDIO1616Output[tdsControl] = 0x7B00000;
for ( ii = 0; ii < tdsCount; ii++ )
{
// CDIO1616Output[ii] = TDS_START_ADC_NEG_DAC_POS;
......@@ -403,37 +402,61 @@ fe_start_controller( void* arg )
}
break;
case SYNC_SRC_1PPS:
#ifndef NO_DAC_PRELOAD
gsc16ai64Enable( &cdsPciModules );
status = iop_dac_preload( dacPtr );
#ifdef ONE_PPS_TEST
// Need to start clocks if testing on a system that has TDS receiver
for ( ii = 0; ii < tdsCount; ii++ )
{
// CDIO1616Output[ii] = TDS_START_ADC_NEG_DAC_POS;
CDIO1616Output[ ii ] =
TDS_START_ADC_NEG_DAC_POS | TDS_NO_DAC_DUOTONE;
CDIO1616Input[ ii ] = contec1616WriteOutputRegister(
&cdsPciModules, tdsControl[ ii ], CDIO1616Output[ ii ] );
}
#endif
if(dac_preload)
status = iop_dac_preload( dacPtr );
// Arm ADC modules
// This has to be done sequentially, one at a time.
status = sync_adc_2_1pps( );
// Return status will be 1 if sync signal found
if(status == 1) {
pLocalEpics->epicsOutput.timeErr = syncSource;
} else {
pLocalEpics->epicsOutput.timeErr = SYNC_SRC_NONE;
dac_preload = 0;
}
// Enable all DAC cards
gsc18ao8Enable( &cdsPciModules );
gsc20ao8Enable( &cdsPciModules );
gsc16ao16Enable( &cdsPciModules );
break;
case SYNC_SRC_NONE:
// Enable all available ADC/DAC modules
gsc16ai64Enable( &cdsPciModules );
gsc18ai32Enable( &cdsPciModules );
sync21pps = 1;
gsc18ao8Enable( &cdsPciModules );
gsc20ao8Enable( &cdsPciModules );
gsc16ao16Enable( &cdsPciModules );
dac_preload = 0;
break;
case SYNC_SRC_DOLPHIN:
sync21pps = 1;
break;
case SYNC_SRC_TIMER:
sync21pps = 1;
break;
default:
{
// IRIG-B card not found, so use CPU time to get close to 1PPS on
// startup Pause until this second ends
dac_preload = 0;
// Enable all available ADC modules
gsc16ai64Enable( &cdsPciModules );
gsc18ai32Enable( &cdsPciModules );
sync21pps = 1;
// Enable all available DAC modules
gsc18ao8Enable( &cdsPciModules );
gsc20ao8Enable( &cdsPciModules );
gsc16ao16Enable( &cdsPciModules );
break;
}
}
// for(jj=0;jj<cdsPciModules.adcCount;jj++) gsc18ai32DmaEnable(jj);
pLocalEpics->epicsOutput.fe_status = NORMAL_RUN;
onePpsTime = cycleNum;
......@@ -441,12 +464,10 @@ fe_start_controller( void* arg )
timeSec = remote_time( (struct CDS_EPICS*)pLocalEpics );
#elif USE_DOLPHIN_TIMING
timeSec = sync2master( pcieTimer );
sync21pps = 1;
#elif RUN_WO_IO_MODULES
// printk("Sync to cpu\n");
timeSec = sync2cpuclock( );
// printk("Sync to cpu %old\n",timeSec);
sync21pps = 1;
#else
timeSec = current_time_fe( ) - 1;
if ( cdsPciModules.gpsType == TSYNC_RCVR )
......@@ -536,37 +557,6 @@ fe_start_controller( void* arg )
}
}
#endif
// Try synching to 1PPS on ADC[0][31] if not using TDS
// Only try for 1 sec.
if ( !sync21pps )
{
// 1PPS signal should rise above 4000 ADC counts if present.
if ( ( adcinfo.adcData[ 0 ][ 31 ] < ONE_PPS_THRESH ) &&
( sync21ppsCycles < ( CYCLE_PER_SECOND * OVERSAMPLE_TIMES ) ) )
{
ll = -1;
sync21ppsCycles++;
}
else
{
// Need to start clocking the DAC outputs.
gsc18ao8Enable( &cdsPciModules );
gsc16ao16Enable( &cdsPciModules );
sync21pps = 1;
// 1PPS never found, so indicate NO SYNC to user
if ( sync21ppsCycles >=
( CYCLE_PER_SECOND * OVERSAMPLE_TIMES ) )
{
syncSource = SYNC_SRC_NONE;
}
else
{
// 1PPS found and synched to
syncSource = SYNC_SRC_1PPS;
}
pLocalEpics->epicsOutput.timeErr = syncSource;
}
}
// In normal operation, the following for loop runs only once per IOP
// code cycle. This for loop runs > once per cycle if ADC is clocking
......@@ -663,7 +653,8 @@ fe_start_controller( void* arg )
/// \> Cycle 1 and Spectricom IRIGB (standard), get IRIG-B time
/// information.
// *****************************************************************
if ( cycleNum == HKP_READ_TSYNC_IRIBB )
// if ( cycleNum == HKP_READ_TSYNC_IRIBB )
if ( cycleNum == HKP_READ_TSYNC_IRIBB && syncSource == SYNC_SRC_TDS)
{
if ( cdsPciModules.gpsType == TSYNC_RCVR )
{
......@@ -705,8 +696,7 @@ fe_start_controller( void* arg )
duotime( DT_SAMPLE_CNT, dt_diag.meanAdc, dt_diag.adc );
pLocalEpics->epicsOutput.dtTime = duotoneTime;
if ( ( ( duotoneTime < MIN_DT_DIAG_VAL ) ||
( duotoneTime > MAX_DT_DIAG_VAL ) ) &&
syncSource != SYNC_SRC_1PPS )
( duotoneTime > MAX_DT_DIAG_VAL ) ) )
feStatus |= FE_ERROR_TIMING;
duotoneTimeDac =
duotime( DT_SAMPLE_CNT, dt_diag.meanDac, dt_diag.dac );
......@@ -1102,16 +1092,16 @@ fe_start_controller( void* arg )
/// code.
// This code runs once per second.
// *****************************************************************
#ifndef NO_DAC_PRELOAD
if ( cycleNum >= HKP_DAC_FIFO_CHK &&
cycleNum < ( HKP_DAC_FIFO_CHK + cdsPciModules.dacCount ) )
{
if(!expect_delays) status = check_dac_buffers( cycleNum );
if(dac_preload) {
if ( cycleNum >= HKP_DAC_FIFO_CHK &&
cycleNum < ( HKP_DAC_FIFO_CHK + cdsPciModules.dacCount ) )
{
if(!expect_delays) status = check_dac_buffers( cycleNum );
}
if ( dacTimingError )
feStatus |= FE_ERROR_DAC;
}
if ( dacTimingError )
feStatus |= FE_ERROR_DAC;
#endif
// *****************************************************************
// Update end of cycle information
......
......@@ -204,7 +204,7 @@ rt_fe_cleanup( void )
// printk("Setting stop_working_threads to 1\n");
// Stop the code and wait
#ifdef NO_CPU_SHUTDOWN
int ret;
// int ret;
ret = kthread_stop( sthread );
#endif
stop_working_threads = 1;
......
......@@ -145,14 +145,15 @@ gsc16ai64CheckDmaDone( int module )
int
gsc16ai64WaitDmaDone( int module, volatile int* data )
{
int ii = 0;
do
{
} while ( ( adcDma[ module ]->DMA_CSR & GSAI_DMA_DONE ) == 0 );
ii ++;
udelay(1);
} while ( ( adcDma[ module ]->DMA_CSR & GSAI_DMA_DONE == 0 ) && (ii < 10000) );
// First channel should be marked with an upper bit set
if ( *data == 0 )
return 0;
else
return 16;
if(ii > 9999) return 44444;
else return *data;
}
// *****************************************************************************
......
......@@ -2,6 +2,7 @@ inline int iop_adc_init( adcInfo_t* );
inline int iop_adc_read( adcInfo_t*, int[] );
inline int sync_adc_2_1pps( void );
// Routine for initializing ADC modules on startup
inline int
iop_adc_init( adcInfo_t* adcinfo )
{
......@@ -40,7 +41,7 @@ iop_adc_init( adcInfo_t* adcinfo )
// Set ADC Present Flag
pLocalEpics->epicsOutput.statAdc[ jj ] = ADC_MAPPED;
// Set ADC AutoCal Pass/Fail Flag
if((cdsPciModules.adcConfig [ jj ] & GSAI_AUTO_CAL_PASS) != 0)
if ( ( cdsPciModules.adcConfig[ jj ] & GSAI_AUTO_CAL_PASS ) != 0 )
pLocalEpics->epicsOutput.statAdc[ jj ] |= ADC_CAL_PASS;
// Reset Diag Info
adcinfo->adcRdTimeErr[ jj ] = 0;
......@@ -61,6 +62,8 @@ iop_adc_init( adcInfo_t* adcinfo )
return 0;
}
// Routine to startup and synchronize ADC modules when 1PPS
// signal is used for synch.
inline int
sync_adc_2_1pps( )
{
......@@ -72,37 +75,57 @@ sync_adc_2_1pps( )
kk = 0;
for ( jj = 0; jj < cdsPciModules.adcCount; jj++ )
{
adcDummyData = (int*)cdsPciModules.pci_adc[ 0 ];
adcDummyData += 31;
adcDummyData = (int*)cdsPciModules.pci_adc[ jj ];
adcDummyData += ADC_DUOTONE_CHAN;
// Enable next ADC card
gsc16ai64Enable1PPS( jj );
status = gsc16ai64WaitDmaDone( 0, adcDummyData );
// Wait for ADC read to complete
status = gsc16ai64WaitDmaDone( jj, adcDummyData );
// if(status == 44444) return -1;
kk++;
udelay( 2 );
// Rearm ADC boards that had been previously enables
for ( ii = 0; ii < kk; ii++ )
{
gsc16ai64DmaEnable( ii );
}
}
// Need to do some dummy reads here to allow time for last ADC to arm
// as it takes two clock cycles past arm to actually deliver data.
for ( ii = 0; ii < cdsPciModules.adcCount; ii++ )
// Look for 1PPS signal for 1+ seconds
for ( jj = 0; jj < 75009; jj++ )
{
// Want to verify ADC FIFOs are empty to ensure they are in sync.
status = gsc16ai64WaitDmaDone( 0, adcDummyData );
status = gsc16ai64CheckAdcBuffer( ii );
for ( jj = 0; jj < cdsPciModules.adcCount; jj++ )
// Wait until all ADC reads are complete
for ( ii = 0; ii < cdsPciModules.adcCount; ii++ )
{
adcDummyData = (int*)cdsPciModules.pci_adc[ ii ];
adcDummyData += 31;
// Want to verify ADC FIFOs are empty to ensure they are in sync.
status = gsc16ai64WaitDmaDone( ii, adcDummyData );
status = gsc16ai64CheckAdcBuffer( ii );
}
adcDummyData = (int*)cdsPciModules.pci_adc[ ADC_DUOTONE_BRD ];
adcDummyData += ADC_DUOTONE_CHAN;
// Check value of 1PPS channel
if ( *adcDummyData > ONE_PPS_THRESH )
{
gsc16ai64DmaEnable( jj );
// Found 1PPS sync signal
return 1;
}
// Rearm ADC boards
for ( ii = 0; ii < cdsPciModules.adcCount; ii++ )
gsc16ai64DmaEnable( ii );
}
// Did not find 1PPS signal
return 0;
}
// ADC Read *****************************************************************
// Routine for reading data from ADC modules.
inline int
iop_adc_read( adcInfo_t* adcinfo, int cpuClk[] )
{
int ii,kk;
int ii, kk;
volatile int* packedData;
int limit;
int mask;
......@@ -169,6 +192,7 @@ iop_adc_read( adcInfo_t* adcinfo, int cpuClk[] )
// Indicate short cycle during recovery from long cycle
adcStat = -1;
#ifdef XMIT_DOLPHIN_TIME
// Send time on Dolphin net if this is the time xmitter.
pcieTimer->gps_time = timeSec;
pcieTimer->cycle = cycleNum;
clflush_cache_range( (void*)&pcieTimer->gps_time, 16 );
......@@ -196,7 +220,6 @@ iop_adc_read( adcInfo_t* adcinfo, int cpuClk[] )
/// is overflowing.
if ( adcinfo->adcWait >= MAX_ADC_WAIT )
{
// printk("timeout %d %d \n",jj,adcinfo->adcWait);
pLocalEpics->epicsOutput.stateWord = FE_ERROR_ADC;
pLocalEpics->epicsOutput.diagWord |= ADC_TIMEOUT_ERR;
pLocalEpics->epicsOutput.fe_status = ADC_TO_ERROR;
......@@ -205,7 +228,6 @@ iop_adc_read( adcInfo_t* adcinfo, int cpuClk[] )
stop_working_threads = 1;
vmeDone = 1;
continue;
// return 0;
}
if ( card == 0 )
......@@ -236,7 +258,6 @@ iop_adc_read( adcInfo_t* adcinfo, int cpuClk[] )
/// - ---- First, and only first, channel should have upper bit marker
/// set. If not, have a channel hopping error.
if ( (unsigned int)*packedData < 65535 )
// if(!((unsigned int)*packedData & ADC_1ST_CHAN_MARKER))
{
adcinfo->chanHop = 1;
fe_status_return_subcode = card;
......@@ -248,7 +269,7 @@ iop_adc_read( adcInfo_t* adcinfo, int cpuClk[] )
mask = GSAI_DATA_MASK;
num_outs = cdsPciModules.adcChannels[ card ];
loops = UNDERSAMPLE;
if ( cdsPciModules.adcType[ card ] == GSC_16AI64SSA && UNDERSAMPLE > 4)
if ( cdsPciModules.adcType[ card ] == GSC_16AI64SSA && UNDERSAMPLE > 4 )
loops = 1;
/// - ---- Determine next ipc memory location to load ADC data
ioMemCntr = ( ( cycleNum / ADC_MEMCPY_RATE ) % IO_MEMORY_SLOTS );
......@@ -263,6 +284,8 @@ iop_adc_read( adcInfo_t* adcinfo, int cpuClk[] )
adcinfo->adcData[ card ][ chan ] = ( *packedData & mask );
adcinfo->adcData[ card ][ chan ] -= offset;
#ifdef DEC_TEST
// This only used on test system for checking decimation filters
// by providing an ADC signal via a GDS EXC signal
if ( chan == 0 )
{
adcinfo->adcData[ card ][ chan ] =
......@@ -278,7 +301,7 @@ iop_adc_read( adcInfo_t* adcinfo, int cpuClk[] )
UNDERSAMPLE > 4 )
{
for ( ii = 1; ii < UNDERSAMPLE; ii++ )
dWord[ card ][ chan ][ ii ] =
dWord[ card ][ chan ][ ii ] =
adcinfo->adcData[ card ][ chan ];
}
/// - ---- Load ADC value into ipc memory buffer
......@@ -301,8 +324,8 @@ iop_adc_read( adcInfo_t* adcinfo, int cpuClk[] )
// normal 64K adc
if ( UNDERSAMPLE < 5 )
{
/// - ---- Write GPS time and cycle count as indicator to control app
/// that adc data is ready
/// - ---- Write GPS time and cycle count as indicator to
/// control app that adc data is ready
ioMemData->gpsSecond = timeSec;
ioMemData->iodata[ card ][ ioMemCntr ].timeSec = timeSec;
ioMemData->iodata[ card ][ ioMemCntr ].cycle = iocycle;
......@@ -310,15 +333,14 @@ iop_adc_read( adcInfo_t* adcinfo, int cpuClk[] )
iocycle++;
iocycle %= IOP_IO_RATE;
}
}
// For ADC undersampling when running with a fast ADC at 512K
// to limit rate to user apps at 64K
if ( UNDERSAMPLE > 4 )
{
/// - ---- Write GPS time and cycle count as indicator to control app that
/// adc data is ready
/// - ---- Write GPS time and cycle count as indicator to control
/// app that adc data is ready
ioMemData->gpsSecond = timeSec;
ioMemData->iodata[ card ][ ioMemCntr ].timeSec = timeSec;
ioMemData->iodata[ card ][ ioMemCntr ].cycle = iocycle;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment