Scope
FPGAAnalogDemultiplexerResonance.cpp
1 #include "StdAfx.h"
2 #include "FPGAAnalogDemultiplexerResonance.h"
3 #include "parameters/IO.h"
4 #include "helpers/DaqChunkResonance.h"
5 
6 namespace scope {
7 
9  : FPGAIO5771(NiFpga_AnalogDemultiplexer_NI5771_Resonance_IndicatorBool_UserCommandIdle
10  , NiFpga_AnalogDemultiplexer_NI5771_Resonance_IndicatorBool_PLLLocked
11  , NiFpga_AnalogDemultiplexer_NI5771_Resonance_IndicatorBool_Configured
12  , NiFpga_AnalogDemultiplexer_NI5771_Resonance_IndicatorBool_UserError
13  , NiFpga_AnalogDemultiplexer_NI5771_Resonance_IndicatorU8_UserCommandStatus
14  , NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlU8_UserCommand
15  , NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlU16_UserData0
16  , NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlU8_UserData1
17  , NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlBool_UserCommandCommit) {
18  assert(SCOPE_NAREAS <= 2);
19  status = NiFpga_Initialize();
20 
21  char* const Bitfile = "devices\\fpga\\" NiFpga_AnalogDemultiplexer_NI5771_Resonance_Bitfile;
22 
23  // Load but do not run yet
24  status = NiFpga_Open(Bitfile, NiFpga_AnalogDemultiplexer_NI5771_Resonance_Signature, "RIO0", 0, &session);
25  DBOUT(L"FPGADemultiplexer: FPGA Session opened");
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_AnalogDemultiplexer_NI5771_Resonance_TargetToHostFifoU64_ToHostA1FIFO;
40  fifos[1] = NiFpga_AnalogDemultiplexer_NI5771_Resonance_TargetToHostFifoU64_ToHostA2FIFO;
41  reqpixels[0] = NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlU32_RequestedpixelsA1;
42  reqpixels[1] = NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlU32_RequestedpixelsA2;
43  smplsperpixel = NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlU16_Samplesperpixel;
44 
45 }
46 
48  status = NiFpga_Close(session, 0);
49  status = NiFpga_Finalize();
50  DBOUT(L"FPGAAnalogDemultiplexerResonance::~FPGAAnalogDemultiplexerResonance session closed");
51 }
52 
54  if ( !initialized ) {
55  parameters = dynamic_cast<parameters::InputsFPGAAnalogDemultiplexer*>(_parameters);
56 
58 
59  // addition #1 to the fpga code to run Analog Demultiplexing for resonance scanmode (Karlis)
60  uint32_t chunksize = 1000000;
61 
62  status = NiFpga_ConfigureFifo(session, fifos[0], 5*chunksize);
63  status = NiFpga_ConfigureFifo(session, fifos[1], 5*chunksize);
64 
65  FPGAInterface::Initialize(_parameters);
66  }
67 }
68 
69 double FPGAAnalogDemultiplexerResonance::SetPixeltime(const uint32_t& _area, const double& _pixeltime) {
70  // sampling rate of the NI 5771 is 1.5GHz
71  uint16_t samplesperpixel = round2ui16(_pixeltime * 1E-6 * 1.5E9);
72 
73  // only set the pixeltime from area 1 (this holds for all areas)!
74  if ( _area == 0 ) {
75  DBOUT(L"FPGADemultiplexer::SetPixeltime Clockcycles per pixel" << samplesperpixel);
76  // Since the Demultiplexer VI is working on arrays of 8 samples clockcycles has to be a multiple of 8
77  if ( samplesperpixel%8 != 0 ) {
78  samplesperpixel -= (samplesperpixel%8);
79  DBOUT(L"FPGADemultiplexer::SetPixeltime Coerced samples per pixel" << samplesperpixel);
80  }
81  status = NiFpga_WriteU16(session, smplsperpixel, samplesperpixel);
82  }
83  return static_cast<double>(samplesperpixel)*1E6/1.5E9;
84 }
85 
86 double FPGAAnalogDemultiplexerResonance::SetLinetime(const uint32_t& _area, const double& _linetime) {
87  // Not supported by FPGA VI
88  return _linetime;
89 }
90 
91 void FPGAAnalogDemultiplexerResonance::SetTriggering(const bool& _waitfortrigger) {
92  status = NiFpga_WriteBool(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlBool_Waitfortrigger, _waitfortrigger);
93 }
94 
96  status = NiFpga_WriteBool(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlBool_Acquirecontinuously, _cont);
97 }
98 
99 void FPGAAnalogDemultiplexerResonance::SetRequestedPixels(const uint32_t& _area, const uint32_t& _reqpixels) {
100  status = NiFpga_WriteU32(session, reqpixels[_area], _reqpixels);
101  DBOUT(L"FPGAAnalogDemultiplexerResonance::SetRequestedPixels area " << _area << L": " << _reqpixels);
102 }
103 
105  NiFpga_Bool alreadyrunning = false;
106  status = NiFpga_ReadBool(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlBool_Acquire, &alreadyrunning);
107 
108  // Only clear fifos if not alreay running (e.g. by a previous StartAcquisition from another area!!) Leads to nasty bugs!
109  if ( !alreadyrunning ) {
110  ClearFIFOs();
111  SetChannelProps();
112  status = NiFpga_WriteBool(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlBool_Acquire, true);
113  }
114 }
115 
117  DBOUT(L"FPGAAnalogDemultiplexerResonance::StopAcquisition");
118  status = NiFpga_WriteBool(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlBool_Acquire, false);
119 }
120 
121 int32_t FPGAAnalogDemultiplexerResonance::ReadPixels(DaqChunk& _chunk, const double& _timeout, bool& _timedout) {
122  size_t remaining = 0;
123 
124  // We have to upcast here to get access to the resonance sync vector
125  auto chunkres = dynamic_cast<DaqChunkResonance&>(_chunk);
126 
127  // only two channels and one area supported in FPGA vi
128  assert( (_chunk.NChannels() == 2) && (_chunk.Area() == 0) );
129 
130  // we need enough space
131  assert(_chunk.data.size() >= _chunk.PerChannel() * _chunk.NChannels());
132 
133  NiFpga_Status stat = NiFpga_Status_Success;
134 
135  // Make temporary vector to hold the U64 data from both channels
136  std::vector<uint64_t> u64data(_chunk.PerChannel());
137 
138  // Get the desired bitshift for each channel
139  std::vector<uint8_t> bitshift(2);
140  bitshift[0] = (_chunk.Area()==0)?parameters->BitshiftA1Ch1():parameters->BitshiftA2Ch1();
141  bitshift[1] = (_chunk.Area()==0)?parameters->BitshiftA1Ch2():parameters->BitshiftA2Ch2();
142 
143  // Sets the desired baseline on the FPGA. Do it here so changes in GUI get transferred to the FPGA quickly.
144  //SetChannelProps();
145 
146  // Do the read from the FIFO
147  stat = NiFpga_ReadFifoU64(session
148  , fifos[_chunk.Area()] // select correct fifo
149  , u64data.data()
150  , _chunk.PerChannel()
151  , static_cast<uint32_t>(_timeout * 1000) // FPGA C API takes timeout in milliseconds, to be consistent with DAQmx we have _timeout in seconds
152  , &remaining);
153  _timedout = (stat == NiFpga_Status_FifoTimeout);
154 
155  DBOUT(L"FPGAAnalogDemultiplexerResonance::ReadPixels area " << _chunk.Area() << L" remaining: " << remaining);
156 
157  // avoid throwing exception on time out (since FpgaStatus status could throw on all errors)
158  if ( _timedout )
159  return -1;
160  status = stat;
161 
162  // U64 from FIFO has Ch1 in the higher 32 bits, Ch2 in the lower 32 bits
163  auto itch1 = std::begin(chunkres.data);
164  auto itch2 = std::begin(chunkres.data) + chunkres.PerChannel();
165  // addition #2 to the fpga code to run Analog Demultiplexing for resonance scanmode (Karlis)
166  auto itsync = std::begin(chunkres.resSync);
167  for( const uint64_t& u64 : u64data) {
168  // *itch1 = static_cast<uint16_t>((u64 >> 32)); // shift 32 bits to the right to get Ch1, then do bitshift
169  // *itch2 = static_cast<uint16_t>((u64 & 0xffff)); // leave only lower 16 bits to get Ch2, then do bitshift
170  *itch1 = static_cast<uint16_t>((u64 >> 32) >> bitshift[0]); // shift 32 bits to the right to get Ch1, then do bitshift
171  *itch2 = static_cast<uint16_t>((u64 & 0xffff) >> bitshift[1]); // leave only lower 16 bits to get Ch2, then do bitshift
172  *itsync = (u64 >> 63) != 0; // highest bit is sync
173  itch1++;
174  itch2++;
175  itsync++;
176  }
177 
178  if ( status.Success() )
179  return chunkres.PerChannel();
180  return -1;
181 }
182 
184  status = NiFpga_WriteU8(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlU8_BaselineU8Ch1, parameters->BaselineCh1());
185  status = NiFpga_WriteU8(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlU8_BaselineU8Ch2, parameters->BaselineCh2());
186  status = NiFpga_WriteU8(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlU8_CutoffU8Ch1, parameters->CutoffCh1());
187  status = NiFpga_WriteU8(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlU8_CutoffU8Ch2, parameters->CutoffCh2());
188  DBOUT(L"FPGAAnalogDemultiplexerResonance::SetChannelProps baseline " << parameters->BaselineCh1() << L" " << parameters->BaselineCh2());
189 }
190 
192  NiFpga_Bool b(0);
193  uint16_t ui = 0;
194  status = NiFpga_ReadBool(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_IndicatorBool_ToHostA1FIFOOverflow, &b);
195  parameters->diagnosis.ToHostOverflowA1 = (b!=0);
196  status = NiFpga_ReadBool(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_IndicatorBool_ToHostA2FIFOOverflow, &b);
197  parameters->diagnosis.ToHostOverflowA1 = (b!=0);
198  status = NiFpga_ReadBool(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_IndicatorBool_InterloopFIFOOverflow, &b);
199  parameters->diagnosis.InterloopOverflow = (b!=0);
200  status = NiFpga_ReadBool(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_IndicatorBool_InterloopFIFOtimeout, &b);
201  parameters->diagnosis.InterloopTimeout = (b!=0);
202  status = NiFpga_ReadBool(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_IndicatorBool_IOModuleAIOverRange, &b);
203  parameters->diagnosis.AIOverRange = (b!=0);
204  status = NiFpga_ReadBool(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_IndicatorBool_Acquiring, &b);
205  parameters->diagnosis.Acquiring = (b!=0);
206 }
207 
209  status = NiFpga_WriteBool(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlBool_ClearInterloopFIFO, 1);
210  std::this_thread::sleep_for(std::chrono::milliseconds(50));
211  status = NiFpga_WriteBool(session, NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlBool_ClearInterloopFIFO, 0);
212 
213  // Stop FIFOs (clears them)
214  for ( auto f : fifos )
215  status = NiFpga_StopFifo(session, f);
216  std::this_thread::sleep_for(std::chrono::milliseconds(50));
217 
218  // Restart FIFOs
219  for ( auto f : fifos )
220  status = NiFpga_StartFifo(session, f);
221  std::this_thread::sleep_for(std::chrono::milliseconds(50));
222 
223  DBOUT(L"FPGAAnalogDemultiplexerResonance::ClearFIFOs()");
224 }
225 
226 }
NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlU16 smplsperpixel
samples per pixel for both areas
void SetTriggering(const bool &_waitfortrigger) override
Sets if the FPGA should wait for a trigger before starting acquisition.
std::array< NiFpga_AnalogDemultiplexer_NI5771_Resonance_TargetToHostFifoU64, 2 > fifos
all FIFOs for both areas
ScopeNumber< uint8_t > BitshiftA1Ch2
Number of bits to shift U32 right before casting to U16 (area 1 channel 2)
Definition: IO.h:369
A DaqChunk contains data from all channels sequentially and additionally a bool vector for the resona...
int32_t ReadPixels(DaqChunk &_chunk, const double &_timeout, bool &_timedout) override
Read only pixels from the FPGA FIFO.
void SetContinuousAcquisition(const bool &_cont) override
Sets if the FPGA should acquire data continuously or acquire the number of pixels per channel set wit...
Parameters for pixel acquisition FPGAAnalogDemultiplexer.
Definition: IO.h:355
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
ScopeNumber< bool > AIOverRange
indicator if input is over the ADC range
Definition: IO.h:390
double SetPixeltime(const uint32_t &_area, const double &_pixeltime) override
Sets the time per pixel/dwell time (in seconds)
Handels the NI FlexRIO adapter module IO-5771.
Definition: FPGAIO5771.h:11
ScopeNumber< uint8_t > BitshiftA2Ch1
Number of bits to shift U32 right before casting to U16 (area 2 channel 1)
Definition: IO.h:372
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
ScopeNumber< uint8_t > CutoffCh2
Cutoff U8 value to set zero in channel 2 (NI5771 reads ~ -1..+1V as unsigned 8 bit number...
Definition: IO.h:313
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< uint8_t > BitshiftA2Ch2
Number of bits to shift U32 right before casting to U16 (area 2 channel 2)
Definition: IO.h:375
void StartAcquisition() override
Starts the acquisition on the FPGA.
void CheckFPGADiagnosis()
Checks the status of the FIFOs on the FPGA.
FPGAStatusSafe status
current FPGA status.
Definition: FPGAInterface.h:23
#define DBOUT(s)
A debug output to the debug console.
Definition: helpers.h:153
bool Success() const
ScopeNumber< bool > Acquiring
and the Acquiring indicator
Definition: IO.h:387
void StopAcquisition() override
Stops the acquisition on the FPGA.
parameters::InputsFPGAAnalogDemultiplexer * parameters
the parameter set
std::array< NiFpga_AnalogDemultiplexer_NI5771_Resonance_ControlU32, 2 > reqpixels
requested pixels for both areas
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
void ClearFIFOs()
Clears the interloop and ToHost FIFOs.
virtual void Initialize(parameters::InputsFPGA *_parameters)
Set initial parameters.
Definition: FPGAInterface.h:38
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
Parameters for pixel acquisition with NI-FPGA.
Definition: IO.h:117
ScopeNumber< uint8_t > CutoffCh1
Cutoff U8 value to set zero in channel 1 (NI5771 reads ~ -1..+1V as unsigned 8 bit number...
Definition: IO.h:310
FPGAAnalogDemultiplexerResonance()
Load the FPGA bitfile, set the IO module's onboard clock and initialize the acquisition.
void SetChannelProps()
Set channel properties as baseline cutoff and bitshift.
Diagnosis diagnosis
Keeps the LEDs/ScopeNumber for FPGA diagnosis together.
Definition: IO.h:403
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) ...
ScopeNumber< uint8_t > BitshiftA1Ch1
Number of bits to shift U32 right before casting to U16 (area 1 channel 1)
Definition: IO.h:366
NiFpga_Session session
NI FPGA session handle.
Definition: FPGAInterface.h:26
void Initialize(parameters::InputsFPGA *_parameters) override
Set initial parameters.