Scope
FPGADigitalDemultiplexer.cpp
1 #include "StdAfx.h"
2 #include "FPGADigitalDemultiplexer.h"
3 #include "parameters/IO.h"
4 #include "helpers/DaqChunk.h"
5 
6 namespace scope {
7 
9  : FPGAIO6587(NiFpga_DigitalDemultiplexerV3_IndicatorBool_Onboard_Clock_Ready
10  , NiFpga_DigitalDemultiplexerV3_ControlU16_Onboard_Clock_Write_Data
11  , NiFpga_DigitalDemultiplexerV3_ControlBool_Onboard_Clock_Write
12  , NiFpga_DigitalDemultiplexerV3_IndicatorBool_Xpoint_Switch_Ready
13  , NiFpga_DigitalDemultiplexerV3_ControlU8_ClockSource
14  , NiFpga_DigitalDemultiplexerV3_ControlBool_Xpoint_Switch_Write
15  , NiFpga_DigitalDemultiplexerV3_ControlBool_Commit
16  , NiFpga_DigitalDemultiplexerV3_ControlBool_Acq_Reset)
17  , samplingrate(1E9) {
18  assert(SCOPE_NAREAS <= 2);
19  status = NiFpga_Initialize();
20 
21  char* const Bitfile = "devices\\fpga\\" NiFpga_DigitalDemultiplexerV3_Bitfile;
22 
23  // Load but do not run yet
24  status = NiFpga_Open(Bitfile, NiFpga_DigitalDemultiplexerV3_Signature, "RIO0", 0, &session);
25  DBOUT(L"FPGADemultiplexer: FPGA Session opened\n");
26 
27  // Reset the non-running FPGA to clear any bad stuff (e.g. after a program crash with open FPGA before)
28  status = NiFpga_Reset(session);
29 
30  // YOU HAVE TO WAIT THAT LONG!!!
31  // Otherwise you will occasionally (!!!) into strange problems (communication with fpga error -61046)
32  // This took me very very long to figure out...
33  std::this_thread::sleep_for(std::chrono::milliseconds(500));
34  // Run after reset
35  status = NiFpga_Run(session, 0);
36 
38 
39  fifos[0] = NiFpga_DigitalDemultiplexerV3_TargetToHostFifoU16_ToHostArea1Ch1FIFO;
40  fifos[1] = NiFpga_DigitalDemultiplexerV3_TargetToHostFifoU16_ToHostArea1Ch2FIFO;
41  fifos[2] = NiFpga_DigitalDemultiplexerV3_TargetToHostFifoU16_ToHostArea2Ch1FIFO;
42  fifos[3] = NiFpga_DigitalDemultiplexerV3_TargetToHostFifoU16_ToHostArea2Ch2FIFO;
43  reqpixels[0] = NiFpga_DigitalDemultiplexerV3_ControlU32_RequestedpixelsA1;
44  reqpixels[1] = NiFpga_DigitalDemultiplexerV3_ControlU32_RequestedpixelsA2;
45  smplsperpixel[0] = NiFpga_DigitalDemultiplexerV3_ControlU16_SamplesperpixelA1;
46  smplsperpixel[1] = NiFpga_DigitalDemultiplexerV3_ControlU16_SamplesperpixelA2;
47  smplsperpixelacq[0] = NiFpga_DigitalDemultiplexerV3_ControlU16_SamplesperpixelAcqA1;
48  smplsperpixelacq[1] = NiFpga_DigitalDemultiplexerV3_ControlU16_SamplesperpixelAcqA2;
49 }
50 
52  status = NiFpga_Close(session, 0);
53  status = NiFpga_Finalize();
54  DBOUT(L"FPGADemultiplexer::~FPGADemultiplexer session closed");
55 }
56 
58  if ( !initialized ) {
59  parameters = dynamic_cast<parameters::InputsFPGADigitalDemultiplexer*>(_parameters);
60 
61  assert( (parameters->samplingrate() > 100E6) && (parameters->samplingrate() < 1.6E9));
62 
64  // Clock frequency is 0.5x sampling rate, due to double data rate
66  // YOU HAVE TO WAIT THAT LONG!!!
67  // Otherwise you will occasionally (!!!) into strange problems (communication with fpga error -61046)
68  // This took me very very long to figure out...
69  std::this_thread::sleep_for(std::chrono::milliseconds(500));
71 
73 
74  // Set counting mode
75  status = NiFpga_WriteBool(session, NiFpga_DigitalDemultiplexerV3_ControlBool_Countmode, parameters->countmode());
76 
77  FPGAInterface::Initialize(_parameters);
78  }
79 }
80 
81 double FPGADigitalDemultiplexer::SetPixeltime(const uint32_t& _area, const double& _pixeltime) {
82  // sampling rate is twice the IO modules frequency (because of dual data rate transfer)
83  uint16_t clockcycles = round2ui16(_pixeltime * 1E-6 * samplingrate);
84  DBOUT(L"FPGADemultiplexer::SetPixeltime Clockcycles per pixel" << clockcycles);
85  // Since the Demultiplexer VI is working on arrays of 60 samples clockcycles has to be a multiple of 60
86  if ( clockcycles%60 != 0 ) {
87  clockcycles -= (clockcycles%60);
88  DBOUT(L"FPGADemultiplexer::SetPixeltime Coerced clockcycles per pixel" << clockcycles);
89  }
90  status = NiFpga_WriteU16(session, smplsperpixel[_area], clockcycles);
91  status = NiFpga_WriteU16(session, smplsperpixelacq[_area], clockcycles);
92  pixeltimes[_area] = static_cast<double>(clockcycles)*1E6/samplingrate;
93  return pixeltimes[_area];
94 }
95 
96 double FPGADigitalDemultiplexer::SetLinetime(const uint32_t& _area, const double& _linetime) {
97  // Not supported by FPGA VI
98  return _linetime;
99 }
100 
101 void FPGADigitalDemultiplexer::SetTriggering(const bool& _waitfortrigger) {
102  status = NiFpga_WriteBool(session, NiFpga_DigitalDemultiplexerV3_ControlBool_Waitfortrigger, _waitfortrigger);
103 }
104 
106  status = NiFpga_WriteBool(session, NiFpga_DigitalDemultiplexerV3_ControlBool_Acquirecontinuously, _cont);
107 }
108 
109 void FPGADigitalDemultiplexer::SetRequestedPixels(const uint32_t& _area, const uint32_t& _reqpixels) {
110  status = NiFpga_WriteU32(session, reqpixels[_area], _reqpixels);
111 }
112 
114  NiFpga_Bool alreadyrunning = false;
115  status = NiFpga_ReadBool(session, NiFpga_DigitalDemultiplexerV3_ControlBool_Acquire, &alreadyrunning);
116  if ( !alreadyrunning ) {
117  ClearFIFOs(); // Only clear them if not alreay running (e.g. by a previous StartAcquisition from another area!!) Leads to nasty bugs!
118  status = NiFpga_WriteBool(session, NiFpga_DigitalDemultiplexerV3_ControlBool_Acquire, true);
119  }
120 }
121 
123  DBOUT(L"FPGADigitalDemultiplexer::StopAcquisition");
124  status = NiFpga_WriteBool(session, NiFpga_DigitalDemultiplexerV3_ControlBool_Acquire, false);
125 }
126 
128  status = NiFpga_WriteBool(session, NiFpga_DigitalDemultiplexerV3_ControlBool_Acq_Reset, false);
129  status = NiFpga_WriteBool(session, NiFpga_DigitalDemultiplexerV3_ControlBool_Acq_Reset, true);
130  std::this_thread::sleep_for(std::chrono::milliseconds(200));
131  status = NiFpga_WriteBool(session, NiFpga_DigitalDemultiplexerV3_ControlBool_Acq_Reset, false);
132 }
133 
134 int32_t FPGADigitalDemultiplexer::ReadPixels(DaqChunk& _chunk, const double& _timeout, bool& _timedout) {
135  size_t remaining = 0;
136 
137  // only two channels and two areas supported in FPGA vi
138  assert( (_chunk.NChannels() == 2) && (_chunk.Area() <= 1) );
139 
140  // we need enough space
141  assert(_chunk.data.size() >= _chunk.PerChannel() * _chunk.NChannels());
142 
143  NiFpga_Status stat = NiFpga_Status_Success;
144 
145  for ( uint32_t c = 0 ; c < _chunk.NChannels() ; c++ ) {
146  stat = NiFpga_ReadFifoU16(session
147  , fifos[_chunk.Area() * 2+c] // select correct fifo
148  , &_chunk.data[c*_chunk.PerChannel()] // offset start in vector for second channel pixels
149  , _chunk.PerChannel()
150  , static_cast<uint32_t>(_timeout * 1000) // FPGA C API takes timeout in milliseconds, to be consistent with DAQmx we have _timeout in seconds
151  , &remaining);
152  _timedout = (stat == NiFpga_Status_FifoTimeout);
153 
154  // avoid throwing exception on time out (since FpgaStatus status could throw on all errors)
155  if ( _timedout )
156  return -1;
157  status = stat;
158  }
159 
160  if ( status.Success() )
161  return _chunk.PerChannel();
162  return -1;
163 }
164 
166  NiFpga_Bool b(0);
167  uint16_t ui = 0;
168  status = NiFpga_ReadBool(session, NiFpga_DigitalDemultiplexerV3_IndicatorBool_ToHostFIFOOverflowA1Ch1, &b);
169  parameters->diagnosis.ToHostOverflowA1Ch1 = (b!=0);
170  status = NiFpga_ReadBool(session, NiFpga_DigitalDemultiplexerV3_IndicatorBool_ToHostFIFOOverflowA1Ch2, &b);
171  parameters->diagnosis.ToHostOverflowA1Ch2 = (b!=0);
172  status = NiFpga_ReadBool(session, NiFpga_DigitalDemultiplexerV3_IndicatorBool_ToHostFIFOOverflowA2Ch1, &b);
173  parameters->diagnosis.ToHostOverflowA2Ch1 = (b!=0);
174  status = NiFpga_ReadBool(session, NiFpga_DigitalDemultiplexerV3_IndicatorBool_ToHostFIFOOverflowA2Ch2, &b);
175  parameters->diagnosis.ToHostOverflowA2Ch2 = (b!=0);
176  status = NiFpga_ReadBool(session, NiFpga_DigitalDemultiplexerV3_IndicatorBool_InterloopFIFOoverflow, &b);
177  parameters->diagnosis.InterloopOverflow = (b!=0);
178  status = NiFpga_ReadBool(session, NiFpga_DigitalDemultiplexerV3_IndicatorBool_InterloopFIFOtimeout, &b);
179  parameters->diagnosis.InterloopTimeout = (b!=0);
180  status = NiFpga_ReadU16(session, NiFpga_DigitalDemultiplexerV3_IndicatorU16_LaserpulsesperpixelA1, &ui);
181  DBOUT(L"Laserpulsecount " << ui);
182  parameters->diagnosis.MeasuredLaserFreq = static_cast<double>(ui) / (pixeltimes[0] * 1E-6);
183  status = NiFpga_ReadBool(session, NiFpga_DigitalDemultiplexerV3_IndicatorBool_Acquiring, &b);
184  parameters->diagnosis.Acquiring = (b!=0);
185 }
186 
188  status = NiFpga_WriteBool(session, NiFpga_DigitalDemultiplexerV3_ControlBool_ClearInterloopFIFO, 1);
189  std::this_thread::sleep_for(std::chrono::milliseconds(50));
190  status = NiFpga_WriteBool(session, NiFpga_DigitalDemultiplexerV3_ControlBool_ClearInterloopFIFO, 0);
191 
192  // Stop FIFOs (clears them)
193  for ( auto f : fifos )
194  status = NiFpga_StopFifo(session, f);
195  std::this_thread::sleep_for(std::chrono::milliseconds(50));
196 
197  // Restart FIFOs
198  for ( auto f : fifos )
199  status = NiFpga_StartFifo(session, f);
200  std::this_thread::sleep_for(std::chrono::milliseconds(50));
201 }
202 
203 void FPGADigitalDemultiplexer::SetCountMode(const bool& _mode) {
204  status = NiFpga_WriteBool(session, NiFpga_DigitalDemultiplexerV3_ControlBool_Countmode, _mode);
205 }
206 
207 }
void StartAcquisition() override
Starts the acquisition on the FPGA.
ScopeNumber< double > samplingrate
Sampling rate of the IO modules clock (which is double the clock rate of the FPGA acquisition loop) i...
Definition: IO.h:184
void WriteOnboardClockFrequency(NiFpga_Session _session, const double &_clock_freq)
Writes the program for the Si570 clock chip to the device.
Definition: FPGAIO6587.cpp:67
void SetRequestedPixels(const uint32_t &_area, const uint32_t &_reqpixels) override
Sets the number of pixels per channel the FPGA should acquire, set to -1 for live scanning...
parameters::InputsFPGADigitalDemultiplexer * parameters
the parameter set
std::array< double, 2 > pixeltimes
Pixel dwell time in microseconds.
Parameters for pixel acquisition with FPGADigitalDemultiplexer.
Definition: IO.h:196
FPGADigitalDemultiplexer()
Load the FPGA bitfile, set the IO module's onboard clock, initialize the acquisition.
std::array< NiFpga_DigitalDemultiplexerV3_ControlU32, 2 > reqpixels
requested pixels for both areas
Handels the NI FlexRIO adapter module IO-6587.
Definition: FPGAIO6587.h:11
std::array< NiFpga_DigitalDemultiplexerV3_ControlU16, 2 > smplsperpixel
samples per pixel for both areas
double SetPixeltime(const uint32_t &_area, const double &_pixeltime) override
Sets the time per pixel/dwell time (in seconds)
bool CheckIOModule(NiFpga_Session _session)
Necessary calls at the moment not supported by NI FPGA API 12.0, see CheckIOModule.vi for what to do.
Definition: FPGAIO6587.cpp:27
double SetLinetime(const uint32_t &_area, const double &_linetime) override
Sets the time per line (in seconds) for the generation of the line clock (if implemented) ...
void ResetAcquisition()
Resets the acquisition.
void CheckFPGADiagnosis()
Checks the status of the FIFOs on the FPGA.
ScopeNumber< double > MeasuredLaserFreq
Measured laser frequency, calculated from counted laserpulses per pixel.
Definition: IO.h:223
void Initialize(parameters::InputsFPGA *_parameters) override
Set initial parameters.
std::vector< uint16_t > data
The data vector.
Definition: DaqChunk.h:26
void InitializeAcquisition(NiFpga_Session _session)
Commits the clock frequency and clock source writings and resets the IO module acquisition circuit...
Definition: FPGAIO6587.cpp:116
A DaqChunk contains data from all channels sequentially.
Definition: DaqChunk.h:9
This is the include file for standard system include files, or project specific include files that ar...
bool initialized
true if already initialized
Definition: FPGAInterface.h:29
void SetContinuousAcquisition(const bool &_cont) override
Sets if the FPGA should acquire data continuously or acquire the number of pixels per channel set wit...
FPGAStatusSafe status
current FPGA status.
Definition: FPGAInterface.h:23
std::array< NiFpga_DigitalDemultiplexerV3_TargetToHostFifoU16, 4 > fifos
all FIFOs for both areas both channels
void SetCountMode(const bool &_mode)
Set the counting mode on the FPGA.
#define DBOUT(s)
A debug output to the debug console.
Definition: helpers.h:153
ScopeNumber< bool > Acquiring
and the Acquiring indicator
Definition: IO.h:221
void StopAcquisition() override
Stops the acquisition on the FPGA.
bool Success() const
Diagnosis diagnosis
Keeps the LEDs/ScopeNumber for FPGA diagnosis together.
Definition: IO.h:238
int32_t ReadPixels(DaqChunk &_chunk, const double &_timeout, bool &_timedout) override
Read only pixels from the FPGA FIFO.
void SetClockSource(NiFpga_Session _session, const uint8_t &_clock_source=3)
Possible clock sources (see SetClockSource.vi from NI examples) .
Definition: FPGAIO6587.cpp:93
ScopeNumber< bool > countmode
Type of photon counting.
Definition: IO.h:207
virtual void Initialize(parameters::InputsFPGA *_parameters)
Set initial parameters.
Definition: FPGAInterface.h:38
std::array< NiFpga_DigitalDemultiplexerV3_ControlU16, 2 > smplsperpixelacq
samples per pixel for both areas, for the acquisition loop
void ClearFIFOs()
Clears the interloop and ToHost FIFOs.
Parameters for pixel acquisition with NI-FPGA.
Definition: IO.h:117
NiFpga_Session session
NI FPGA session handle.
Definition: FPGAInterface.h:26
void SetTriggering(const bool &_waitfortrigger) override
Sets if the FPGA should wait for a trigger before starting acquisition.
double samplingrate
programmed sampling rate (usually 1-1.4GHz), this is double the IO modules clock rate ...