Scope
FPGAResonanceScanner_NI5771.cpp
1 #include "StdAfx.h"
2 #include "FPGAResonanceScanner_NI5771.h"
3 #include "parameters/IO.h"
4 #include "helpers/DaqChunk.h"
5 #include "helpers/DaqChunkResonance.h"
6 
7 namespace scope {
8 
10  : FPGAIO5771(NiFpga_AnalogIntegrator_NI5771_Resonance_IndicatorBool_UserCommandIdle
11  , NiFpga_AnalogIntegrator_NI5771_Resonance_IndicatorBool_PLLLocked
12  , NiFpga_AnalogIntegrator_NI5771_Resonance_IndicatorBool_Configured
13  , NiFpga_AnalogIntegrator_NI5771_Resonance_IndicatorBool_UserError
14  , NiFpga_AnalogIntegrator_NI5771_Resonance_IndicatorU8_UserCommandStatus
15  , NiFpga_AnalogIntegrator_NI5771_Resonance_ControlU8_UserCommand
16  , NiFpga_AnalogIntegrator_NI5771_Resonance_ControlU16_UserData0
17  , NiFpga_AnalogIntegrator_NI5771_Resonance_ControlU8_UserData1
18  , NiFpga_AnalogIntegrator_NI5771_Resonance_ControlBool_UserCommandCommit) {
19  assert(SCOPE_NAREAS == 1);
20 
21  status = NiFpga_Initialize();
22 
23  char* const Bitfile = "devices\\fpga\\" NiFpga_AnalogIntegrator_NI5771_Resonance_Bitfile;
24 
25  // Load but do not run yet
26  status = NiFpga_Open(Bitfile, NiFpga_AnalogIntegrator_NI5771_Resonance_Signature, "RIO0", 0, &session);
27  DBOUT(L"FPGAResonanceScannerNI5771: FPGA Session opened");
28 
29  // Reset the non-running FPGA to clear any bad stuff (e.g. after a program crash with open FPGA before)
30  status = NiFpga_Reset(session);
31 
32  // YOU HAVE TO WAIT THAT LONG!!!
33  // Otherwise you will occasionally (!!!) into strange problems (communication with fpga error -61046)
34  // This took me very very long to figure out...
35  std::this_thread::sleep_for(std::chrono::milliseconds(500));
36  // Run after reset
37  status = NiFpga_Run(session, 0);
38 
40 
41  // Set the fifo constants
42  fifos[0] = NiFpga_AnalogIntegrator_NI5771_Resonance_TargetToHostFifoU32_ToHostCh1FIFO;
43  fifos[1] = NiFpga_AnalogIntegrator_NI5771_Resonance_TargetToHostFifoU32_ToHostCh2FIFO;
44 }
45 
47  status = NiFpga_Close(session, 0);
48  status = NiFpga_Finalize();
49  DBOUT(L"FPGAResonanceScannerNI5771::~FPGAResonanceScannerNI5771 session closed");
50 }
51 
53  if ( !initialized ) {
54  parameters = dynamic_cast<parameters::InputsFPGAAnalogIntegrator*>(_parameters);
55 
57 
58  uint32_t chunksize = 1000000;
59 
60  status = NiFpga_ConfigureFifo(session, fifos[0], 5*chunksize);
61  status = NiFpga_ConfigureFifo(session, fifos[1], 5*chunksize);
62 
63  FPGAInterface::Initialize(_parameters);
64  }
65 }
66 
67 double FPGAResonanceScannerNI5771::SetPixeltime(const uint32_t& _area, const double& _pixeltime) {
68  // sampling rate of the NI 5771 is 1.5GHz
69  uint16_t samplesperpixel = round2ui16(_pixeltime * 1E-6 * 1.5E9);
70  status = NiFpga_WriteU16(session, NiFpga_AnalogIntegrator_NI5771_Resonance_ControlU32_Samplesperpixel, samplesperpixel);
71 
72  DBOUT(L"FPGAResonanceScannerNI5771::SetPixeltime samples per pixel" << samplesperpixel);
73  // Since the AnalogIntegrator VI is working on arrays of 8 samples clockcycles has to be a multiple of 8
74  if ( samplesperpixel%8 != 0 ) {
75  samplesperpixel -= (samplesperpixel%8);
76  DBOUT(L"FPGAResonanceScannerNI5771::SetPixeltime Coerced samples per per pixel" << samplesperpixel);
77  }
78 
79  return static_cast<double>(samplesperpixel)*1E6/1.5E9;
80 }
81 
82 double FPGAResonanceScannerNI5771::SetLinetime(const uint32_t& _area, const double& _linetime) {
83  // sampling rate of the NI 5771 is 1.5GHz
84  uint16_t samplesperline = round2ui32(_linetime * 1E-6 * 1.5E9);
85  status = NiFpga_WriteU16(session, NiFpga_AnalogIntegrator_NI5771_Resonance_ControlU32_Samplesperline, samplesperline);
86 
87  DBOUT(L"FPGAResonanceScannerNI5771::SetPixeltime samples per line" << samplesperline);
88  // Since the AnalogIntegrator VI is working on arrays of 8 samples clockcycles has to be a multiple of 8
89  if ( samplesperline%8 != 0 ) {
90  samplesperline -= (samplesperline%8);
91  DBOUT(L"FPGAResonanceScannerNI5771::SetPixeltime Coerced samples per per pixel" << samplesperline);
92  }
93 
94  return static_cast<double>(samplesperline)*1E6/1.5E9;
95 }
96 
97 void FPGAResonanceScannerNI5771::SetTriggering(const bool& _waitfortrigger) {
98  status = NiFpga_WriteBool(session, NiFpga_AnalogIntegrator_NI5771_Resonance_ControlBool_Waitfortrigger, _waitfortrigger);
99 }
100 
102  status = NiFpga_WriteBool(session, NiFpga_AnalogIntegrator_NI5771_Resonance_ControlBool_Acquirecontinuously, _cont);
103 }
104 
105 void FPGAResonanceScannerNI5771::SetRequestedPixels(const uint32_t& _area, const uint32_t& _reqpixels) {
106  status = NiFpga_WriteU32(session, NiFpga_AnalogIntegrator_NI5771_Resonance_ControlU32_Requestedpixels, _reqpixels);
107 }
108 
110  ClearFIFOs();
111  SetChannelProps();
112  status = NiFpga_WriteBool(session, NiFpga_AnalogIntegrator_NI5771_Resonance_ControlBool_Acquire, true);
113 }
114 
115 int32_t FPGAResonanceScannerNI5771::ReadPixels(DaqChunk& _chunk, const double& _timeout, bool& _timedout) {
116  size_t remaining = 0;
117 
118  // only two channels supported in FPGA vi
119  assert(_chunk.NChannels() <= 2 );
120 
121  // should be always true (because it is handled inside DaqChunk), but better to check anyway...
122  assert(_chunk.data.size() >= _chunk.PerChannel() * _chunk.NChannels());
123 
124  NiFpga_Status stat = NiFpga_Status_Success;
125 
126  std::vector<uint32_t> u32data(_chunk.PerChannel());
127  std::vector<int32_t> bitshift(_chunk.NChannels());
128  bitshift[0] = parameters->BitshiftCh1();
129  bitshift[1] = parameters->BitshiftCh2();
130 
131  // Read each channels fifo
132  for ( uint32_t c = 0 ; c < _chunk.NChannels() ; c++ ) {
133  stat = NiFpga_ReadFifoU32(session
134  , fifos[c]
135  , u32data.data()
136  , _chunk.PerChannel()
137  , static_cast<uint32_t>(_timeout * 1000) // FPGA C API takes timeout in milliseconds, to be consistent with DAQmx we have _timeout in seconds
138  , &remaining);
139 
140  _timedout = (stat == NiFpga_Status_FifoTimeout);
141 
142  // avoid throwing exception on time out (since FpgaStatus status could throw on all errors)
143  // return immediately, makes no sense to also wait for the other channels, since anyway something went seriously wrong
144  if ( _timedout )
145  return -1;
146 
147  // this could throw on error (if we would use FPGAStatus instead of FPGAStatusSafe)
148  status = stat;
149 
150  // isolate pixel uint16 from uint32
151  auto itdata = std::begin(_chunk.data) + c * _chunk.PerChannel();
152  for(auto u32 : u32data) {
153  *itdata = u32 & 0x0000ffff;
154  itdata++;
155  }
156  }
157 
158  // Now we need to upcast
159  DaqChunkResonance& _chunkres = dynamic_cast<DaqChunkResonance&>(_chunk);
160 
161  // isolate sync bool from uint32
162  auto itsync = std::begin(_chunkres.resSync);
163  for(auto u32 : u32data) {
164  *itsync = ((u32 >> 31) != 0);
165  itsync++;
166  }
167 
168  if ( status.Success() )
169  return _chunk.PerChannel();
170 
171  return -1;
172 }
173 
175  status = NiFpga_WriteBool(session, NiFpga_AnalogIntegrator_NI5771_Resonance_ControlBool_Acquire, false);
176 }
177 
179  // We want to right-shift bits thus *-1
180  //status = NiFpga_WriteI8(session, NiFpga_AnalogIntegrator_NI5771_Resonance_ControlI8_BitshiftCh1, -1 * parameters->BitshiftCh1());
181  //status = NiFpga_WriteI8(session, NiFpga_AnalogIntegrator_NI5771_Resonance_ControlI8_BitshiftCh2, -1 * parameters->BitshiftCh2());
182  // We subtract baseline from cumulated 8 samples, thus 8*
183  status = NiFpga_WriteU8(session, NiFpga_AnalogIntegrator_NI5771_Resonance_ControlU8_Baselinex8Ch1, parameters->BaselineCh1());
184  status = NiFpga_WriteU8(session, NiFpga_AnalogIntegrator_NI5771_Resonance_ControlU8_Baselinex8Ch2, parameters->BaselineCh2());
185 
186  DBOUT(L"FPGAResonanceScannerNI5771::SetChannelProps " << parameters->BitshiftCh1() << L" " << parameters->BaselineCh1());
187 }
188 
190  NiFpga_Bool b;
191  status = NiFpga_ReadBool(session, NiFpga_AnalogIntegrator_NI5771_Resonance_IndicatorBool_ToHostCh1FIFOOverflow, &b);
192  parameters->diagnosis.ToHostOverflowCh1 = (b!=0);
193  status = NiFpga_ReadBool(session, NiFpga_AnalogIntegrator_NI5771_Resonance_IndicatorBool_ToHostCh2FIFOOverflow, &b);
194  parameters->diagnosis.ToHostOverflowCh2 = (b!=0);
195  status = NiFpga_ReadBool(session, NiFpga_AnalogIntegrator_NI5771_Resonance_IndicatorBool_InterloopFIFOOverflow, &b);
196  parameters->diagnosis.InterloopOverflow = (b!=0);
197  status = NiFpga_ReadBool(session, NiFpga_AnalogIntegrator_NI5771_Resonance_IndicatorBool_InterloopFIFOTimeout, &b);
198  parameters->diagnosis.InterloopTimeout = (b!=0);
199  status = NiFpga_ReadBool(session, NiFpga_AnalogIntegrator_NI5771_Resonance_IndicatorBool_Acquiring, &b);
200  parameters->diagnosis.Acquiring = (b!=0);
201  status = NiFpga_ReadBool(session, NiFpga_AnalogIntegrator_NI5771_Resonance_IndicatorBool_IOModuleAIOverRange, &b);
202  parameters->diagnosis.AIOverRange = (b!=0);
203 }
204 
206  // Clear interloop fifo
207  status = NiFpga_WriteBool(session, NiFpga_AnalogIntegrator_NI5771_Resonance_ControlBool_ClearInterloopFIFO, true);
208  std::this_thread::sleep_for(std::chrono::milliseconds(50));
209  status = NiFpga_WriteBool(session, NiFpga_AnalogIntegrator_NI5771_Resonance_ControlBool_ClearInterloopFIFO, false);
210 
211  // Stop to host FIFOs (clears them)
212  for ( auto f : fifos )
213  status = NiFpga_StopFifo(session, f);
214  std::this_thread::sleep_for(std::chrono::milliseconds(50));
215 
216  // Restart to host FIFOs
217  for ( auto f : fifos )
218  status = NiFpga_StartFifo(session, f);
219  std::this_thread::sleep_for(std::chrono::milliseconds(50));
220 }
221 
222 }
ScopeNumber< uint8_t > BitshiftCh2
Number of bits to shift U32 right before casting to U16 (channel 2)
Definition: IO.h:425
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...
ScopeNumber< bool > AIOverRange
indicator if input is over the ADC range
Definition: IO.h:440
A DaqChunk contains data from all channels sequentially and additionally a bool vector for the resona...
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: FPGAIO5771.cpp:92
void StartAcquisition() override
Starts the acquisition on the FPGA.
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 SetTriggering(const bool &_waitfortrigger) override
Sets if the FPGA should wait for a trigger before starting acquisition.
Handels the NI FlexRIO adapter module IO-5771.
Definition: FPGAIO5771.h:11
ScopeNumber< uint8_t > BitshiftCh1
Number of bits to shift U32 right before casting to U16 (channel 1)
Definition: IO.h:422
std::vector< uint16_t > data
The data vector.
Definition: DaqChunk.h:26
ScopeNumber< uint8_t > BaselineCh2
Baseline U8 value to set zero in channel 2 (NI5771 reads ~ -1..+1V as unsigned 8 bit number...
Definition: IO.h:307
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
double SetPixeltime(const uint32_t &_area, const double &_pixeltime) override
Sets the time per pixel/dwell time (in seconds)
void SetChannelProps()
Set channel properties as baseline and bitshift.
FPGAStatusSafe status
current FPGA status.
Definition: FPGAInterface.h:23
#define DBOUT(s)
A debug output to the debug console.
Definition: helpers.h:153
std::array< NiFpga_AnalogIntegrator_NI5771_Resonance_TargetToHostFifoU32, 2 > fifos
both fifos for both channels
bool Success() const
FPGAResonanceScannerNI5771()
Load the FPGA bitfile, set the IO module's onboard clock and initialize the acquisition.
void StopAcquisition() override
Stops the acquisition on the FPGA.
Parameters for pixel acquisition FPGAAnalogIntegrator.
Definition: IO.h:411
void SetClockSource(NiFpga_Session _session, const uint8_t &_clock_source=0)
Possible clock sources (see adapter modules help and Configure Clock.vi from NI 5771 Clock Select exa...
Definition: FPGAIO5771.cpp:41
parameters::InputsFPGAAnalogIntegrator * parameters
the parameter set
ScopeNumber< bool > Acquiring
and the Acquiring indicator
Definition: IO.h:437
virtual void Initialize(parameters::InputsFPGA *_parameters)
Set initial parameters.
Definition: FPGAInterface.h:38
int32_t ReadPixels(DaqChunk &_chunk, const double &_timeout, bool &_timedout) override
Read only pixels from the FPGA FIFO.
ScopeNumber< uint8_t > BaselineCh1
Baseline U8 value to set zero in channel 1 (NI5771 reads ~ -1..+1V as unsigned 8 bit number...
Definition: IO.h:304
Diagnosis diagnosis
Keeps the LEDs/ScopeNumber for FPGA diagnosis together.
Definition: IO.h:453
Parameters for pixel acquisition with NI-FPGA.
Definition: IO.h:117
void SetContinuousAcquisition(const bool &_cont) override
Sets if the FPGA should acquire data continuously or acquire the number of pixels per channel set wit...
NiFpga_Session session
NI FPGA session handle.
Definition: FPGAInterface.h:26
void ClearFIFOs()
Clears the interloop and ToHost FIFOs.
void CheckFPGADiagnosis()
Checks the status of the FIFOs on the FPGA.
std::vector< bool > resSync
The vector with booleans for the synchronization signal for the resonance scanner.
void Initialize(parameters::InputsFPGA *_parameters) override
Set initial parameters.