Scope
FPGAAnalogDemultiplexer.cpp
1 #include "StdAfx.h"
2 #include "FPGAAnalogDemultiplexer.h"
3 #include "parameters/IO.h"
4 #include "helpers/DaqChunk.h"
5 
6 namespace scope {
7 
9  : FPGAIO5771(NiFpga_AnalogDemultiplexerV2_NI5771_IndicatorBool_UserCommandIdle
10  , NiFpga_AnalogDemultiplexerV2_NI5771_IndicatorBool_PLLLocked
11  , NiFpga_AnalogDemultiplexerV2_NI5771_IndicatorBool_Configured
12  , NiFpga_AnalogDemultiplexerV2_NI5771_IndicatorBool_UserError
13  , NiFpga_AnalogDemultiplexerV2_NI5771_IndicatorU8_UserCommandStatus
14  , NiFpga_AnalogDemultiplexerV2_NI5771_ControlU8_UserCommand
15  , NiFpga_AnalogDemultiplexerV2_NI5771_ControlU16_UserData0
16  , NiFpga_AnalogDemultiplexerV2_NI5771_ControlU8_UserData1
17  , NiFpga_AnalogDemultiplexerV2_NI5771_ControlBool_UserCommandCommit) {
18  assert(SCOPE_NAREAS <= 2);
19  status = NiFpga_Initialize();
20 
21  char* const Bitfile = "devices\\fpga\\" NiFpga_AnalogDemultiplexerV2_NI5771_Bitfile;
22 
23  // Load but do not run yet
24  status = NiFpga_Open(Bitfile, NiFpga_AnalogDemultiplexerV2_NI5771_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_AnalogDemultiplexerV2_NI5771_TargetToHostFifoU64_ToHostA1FIFO;
40  fifos[1] = NiFpga_AnalogDemultiplexerV2_NI5771_TargetToHostFifoU64_ToHostA2FIFO;
41  reqpixels[0] = NiFpga_AnalogDemultiplexerV2_NI5771_ControlU32_RequestedpixelsA1;
42  reqpixels[1] = NiFpga_AnalogDemultiplexerV2_NI5771_ControlU32_RequestedpixelsA2;
43  smplsperpixel = NiFpga_AnalogDemultiplexerV2_NI5771_ControlU16_Samplesperpixel;
44 
45 }
46 
48  status = NiFpga_Close(session, 0);
49  status = NiFpga_Finalize();
50  DBOUT(L"FPGAAnalogDemultiplexer::~FPGAAnalogDemultiplexer session closed");
51 }
52 
54  if ( !initialized ) {
55  parameters = dynamic_cast<parameters::InputsFPGAAnalogDemultiplexer*>(_parameters);
56 
58 
59  FPGAInterface::Initialize(_parameters);
60  }
61 }
62 
63 double FPGAAnalogDemultiplexer::SetPixeltime(const uint32_t& _area, const double& _pixeltime) {
64  // sampling rate of the NI 5771 is 1.5GHz
65  uint16_t samplesperpixel = round2ui16(_pixeltime * 1E-6 * 1.5E9);
66 
67  // only set the pixeltime from area 1 (this holds for all areas)!
68  if ( _area == 0 ) {
69  DBOUT(L"FPGADemultiplexer::SetPixeltime Clockcycles per pixel" << samplesperpixel);
70  // Since the Demultiplexer VI is working on arrays of 8 samples clockcycles has to be a multiple of 8
71  if ( samplesperpixel%8 != 0 ) {
72  samplesperpixel -= (samplesperpixel%8);
73  DBOUT(L"FPGADemultiplexer::SetPixeltime Coerced samples per pixel" << samplesperpixel);
74  }
75  status = NiFpga_WriteU16(session, smplsperpixel, samplesperpixel);
76  }
77  return static_cast<double>(samplesperpixel)*1E6/1.5E9;
78 }
79 
80 double FPGAAnalogDemultiplexer::SetLinetime(const uint32_t& _area, const double& _linetime) {
81  // Not supported by FPGA VI
82  return _linetime;
83 }
84 
85 void FPGAAnalogDemultiplexer::SetTriggering(const bool& _waitfortrigger) {
86  status = NiFpga_WriteBool(session, NiFpga_AnalogDemultiplexerV2_NI5771_ControlBool_Waitfortrigger, _waitfortrigger);
87 }
88 
90  status = NiFpga_WriteBool(session, NiFpga_AnalogDemultiplexerV2_NI5771_ControlBool_Acquirecontinuously, _cont);
91 }
92 
93 void FPGAAnalogDemultiplexer::SetRequestedPixels(const uint32_t& _area, const uint32_t& _reqpixels) {
94  status = NiFpga_WriteU32(session, reqpixels[_area], _reqpixels);
95  DBOUT(L"FPGAAnalogDemultiplexer::SetRequestedPixels area " << _area << L": " << _reqpixels);
96 }
97 
99  NiFpga_Bool alreadyrunning = false;
100  status = NiFpga_ReadBool(session, NiFpga_AnalogDemultiplexerV2_NI5771_ControlBool_Acquire, &alreadyrunning);
101 
102  // Only clear fifos if not alreay running (e.g. by a previous StartAcquisition from another area!!) Leads to nasty bugs!
103  if ( !alreadyrunning ) {
104  ClearFIFOs();
105  SetChannelProps();
106  status = NiFpga_WriteBool(session, NiFpga_AnalogDemultiplexerV2_NI5771_ControlBool_Acquire, true);
107  }
108 }
109 
111  DBOUT(L"FPGAAnalogDemultiplexer::StopAcquisition");
112  status = NiFpga_WriteBool(session, NiFpga_AnalogDemultiplexerV2_NI5771_ControlBool_Acquire, false);
113 }
114 
115 int32_t FPGAAnalogDemultiplexer::ReadPixels(DaqChunk& _chunk, const double& _timeout, bool& _timedout) {
116  size_t remaining = 0;
117 
118  // only two channels and two areas supported in FPGA vi
119  assert( (_chunk.NChannels() == 2) && (_chunk.Area() <= 1) );
120 
121  // we need enough space
122  assert(_chunk.data.size() >= _chunk.PerChannel() * _chunk.NChannels());
123 
124  NiFpga_Status stat = NiFpga_Status_Success;
125 
126  // Make temporary vector to hold the U64 data from both channels
127  std::vector<uint64_t> u64data(_chunk.PerChannel());
128 
129  // Get the desired bitshift for each channel
130  std::vector<const uint8_t> bitshift(2);
131  bitshift[0] = (_chunk.Area()==0)?parameters->BitshiftA1Ch1():parameters->BitshiftA2Ch1();
132  bitshift[1] = (_chunk.Area()==0)?parameters->BitshiftA1Ch2():parameters->BitshiftA2Ch2();
133 
134  // Sets the desired baseline on the FPGA. Do it here so changes in GUI get transferred to the FPGA quickly.
135  //SetChannelProps();
136 
137  // Do the read from the FIFO
138  stat = NiFpga_ReadFifoU64(session
139  , fifos[_chunk.Area()] // select correct fifo
140  , u64data.data()
141  , _chunk.PerChannel()
142  , static_cast<uint32_t>(_timeout * 1000) // FPGA C API takes timeout in milliseconds, to be consistent with DAQmx we have _timeout in seconds
143  , &remaining);
144  _timedout = (stat == NiFpga_Status_FifoTimeout);
145 
146  DBOUT(L"FPGAAnalogDemultiplexer::ReadPixels area " << _chunk.Area() << L" remaining: " << remaining);
147 
148  // avoid throwing exception on time out (since FpgaStatus status could throw on all errors)
149  if ( _timedout )
150  return -1;
151  status = stat;
152 
153  // U64 from FIFO has Ch1 in the higher 32 bits, Ch2 in the lower 32 bits
154  auto itch1 = std::begin(_chunk.data);
155  auto itch2 = std::begin(_chunk.data) + _chunk.PerChannel();
156  std::for_each(std::begin(u64data), std::end(u64data), [&](const uint64_t& u64) {
157  *itch1 = static_cast<uint16_t>((u64 >> 32) >> bitshift[0]); // shift 32 bits to the right to get Ch1, then do bitshift
158  *itch2 = static_cast<uint16_t>((u64 & 0xffff) >> bitshift[1]); // leave only lower 16 bits to get Ch2, then do bitshift
159  itch1++;
160  itch2++;
161  });
162 
163  if ( status.Success() )
164  return _chunk.PerChannel();
165  return -1;
166 }
167 
169  status = NiFpga_WriteU8(session, NiFpga_AnalogDemultiplexerV2_NI5771_ControlU8_BaselineU8Ch1, parameters->BaselineCh1());
170  status = NiFpga_WriteU8(session, NiFpga_AnalogDemultiplexerV2_NI5771_ControlU8_BaselineU8Ch2, parameters->BaselineCh2());
171  status = NiFpga_WriteU8(session, NiFpga_AnalogDemultiplexerV2_NI5771_ControlU8_CutoffU8Ch1, parameters->CutoffCh1());
172  status = NiFpga_WriteU8(session, NiFpga_AnalogDemultiplexerV2_NI5771_ControlU8_CutoffU8Ch2, parameters->CutoffCh2());
173  DBOUT(L"FPGAAnalogDemultiplexer::SetChannelProps baseline " << parameters->BaselineCh1() << L" " << parameters->BaselineCh2());
174 }
175 
177  NiFpga_Bool b(0);
178  uint16_t ui = 0;
179  status = NiFpga_ReadBool(session, NiFpga_AnalogDemultiplexerV2_NI5771_IndicatorBool_ToHostA1FIFOOverflow, &b);
180  parameters->diagnosis.ToHostOverflowA1 = (b!=0);
181  status = NiFpga_ReadBool(session, NiFpga_AnalogDemultiplexerV2_NI5771_IndicatorBool_ToHostA2FIFOOverflow, &b);
182  parameters->diagnosis.ToHostOverflowA1 = (b!=0);
183  status = NiFpga_ReadBool(session, NiFpga_AnalogDemultiplexerV2_NI5771_IndicatorBool_InterloopFIFOOverflow, &b);
184  parameters->diagnosis.InterloopOverflow = (b!=0);
185  status = NiFpga_ReadBool(session, NiFpga_AnalogDemultiplexerV2_NI5771_IndicatorBool_InterloopFIFOtimeout, &b);
186  parameters->diagnosis.InterloopTimeout = (b!=0);
187  status = NiFpga_ReadBool(session, NiFpga_AnalogDemultiplexerV2_NI5771_IndicatorBool_IOModuleAIOverRange, &b);
188  parameters->diagnosis.AIOverRange = (b!=0);
189  status = NiFpga_ReadBool(session, NiFpga_AnalogDemultiplexerV2_NI5771_IndicatorBool_Acquiring, &b);
190  parameters->diagnosis.Acquiring = (b!=0);
191 }
192 
194  status = NiFpga_WriteBool(session, NiFpga_AnalogDemultiplexerV2_NI5771_ControlBool_ClearInterloopFIFO, 1);
195  std::this_thread::sleep_for(std::chrono::milliseconds(50));
196  status = NiFpga_WriteBool(session, NiFpga_AnalogDemultiplexerV2_NI5771_ControlBool_ClearInterloopFIFO, 0);
197 
198  // Stop FIFOs (clears them)
199  for ( auto f : fifos )
200  status = NiFpga_StopFifo(session, f);
201  std::this_thread::sleep_for(std::chrono::milliseconds(50));
202 
203  // Restart FIFOs
204  for ( auto f : fifos )
205  status = NiFpga_StartFifo(session, f);
206  std::this_thread::sleep_for(std::chrono::milliseconds(50));
207 
208  DBOUT(L"FPGAAnalogDemultiplexer::ClearFIFOs()");
209 }
210 
211 }
parameters::InputsFPGAAnalogDemultiplexer * parameters
the parameter set
void StartAcquisition() override
Starts the acquisition on the FPGA.
void SetTriggering(const bool &_waitfortrigger) override
Sets if the FPGA should wait for a trigger before starting acquisition.
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 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 > BitshiftA1Ch2
Number of bits to shift U32 right before casting to U16 (area 1 channel 2)
Definition: IO.h:369
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
void SetChannelProps()
Set channel properties as baseline cutoff and bitshift.
std::array< NiFpga_AnalogDemultiplexerV2_NI5771_TargetToHostFifoU64, 2 > fifos
all FIFOs for both areas
std::array< NiFpga_AnalogDemultiplexerV2_NI5771_ControlU32, 2 > reqpixels
requested pixels for both areas
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 StopAcquisition() override
Stops the acquisition on the FPGA.
ScopeNumber< uint8_t > BitshiftA2Ch2
Number of bits to shift U32 right before casting to U16 (area 2 channel 2)
Definition: IO.h:375
FPGAStatusSafe status
current FPGA status.
Definition: FPGAInterface.h:23
NiFpga_AnalogDemultiplexerV2_NI5771_ControlU16 smplsperpixel
samples per pixel for both areas
#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
double SetPixeltime(const uint32_t &_area, const double &_pixeltime) override
Sets the time per pixel/dwell time (in seconds)
void SetContinuousAcquisition(const bool &_cont) override
Sets if the FPGA should acquire data continuously or acquire the number of pixels per channel set wit...
void Initialize(parameters::InputsFPGA *_parameters) override
Set initial parameters.
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
int32_t ReadPixels(DaqChunk &_chunk, const double &_timeout, bool &_timedout) override
Read only pixels from the FPGA FIFO.
~FPGAAnalogDemultiplexer()
Close FPGA session.
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
void ClearFIFOs()
Clears the interloop and ToHost FIFOs.
Parameters for pixel acquisition with NI-FPGA.
Definition: IO.h:117
void CheckFPGADiagnosis()
Checks the status of the FIFOs on the FPGA.
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
Diagnosis diagnosis
Keeps the LEDs/ScopeNumber for FPGA diagnosis together.
Definition: IO.h:403
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
FPGAAnalogDemultiplexer()
Load the FPGA bitfile, set the IO module's onboard clock and initialize the acquisition.