1 #include "FPGA_common.h"
2 #include "IConnection.h"
3 #include "LMS64CProtocol.h"
4 #include <ciso646>
5 #include <vector>
6 #include <map>
7 #include <math.h>
8 #include <assert.h>
9 #include <thread>
10 #include "Logger.h"
11 #include <algorithm>
12 using namespace std;
13
14 namespace lime
15 {
16
17 // 0x000A
18 const int RX_EN = 1; //controls both receiver and transmitter
19 const int TX_EN = 1 << 1; //used for wfm playback from fpga
20 const int STREAM_LOAD = 1 << 2;
21
22 // 0x0009
23 const int SMPL_NR_CLR = 1; // rising edge clears
24 const int TXPCT_LOSS_CLR = 1 << 1; // 0 - normal operation, 1-clear
25
26 const uint16_t PLLCFG_START = 0x1;
27 const uint16_t PHCFG_START = 0x2;
28 const uint16_t PLLRST_START = 0x4;
29 const uint16_t PHCFG_UPDN = 1 << 13;
30 const uint16_t PHCFG_MODE = 1 << 14;
31
32 const uint16_t busyAddr = 0x0021;
33
FPGA()34 FPGA::FPGA()
35 {
36 useCache = false;
37 }
38
EnableValuesCache(bool enabled)39 void FPGA::EnableValuesCache(bool enabled)
40 {
41 useCache = enabled;
42 if (!useCache)
43 regsCache.clear();
44 }
45
WriteRegister(uint32_t addr,uint32_t val)46 int FPGA::WriteRegister(uint32_t addr, uint32_t val)
47 {
48 return WriteRegisters(&addr, &val, 1);
49 }
50
ReadRegister(uint32_t addr)51 int FPGA::ReadRegister(uint32_t addr)
52 {
53 uint32_t val;
54 return ReadRegisters(&addr, &val, 1) != 0 ? -1 : val;
55 }
56
WriteRegisters(const uint32_t * addrs,const uint32_t * data,unsigned cnt)57 int FPGA::WriteRegisters(const uint32_t *addrs, const uint32_t *data, unsigned cnt)
58 {
59 if (useCache)
60 {
61 const int readonly_regs[] = {
62 0x000, 0x001, 0x002, 0x003, 0x021, 0x022, 0x065, 0x067, 0x069, 0x06A,
63 0x06B, 0x06C, 0x06D, 0x06F, 0x070, 0x071, 0x072, 0x073, 0x074, 0x076,
64 0x077, 0x078, 0x07A, 0x07B, 0x07C, 0x0C2, 0x100, 0x101, 0x102, 0x103,
65 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10A, 0x10B, 0x10C, 0x10D,
66 0x10E, 0x10F, 0x110, 0x111, 0x114};
67
68 std::vector<uint32_t> reg_addr;
69 std::vector<uint32_t> reg_val;
70 for (unsigned i = 0; i < cnt; i++)
71 {
72 auto endptr = readonly_regs + sizeof(readonly_regs)/sizeof(*readonly_regs);
73 if (std::find(readonly_regs, endptr, addrs[i])!=endptr)
74 continue;
75
76 auto result = regsCache.find(addrs[i]);
77 if (result != regsCache.end() && result->second == data[i])
78 continue;
79 reg_addr.push_back(addrs[i]);
80 reg_val.push_back(data[i]);
81 regsCache[addrs[i]] = data[i];
82 }
83 if (reg_val.size())
84 return connection->WriteRegisters(reg_addr.data(), reg_val.data(), reg_val.size());
85 return 0;
86 }
87 return connection->WriteRegisters(addrs, data, cnt);
88 }
89
ReadRegisters(const uint32_t * addrs,uint32_t * data,unsigned cnt)90 int FPGA::ReadRegisters(const uint32_t *addrs, uint32_t *data, unsigned cnt)
91 {
92 if (useCache)
93 {
94 const int volatile_regs[] = {
95 0x021, 0x022, 0x060, 0x065, 0x067, 0x069, 0x06A, 0x06B, 0x06C, 0x06D,
96 0x06F, 0x070, 0x071, 0x072, 0x073, 0x074, 0x076, 0x077, 0x078, 0x07A,
97 0x07B, 0x07C, 0x0C2, 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106,
98 0x107, 0x108, 0x109, 0x10A, 0x10B, 0x10C, 0x10D, 0x10E, 0x10F, 0x110,
99 0x111, 0x114};
100
101 std::vector<uint32_t> reg_addr;
102 for (unsigned i = 0; i < cnt; i++)
103 {
104 auto endptr = volatile_regs + sizeof(volatile_regs)/sizeof(*volatile_regs);
105 if (std::find(volatile_regs, endptr, addrs[i])==endptr)
106 {
107 auto result = regsCache.find(addrs[i]);
108 if (result != regsCache.end())
109 continue;
110 }
111 reg_addr.push_back(addrs[i]);
112 }
113
114 if (reg_addr.size())
115 {
116 std::vector<uint32_t> reg_val(reg_addr.size());
117 if (connection->ReadRegisters(reg_addr.data(), reg_val.data(), reg_addr.size()) <0)
118 return -1;
119 for (unsigned i = 0; i < reg_addr.size(); i++)
120 regsCache[reg_addr[i]] = reg_val[i];
121 }
122 for (unsigned i = 0; i < cnt; i++)
123 data[i] = regsCache[addrs[i]];
124 return 0;
125 }
126 return connection->ReadRegisters(addrs, data, cnt);
127 }
128
SetConnection(IConnection * conn)129 void FPGA::SetConnection(IConnection* conn)
130 {
131 connection = conn;
132 }
133
GetConnection() const134 IConnection* FPGA::GetConnection() const
135 {
136 return connection;
137 }
138
StartStreaming()139 int FPGA::StartStreaming()
140 {
141 int interface_ctrl_000A = ReadRegister(0x000A);
142 if (interface_ctrl_000A < 0)
143 return -1;
144 uint32_t value = RX_EN;
145 return WriteRegister(0x000A, interface_ctrl_000A | value);
146 }
147
StopStreaming()148 int FPGA::StopStreaming()
149 {
150 int interface_ctrl_000A = ReadRegister(0x000A);
151 if (interface_ctrl_000A < 0)
152 return -1;
153 uint32_t value = ~(RX_EN | TX_EN);
154 return WriteRegister(0x000A, interface_ctrl_000A & value);
155 }
156
ResetTimestamp()157 int FPGA::ResetTimestamp()
158 {
159 #ifndef NDEBUG
160 int interface_ctrl_000A = ReadRegister(0x000A);
161 if (interface_ctrl_000A < 0)
162 return 0;
163
164 if ((interface_ctrl_000A & RX_EN))
165 return ReportError(EPERM, "Streaming must be stopped to reset timestamp");
166
167 #endif // NDEBUG
168 //reset hardware timestamp to 0
169 int interface_ctrl_0009 = ReadRegister(0x0009);
170 if (interface_ctrl_0009 < 0)
171 return 0;
172 uint32_t value = (TXPCT_LOSS_CLR | SMPL_NR_CLR);
173 WriteRegister(0x0009, interface_ctrl_0009 & ~(value));
174 WriteRegister(0x0009, interface_ctrl_0009 | value);
175 return WriteRegister(0x0009, interface_ctrl_0009 & ~value);
176 }
177
SetPllClock(int clockIndex,int nSteps,bool waitLock,uint16_t & reg23val)178 int FPGA::SetPllClock(int clockIndex, int nSteps, bool waitLock, uint16_t ®23val)
179 {
180 const auto timeout = chrono::seconds(3);
181 auto t1 = chrono::high_resolution_clock::now();
182 auto t2 = t1;
183 vector<uint32_t> addrs;
184 vector<uint32_t> values;
185 addrs.push_back(0x0023); values.push_back(reg23val & ~PLLCFG_START);
186 addrs.push_back(0x0024); values.push_back(abs(nSteps)); //CNT_PHASE
187 int cnt_ind = (clockIndex + 2) & 0x1F; //C0 index 2, C1 index 3...
188 reg23val &= ~(0xF<<8);
189 reg23val &= ~(PHCFG_MODE);
190 reg23val = reg23val | (cnt_ind << 8);
191 if(nSteps >= 0)
192 reg23val |= PHCFG_UPDN;
193 else
194 reg23val &= ~PHCFG_UPDN;
195 addrs.push_back(0x0023); values.push_back(reg23val); //PHCFG_UpDn, CNT_IND
196 addrs.push_back(0x0023); values.push_back(reg23val | PHCFG_START);
197
198 if(WriteRegisters(addrs.data(), values.data(), values.size()) != 0)
199 ReportError(EIO, "SetPllFrequency: PHCFG, failed to write registers");
200 addrs.clear(); values.clear();
201
202 bool done = false;
203 uint8_t errorCode = 0;
204 t1 = chrono::high_resolution_clock::now();
205 if(waitLock) do
206 {
207 uint16_t statusReg = ReadRegister(busyAddr);
208 done = statusReg & 0x1;
209 errorCode = (statusReg >> 7) & 0xFF;
210 t2 = chrono::high_resolution_clock::now();
211 std::this_thread::sleep_for(chrono::milliseconds(10));
212 } while(!done && errorCode == 0 && (t2-t1) < timeout);
213 if(t2 - t1 > timeout)
214 return ReportError(ENODEV, "SetPllFrequency: PHCFG timeout, busy bit is still 1");
215 if(errorCode != 0)
216 return ReportError(EBUSY, "SetPllFrequency: error configuring PHCFG");
217 addrs.push_back(0x0023); values.push_back(reg23val & ~PHCFG_START);
218 if(WriteRegisters(addrs.data(), values.data(), values.size()) != 0)
219 ReportError(EIO, "SetPllFrequency: configure FPGA PLL, failed to write registers");
220 return 0;
221 }
222
223 /** @brief Configures board FPGA clocks
224 @param serPort communications port
225 @param pllIndex index of FPGA pll
226 @param clocks list of clocks to configure
227 @param clocksCount number of clocks to configure
228 @return 0-success, other-failure
229 */
SetPllFrequency(const uint8_t pllIndex,const double inputFreq,FPGA_PLL_clock * clocks,const uint8_t clockCount)230 int FPGA::SetPllFrequency(const uint8_t pllIndex, const double inputFreq, FPGA_PLL_clock* clocks, const uint8_t clockCount)
231 {
232 auto t1 = chrono::high_resolution_clock::now();
233 auto t2 = t1;
234 const auto timeout = chrono::seconds(3);
235 if(not connection)
236 return ReportError(ENODEV, "ConfigureFPGA_PLL: connection port is NULL");
237 if(not connection->IsOpen())
238 return ReportError(ENODEV, "ConfigureFPGA_PLL: configure FPGA PLL, device not connected");
239 eLMS_DEV boardType = connection->GetDeviceInfo().deviceName == GetDeviceName(LMS_DEV_LIMESDR_QPCIE) ? LMS_DEV_LIMESDR_QPCIE : LMS_DEV_UNKNOWN;
240
241 if(pllIndex > 15)
242 ReportError(ERANGE, "SetPllFrequency: PLL index(%i) out of range [0-15]", pllIndex);
243
244 //check if all clocks are above 5MHz
245 const double PLLlowerLimit = 5e6;
246 if(inputFreq < PLLlowerLimit)
247 return ReportError(ERANGE, "SetPllFrequency: input frequency must be >=%g MHz", PLLlowerLimit/1e6);
248 for(int i=0; i<clockCount; ++i)
249 if(clocks[i].outFrequency < PLLlowerLimit && not clocks[i].bypass)
250 return ReportError(ERANGE, "SetPllFrequency: clock(%i) must be >=%g MHz", i, PLLlowerLimit/1e6);
251
252 //disable direct clock source
253 uint16_t drct_clk_ctrl_0005 = ReadRegister(0x0005);
254 WriteRegister(0x0005, drct_clk_ctrl_0005 & ~(1 << pllIndex));
255
256 uint16_t reg23val = ReadRegister(0x0003);
257
258 reg23val &= ~(0x1F << 3); //clear PLL index
259 reg23val &= ~PLLCFG_START; //clear PLLCFG_START
260 reg23val &= ~PHCFG_START; //clear PHCFG
261 reg23val &= ~PLLRST_START; //clear PLL reset
262 reg23val &= ~PHCFG_UPDN; //clear PHCFG_UpDn
263 reg23val |= pllIndex << 3;
264
265 uint16_t reg25 = ReadRegister(0x0025);
266
267 uint16_t statusReg;
268 bool done = false;
269 uint8_t errorCode = 0;
270 vector<uint32_t> addrs;
271 vector<uint32_t> values;
272 addrs.push_back(0x0025); values.push_back(reg25 | 0x80);
273 addrs.push_back(0x0023); values.push_back(reg23val); //PLL_IND
274 if (clocks->findPhase == false)
275 {
276 addrs.push_back(0x0023); values.push_back(reg23val | PLLRST_START);
277 }
278 WriteRegisters(addrs.data(), values.data(), values.size());
279 addrs.clear(); values.clear();
280
281 t1 = chrono::high_resolution_clock::now();
282 if(boardType == LMS_DEV_LIMESDR_QPCIE) do //wait for reset to activate
283 {
284 statusReg = ReadRegister(busyAddr);
285 done = statusReg & 0x1;
286 errorCode = (statusReg >> 7) & 0xFF;
287 std::this_thread::sleep_for(chrono::milliseconds(10));
288 t2 = chrono::high_resolution_clock::now();
289 } while(not done && errorCode == 0 && (t2-t1) < timeout);
290 if(t2 - t1 > timeout)
291 return ReportError(ENODEV, "SetPllFrequency: PLLRST timeout, busy bit is still 1");
292 if(errorCode != 0)
293 return ReportError(EBUSY, "SetPllFrequency: error resetting PLL");
294
295 addrs.push_back(0x0023); values.push_back(reg23val & ~PLLRST_START);
296
297 //configure FPGA PLLs
298 const double vcoLimits_Hz[2] = { 600e6, 1300e6 };
299
300 map< unsigned long, int> availableVCOs; //all available frequencies for VCO
301 for(int i=0; i<clockCount; ++i)
302 {
303 unsigned long freq;
304 freq = clocks[i].outFrequency*(int(vcoLimits_Hz[0]/clocks[i].outFrequency) + 1);
305 while(freq >= vcoLimits_Hz[0] && freq <= vcoLimits_Hz[1])
306 {
307 //add all output frequency multiples that are in VCO interval
308 availableVCOs.insert( pair<unsigned long, int>(freq, 0));
309 freq += clocks[i].outFrequency;
310 }
311 }
312
313 int bestScore = 0; //score shows how many outputs have integer dividers
314 //calculate scores for all available frequencies
315 for (auto &it : availableVCOs)
316 {
317 for(int i=0; i<clockCount; ++i)
318 {
319 if(clocks[i].outFrequency == 0 || clocks[i].bypass)
320 continue;
321
322 if( (int(it.first) % int(clocks[i].outFrequency)) == 0)
323 it.second = it.second+1;
324 }
325 if(it.second > bestScore)
326 {
327 bestScore = it.second;
328 }
329 }
330 int N(0), M(0);
331 double bestDeviation = 1e9;
332 for(auto it : availableVCOs)
333 {
334 if(it.second == bestScore)
335 {
336 float coef = (it.first / inputFreq);
337 int Ntemp = 1;
338 int Mtemp = int(coef + 0.5);
339 while(inputFreq / Ntemp > PLLlowerLimit)
340 {
341 ++Ntemp;
342 Mtemp = int(coef*Ntemp + 0.5);
343 if(Mtemp > 255)
344 {
345 --Ntemp;
346 Mtemp = int(coef*Ntemp + 0.5);
347 break;
348 }
349 }
350 double deviation = fabs(it.first - inputFreq*Mtemp / Ntemp);
351 if(deviation <= bestDeviation)
352 {
353 bestDeviation = deviation;
354 M = Mtemp;
355 N = Ntemp;
356 }
357 }
358 }
359
360 int mlow = M / 2;
361 int mhigh = mlow + M % 2;
362 double Fvco = inputFreq*M/N; //actual VCO freq
363 lime::debug("M=%i, N=%i, Fvco=%.3f MHz", M, N, Fvco / 1e6);
364 if(Fvco < vcoLimits_Hz[0] || Fvco > vcoLimits_Hz[1])
365 return ReportError(ERANGE, "SetPllFrequency: VCO(%g MHz) out of range [%g:%g] MHz", Fvco/1e6, vcoLimits_Hz[0]/1e6, vcoLimits_Hz[1]/1e6);
366
367 uint16_t M_N_odd_byp = (M%2 << 3) | (N%2 << 1);
368 if(M == 1)
369 M_N_odd_byp |= 1 << 2; //bypass M
370 if(N == 1)
371 M_N_odd_byp |= 1; //bypass N
372 addrs.push_back(0x0026); values.push_back(M_N_odd_byp);
373 int nlow = N / 2;
374 int nhigh = nlow + N % 2;
375 addrs.push_back(0x002A); values.push_back(nhigh << 8 | nlow); //N_high_cnt, N_low_cnt
376 addrs.push_back(0x002B); values.push_back(mhigh << 8 | mlow);
377
378 uint16_t c7_c0_odds_byps = 0x5555; //bypass all C
379 uint16_t c15_c8_odds_byps = 0x5555; //bypass all C
380
381 //set outputs
382 for(int i=0; i<clockCount; ++i)
383 {
384 int C = int(Fvco / clocks[i].outFrequency + 0.5);
385 int clow = C / 2;
386 int chigh = clow + C % 2;
387 if(i < 8)
388 {
389 if(not clocks[i].bypass && C != 1)
390 c7_c0_odds_byps &= ~(1 << (i*2)); //enable output
391 c7_c0_odds_byps |= (C % 2) << (i*2+1); //odd bit
392 }
393 else
394 {
395 if(not clocks[i].bypass && C != 1)
396 c15_c8_odds_byps &= ~(1 << ((i-8)*2)); //enable output
397 c15_c8_odds_byps |= (C % 2) << ((i-8)*2+1); //odd bit
398 }
399 addrs.push_back(0x002E + i); values.push_back(chigh << 8 | clow);
400 clocks[i].rd_actualFrequency = (inputFreq * M / N) / (chigh + clow);
401 }
402 addrs.push_back(0x0027); values.push_back(c7_c0_odds_byps);
403 addrs.push_back(0x0028); values.push_back(c15_c8_odds_byps);
404 if (clockCount != 4 || clocks->index == 3)
405 {
406 addrs.push_back(0x0023); values.push_back(reg23val | PLLCFG_START);
407 }
408 if(WriteRegisters(addrs.data(), values.data(), values.size()) != 0)
409 lime::error("SetPllFrequency: PLL CFG, failed to write registers");
410 addrs.clear(); values.clear();
411
412 t1 = chrono::high_resolution_clock::now();
413 if(boardType == LMS_DEV_LIMESDR_QPCIE) do //wait for config to activate
414 {
415 statusReg = ReadRegister(busyAddr);
416 done = statusReg & 0x1;
417 errorCode = (statusReg >> 7) & 0xFF;
418 t2 = chrono::high_resolution_clock::now();
419 std::this_thread::sleep_for(chrono::milliseconds(10));
420 } while(not done && errorCode == 0 && (t2-t1) < timeout);
421 if(t2 - t1 > timeout)
422 return ReportError(ENODEV, "SetPllFrequency: PLLCFG timeout, busy bit is still 1");
423 if(errorCode != 0)
424 return ReportError(EBUSY, "SetPllFrequency: error configuring PLLCFG");
425
426 for(int i=0; i<clockCount; ++i)
427 {
428 int C = int(Fvco / clocks[i].outFrequency + 0.5);
429 float fOut_MHz = inputFreq/1e6;
430 float Fstep_us = 1 / (8 * fOut_MHz*C);
431 float Fstep_deg = (360 * Fstep_us) / (1 / fOut_MHz);
432 if (clocks[i].findPhase == false)
433 {
434 const int nSteps = 0.49 + clocks[i].phaseShift_deg / Fstep_deg;
435 SetPllClock(clocks[i].index, nSteps, boardType, reg23val);
436 }
437 else
438 {
439 const int nSteps = (360.0 / Fstep_deg)-0.5;
440 const auto timeout = chrono::seconds(3);
441 t1 = chrono::high_resolution_clock::now();
442 t2 = t1;
443 addrs.clear(); values.clear();
444 int cnt_ind = (clocks[i].index + 2) & 0x1F; //C0 index 2, C1 index 3...
445 reg23val &= ~PLLCFG_START;
446 reg23val &= ~(0xF << 8);
447 reg23val |= (cnt_ind << 8);
448 reg23val |= PHCFG_UPDN;
449 reg23val |= PHCFG_MODE;
450
451 addrs.push_back(0x0023); values.push_back(reg23val); //PHCFG_UpDn, CNT_IND
452 addrs.push_back(0x0024); values.push_back(abs(nSteps)); //CNT_PHASE
453 addrs.push_back(0x0023); values.push_back(reg23val | PHCFG_START);
454
455 if (WriteRegisters(addrs.data(), values.data(), values.size()) != 0)
456 lime::error( "SetPllFrequency: find phase, failed to write registers");
457 addrs.clear(); values.clear();
458
459 bool done = false;
460 bool error = false;
461
462 t1 = chrono::high_resolution_clock::now();
463 do
464 {
465 uint16_t statusReg = ReadRegister(busyAddr);
466 done = statusReg & 0x4;
467 error = statusReg & 0x08;
468 t2 = chrono::high_resolution_clock::now();
469 std::this_thread::sleep_for(chrono::milliseconds(10));
470 } while (!done && (t2 - t1) < timeout);
471 if (!done && t2 - t1 > timeout)
472 lime::error("SetPllFrequency: timeout, busy bit is still 1");
473 if (error)
474 lime::warning("SetPllFrequency: error configuring phase");
475 addrs.push_back(0x0023); values.push_back(reg23val & ~PHCFG_START);
476 if (WriteRegisters(addrs.data(), values.data(), values.size()) != 0)
477 lime::error("SetPllFrequency: configure FPGA PLL, failed to write registers");
478 return (!done) || error ? -1 : 0;
479 }
480 }
481 return 0;
482 }
483
SetDirectClocking(int clockIndex)484 int FPGA::SetDirectClocking(int clockIndex)
485 {
486 if(not connection)
487 return ReportError(ENODEV, "SetDirectClocking: connection port is NULL");
488 if(not connection->IsOpen())
489 return ReportError(ENODEV, "SetDirectClocking: device not connected");
490
491 uint16_t drct_clk_ctrl_0005 = ReadRegister(0x0005);
492 vector<uint32_t> addres;
493 vector<uint32_t> values;
494 //enable direct clocking
495 addres.push_back(0x0005); values.push_back(drct_clk_ctrl_0005 | (1 << clockIndex));
496 if(WriteRegisters(addres.data(), values.data(), values.size()) != 0)
497 return ReportError(EIO, "SetDirectClocking: failed to write registers");
498 return 0;
499 }
500
501 /** @brief Parses FPGA packet payload into samples
502 */
FPGAPacketPayload2Samples(const uint8_t * buffer,int bufLen,bool mimo,bool compressed,complex16_t ** samples)503 int FPGA::FPGAPacketPayload2Samples(const uint8_t* buffer, int bufLen, bool mimo, bool compressed, complex16_t** samples)
504 {
505 if(compressed) //compressed samples
506 {
507 int16_t sample;
508 int collected = 0;
509 for(int b=0; b<bufLen;collected++)
510 {
511 //I sample
512 sample = buffer[b++];
513 sample |= (buffer[b] << 8);
514 sample <<= 4;
515 samples[0][collected].i = sample >> 4;
516 //Q sample
517 sample = buffer[b++];
518 sample |= buffer[b++] << 8;
519 samples[0][collected].q = sample >> 4;
520 if (mimo)
521 {
522 //I sample
523 sample = buffer[b++];
524 sample |= (buffer[b] << 8);
525 sample <<= 4;
526 samples[1][collected].i = sample >> 4;
527 //Q sample
528 sample = buffer[b++];
529 sample |= buffer[b++] << 8;
530 samples[1][collected].q = sample >> 4;
531 }
532 }
533 return collected;
534 }
535
536 if (mimo) //uncompressed samples
537 {
538 complex16_t* ptr = (complex16_t*)buffer;
539 const int collected = bufLen/sizeof(complex16_t)/2;
540 for(int i=0; i<collected;i++)
541 {
542 samples[0][i] = *ptr++;
543 samples[1][i] = *ptr++;
544 }
545 return collected;
546 }
547
548 memcpy(samples[0],buffer,bufLen);
549 return bufLen/sizeof(complex16_t);
550 }
551
Samples2FPGAPacketPayload(const complex16_t * const * samples,int samplesCount,bool mimo,bool compressed,uint8_t * buffer)552 int FPGA::Samples2FPGAPacketPayload(const complex16_t* const* samples, int samplesCount, bool mimo, bool compressed, uint8_t* buffer)
553 {
554 if(compressed)
555 {
556 int b=0;
557 for(int src=0; src<samplesCount; ++src)
558 {
559 buffer[b++] = samples[0][src].i;
560 buffer[b++] = ((samples[0][src].i >> 8) & 0x0F) | (samples[0][src].q << 4);
561 buffer[b++] = samples[0][src].q >> 4;
562 if (mimo)
563 {
564 buffer[b++] = samples[1][src].i;
565 buffer[b++] = ((samples[1][src].i >> 8) & 0x0F) | (samples[1][src].q << 4);
566 buffer[b++] = samples[1][src].q >> 4;
567 }
568 }
569 return b;
570 }
571
572 if (mimo)
573 {
574 complex16_t* ptr = (complex16_t*)buffer;
575 for(int src=0; src<samplesCount; ++src)
576 {
577 *ptr++ = samples[0][src];
578 *ptr++ = samples[1][src];
579 }
580 return samplesCount*2*sizeof(complex16_t);
581 }
582 memcpy(buffer,samples[0],samplesCount*sizeof(complex16_t));
583 return samplesCount*sizeof(complex16_t);
584 }
585
UploadWFM(const void * const * samples,uint8_t chCount,size_t sample_count,StreamConfig::StreamDataFormat format,int epIndex)586 int FPGA::UploadWFM(const void* const* samples, uint8_t chCount, size_t sample_count, StreamConfig::StreamDataFormat format, int epIndex)
587 {
588 bool comp = (epIndex==2 && format!=StreamConfig::FMT_INT12) ? false : true;
589
590 const int samplesInPkt = comp ? samples12InPkt : samples16InPkt;
591 WriteRegister(0xFFFF, 1 << epIndex);
592 WriteRegister(0x000C, chCount == 2 ? 0x3 : 0x1); //channels 0,1
593 WriteRegister(0x000E, comp ? 0x2 : 0x0); //16bit samples
594
595 uint16_t regValue = ReadRegister(0x000D);
596 regValue |= 0x4;
597 WriteRegister(0x000D, regValue);
598
599 lime::FPGA_DataPacket pkt;
600 size_t samplesUsed = 0;
601 int cnt = sample_count;
602
603 const complex16_t* const* src = (const complex16_t* const*)samples;
604 const lime::complex16_t** batch = new const lime::complex16_t*[chCount];
605 lime::complex16_t** samplesShort = new lime::complex16_t*[chCount];
606 for(unsigned i=0; i<chCount; ++i)
607 samplesShort[i] = nullptr;
608
609 if (format == StreamConfig::FMT_INT16 && comp == true)
610 {
611 for(unsigned i=0; i<chCount; ++i)
612 samplesShort[i] = new lime::complex16_t[sample_count];
613 for (int ch = 0; ch < chCount; ch++)
614 for(size_t i=0; i < sample_count; ++i)
615 {
616 samplesShort[ch][i].i = src[ch][i].i >> 4;
617 samplesShort[ch][i].q = src[ch][i].q >> 4;
618 }
619 src = samplesShort;
620 }
621 else if(format == StreamConfig::FMT_FLOAT32)
622 {
623 const float mult = comp ? 2047.0f : 32767.0f;
624 for(unsigned i=0; i<chCount; ++i)
625 samplesShort[i] = new lime::complex16_t[sample_count];
626
627 const float* const* samplesFloat = (const float* const*)samples;
628 for (int ch = 0; ch < chCount; ch++)
629 for(size_t i=0; i < sample_count; ++i)
630 {
631 samplesShort[ch][i].i = samplesFloat[ch][2*i]*mult;
632 samplesShort[ch][i].q = samplesFloat[ch][2*i+1]*mult;
633 }
634 src = samplesShort;
635 }
636
637 while(cnt > 0)
638 {
639 pkt.counter = 0;
640 pkt.reserved[0] = 0;
641 int samplesToSend = cnt > samplesInPkt/chCount ? samplesInPkt/chCount : cnt;
642
643 for(unsigned i=0; i<chCount; ++i)
644 batch[i] = &src[i][samplesUsed];
645 samplesUsed += samplesToSend;
646
647 int bufPos = Samples2FPGAPacketPayload(batch, samplesToSend, chCount==2, comp, pkt.data);
648 int payloadSize = (bufPos / 4) * 4;
649 if(bufPos % 4 != 0)
650 lime::warning("Packet samples count not multiple of 4");
651 pkt.reserved[2] = (payloadSize >> 8) & 0xFF; //WFM loading
652 pkt.reserved[1] = payloadSize & 0xFF; //WFM loading
653 pkt.reserved[0] = 0x1 << 5; //WFM loading
654
655 long bToSend = 16+payloadSize;
656 if (connection->SendData((const char*)&pkt,bToSend,epIndex,500)!=bToSend)
657 break;
658 cnt -= samplesToSend;
659 }
660 delete[] batch;
661 for(unsigned i=0; i<chCount; ++i)
662 if (samplesShort[i])
663 delete [] samplesShort[i];
664 delete[] samplesShort;
665
666 /*Give some time to load samples to FPGA*/
667 std::this_thread::sleep_for(std::chrono::milliseconds(500));
668 connection->AbortSending(epIndex);
669 if(cnt == 0)
670 return 0;
671 else
672 return ReportError(-1, "Failed to upload waveform");
673 }
674
675
676 /** @brief Configures FPGA PLLs to LimeLight interface frequency
677 */
SetInterfaceFreq(double txRate_Hz,double rxRate_Hz,double txPhase,double rxPhase,int channel)678 int FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, double txPhase, double rxPhase, int channel)
679 {
680 lime::FPGA::FPGA_PLL_clock clocks[2];
681 int status = 0;
682
683 const uint32_t addr = (0x02A<<16);
684 uint32_t val;
685 val = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFD; //msbit 1=SPI write
686 connection->WriteLMS7002MSPI(&val, 1, channel);
687 connection->ReadLMS7002MSPI(&addr, &val, 1, channel);
688 bool bypassTx = (val&0xF0) == 0x00;
689 bool bypassRx = (val&0x0F) == 0x0D;
690
691 if (rxRate_Hz >= 5e6)
692 {
693 clocks[0].index = 0;
694 clocks[0].outFrequency = bypassRx ? 2*rxRate_Hz:rxRate_Hz;
695 clocks[1].index = 1;
696 clocks[1].outFrequency = bypassRx ? 2*rxRate_Hz:rxRate_Hz;
697 clocks[1].phaseShift_deg = rxPhase;
698 status = SetPllFrequency(1, rxRate_Hz, clocks, 2);
699 }
700 else
701 status = SetDirectClocking(1);
702
703 if (txRate_Hz >= 5e6)
704 {
705 clocks[0].index = 0;
706 clocks[0].outFrequency = bypassTx ? 2*txRate_Hz:txRate_Hz;
707 clocks[1].index = 1;
708 clocks[1].outFrequency = bypassTx ? 2*txRate_Hz:txRate_Hz;
709 clocks[1].phaseShift_deg = txPhase;
710 status |= SetPllFrequency(0, txRate_Hz, clocks, 2);
711 }
712 else
713 status |= SetDirectClocking(0);
714 return status;
715 }
716
717 /** @brief Configures FPGA PLLs to LimeLight interface frequency
718 */
SetInterfaceFreq(double txRate_Hz,double rxRate_Hz,int channel)719 int FPGA::SetInterfaceFreq(double txRate_Hz, double rxRate_Hz, int channel)
720 {
721 const int pll_ind = (channel == 1) ? 2 : 0;
722 int status = 0;
723 uint32_t reg20;
724 bool bypassTx = false;
725 bool bypassRx = false;
726 const double rxPhC1 = 89.46;
727 const double rxPhC2 = 1.24e-6;
728 const double txPhC1 = 89.61;
729 const double txPhC2 = 2.71e-7;
730
731 const std::vector<uint32_t> spiAddr = { 0x021, 0x022, 0x023, 0x024, 0x027, 0x02A, 0x82,
732 0x400, 0x40C, 0x40B, 0x400, 0x40B, 0x400};
733 const int bakRegCnt = spiAddr.size() - 4;
734
735 bool phaseSearch = false;
736 //if (!(mStreamers.size() > channel && (mStreamers[channel]->rxRunning || mStreamers[channel]->txRunning)))
737 if(rxRate_Hz >= 5e6 && txRate_Hz >= 5e6)
738 {
739 uint32_t addr[3] = {0, 1, 2};
740 uint32_t vals[3];
741 ReadRegisters(addr,vals,3);
742 vals[1] = (vals[1]<<8)|vals[2];
743 if ((vals[0]==0xE && vals[1]>0x20E)||(vals[0]==0xF && vals[1]>0x206)||(vals[0]==0x10 && vals[1]>0x102)||vals[0]==0x17)
744 phaseSearch = true;
745 }
746
747 if (!phaseSearch)
748 return SetInterfaceFreq(txRate_Hz, rxRate_Hz, txPhC1 + txPhC2 * txRate_Hz, rxPhC1 + rxPhC2 * rxRate_Hz, channel);
749
750 std::vector<uint32_t> dataRdA;
751 std::vector<uint32_t> dataRdB;
752 std::vector<uint32_t> dataWr;
753
754 dataWr.resize(spiAddr.size());
755 dataRdA.resize(bakRegCnt);
756 dataRdB.clear();
757 //backup registers
758 dataWr[0] = (uint32_t(0x0020) << 16);
759 connection->ReadLMS7002MSPI(dataWr.data(), ®20, 1, channel);
760
761 dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFD; //msbit 1=SPI write
762 connection->WriteLMS7002MSPI(dataWr.data(), 1, channel);
763
764 for (int i = 0; i < bakRegCnt; ++i)
765 dataWr[i] = (spiAddr[i] << 16);
766 connection->ReadLMS7002MSPI(dataWr.data(),dataRdA.data(), bakRegCnt, channel);
767
768 {
769 const uint32_t addr = (0x02A<<16);
770 uint32_t val;
771 connection->ReadLMS7002MSPI(&addr, &val, 1, channel);
772 bypassTx = (val&0xF0) == 0x00;
773 bypassRx = (val&0x0F) == 0x0D;
774 }
775
776 dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFE; //msbit 1=SPI write
777 connection->WriteLMS7002MSPI(dataWr.data(), 1, channel);
778
779 for (int i = 0; i < bakRegCnt; ++i)
780 if (spiAddr[i] >= 0x100)
781 dataRdB.push_back(spiAddr[i] << 16);
782 connection->ReadLMS7002MSPI(dataRdB.data(), dataRdB.data(), dataRdB.size(), channel);
783
784 dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFF; //msbit 1=SPI write
785 connection->WriteLMS7002MSPI(dataWr.data(), 1, channel);
786
787 {
788 std::vector<uint32_t> spiData = { 0x0E9F, 0x0FFF, 0x5550, 0xE4E4, 0xE4E4, 0x0086, 0x8001,
789 0x028D, 0x00FF, 0x5555, 0x02CD, 0xAAAA, 0x02ED};
790 if (bypassRx)spiData[5] = 0xD;
791 //Load test config
792 const int setRegCnt = spiData.size();
793 for (int i = 0; i < setRegCnt; ++i)
794 dataWr[i] = (1 << 31) | (uint32_t(spiAddr[i]) << 16) | spiData[i]; //msbit 1=SPI write
795 connection->WriteLMS7002MSPI(dataWr.data(), setRegCnt, channel);
796 }
797
798 bool phaseSearchSuccess = false;
799 lime::FPGA::FPGA_PLL_clock clocks[2];
800
801 for (int i = 0; i < 10; i++) //attempt phase search 10 times
802 {
803 clocks[0].index = 1;
804 clocks[0].outFrequency = bypassRx ? 2*rxRate_Hz : rxRate_Hz;
805 clocks[0].phaseShift_deg = rxPhC1 + rxPhC2 * rxRate_Hz;
806 clocks[0].findPhase = true;
807 clocks[1] = clocks[0];
808 if (SetPllFrequency(pll_ind+1, rxRate_Hz, clocks, 2)==0)
809 {
810 phaseSearchSuccess = true;
811 break;
812 }
813 }
814
815 if (!phaseSearchSuccess)
816 {
817 lime::error("LML RX phase search FAIL");
818 status = -1;
819 clocks[0].index = 0;
820 clocks[0].phaseShift_deg = 0;
821 clocks[0].findPhase = false;
822 clocks[1].findPhase = false;
823 SetPllFrequency(pll_ind+1, rxRate_Hz, clocks, 2);
824 }
825
826 {
827 std::vector<uint32_t> spiData = {0x0E9F, 0x0FFF, 0x5550, 0xE4E4, 0xE4E4, 0x0484, 0x8001};
828 if (bypassTx)spiData[5] ^= 0x80;
829 if (bypassRx)spiData[5] ^= 0x9;
830 WriteRegister(0xFFFF, 1 << channel);
831 WriteRegister(0x000A, 0x0000);
832 //Load test config
833 const int setRegCnt = spiData.size();
834 for (int i = 0; i < setRegCnt; ++i)
835 dataWr[i] = (1 << 31) | (uint32_t(spiAddr[i]) << 16) | spiData[i]; //msbit 1=SPI write
836 connection->WriteLMS7002MSPI(dataWr.data(), setRegCnt, channel);
837 }
838
839 phaseSearchSuccess = false;
840 for (int i = 0; i < 10; i++) //attempt phase search 10 times
841 {
842 clocks[0].index = 1;
843 clocks[0].outFrequency = bypassTx ? 2*txRate_Hz:txRate_Hz;
844 clocks[0].phaseShift_deg = txPhC1 + txPhC2 * txRate_Hz;
845 clocks[0].findPhase = true;
846 clocks[1] = clocks[0];
847 WriteRegister(0x000A, 0x0200);
848 if (SetPllFrequency(pll_ind, txRate_Hz, clocks, 2)==0)
849 {
850 phaseSearchSuccess = true;
851 break;
852 }
853 }
854
855 if (!phaseSearchSuccess)
856 {
857 lime::error("LML TX phase search FAIL");
858 status = -1;
859 clocks[0].index = 0;
860 clocks[0].phaseShift_deg = 0;
861 clocks[0].findPhase = false;
862 clocks[1].findPhase = false;
863 SetPllFrequency(pll_ind, txRate_Hz, clocks, 2);
864 }
865
866 //Restore registers
867 dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFD; //msbit 1=SPI write
868 connection->WriteLMS7002MSPI(dataWr.data(), 1, channel);
869 for (int i = 0; i < bakRegCnt; ++i)
870 dataWr[i] = (1 << 31) | (uint32_t(spiAddr[i]) << 16) | dataRdA[i]; //msbit 1=SPI write
871 connection->WriteLMS7002MSPI(dataWr.data(), bakRegCnt, channel);
872 dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | 0xFFFE; //msbit 1=SPI write
873 connection->WriteLMS7002MSPI(dataWr.data(), 1, channel);
874
875 int k = 0;
876 for (int i = 0; i < bakRegCnt; ++i)
877 if (spiAddr[i] >= 0x100){
878 dataWr[k] = (1 << 31) | (uint32_t(spiAddr[i]) << 16) | dataRdB[k]; //msbit 1=SPI write
879 k++;
880 }
881 connection->WriteLMS7002MSPI(dataWr.data(), k, channel);
882 dataWr[0] = (1 << 31) | (uint32_t(0x0020) << 16) | reg20; //msbit 1=SPI write
883 connection->WriteLMS7002MSPI(dataWr.data(), 1, channel);
884 WriteRegister(0x000A, 0);
885
886 return status;
887 }
888
ReadRawStreamData(char * buffer,unsigned length,int epIndex,int timeout_ms)889 int FPGA::ReadRawStreamData(char* buffer, unsigned length, int epIndex, int timeout_ms)
890 {
891 WriteRegister(0xFFFF, 1 << epIndex);
892 StopStreaming();
893 connection->ResetStreamBuffers();
894 WriteRegister(0x0008, 0x0100 | 0x2);
895 WriteRegister(0x0007, 1);
896 StartStreaming();
897 int totalBytesReceived = connection->ReceiveData(buffer,length, epIndex, timeout_ms);
898 StopStreaming();
899 connection->AbortReading(epIndex);
900 return totalBytesReceived;
901 }
902
DetectRefClk(double fx3Clk)903 double FPGA::DetectRefClk(double fx3Clk)
904 {
905 const double fx3Cnt = 16777210; //fixed fx3 counter in FPGA
906 const double clkTbl[] = { 10e6, 30.72e6, 38.4e6, 40e6, 52e6 };
907 const uint32_t addr[] = { 0x61, 0x63 };
908 const uint32_t vals[] = { 0x0, 0x0 };
909 if (WriteRegisters(addr, vals, 2) != 0)
910 return -1;
911
912 auto start = std::chrono::steady_clock::now();
913 if (WriteRegister(0x61, 0x4) != 0)
914 return -1;
915
916 while (1) //wait for test to finish
917 {
918 int completed = ReadRegister(0x65);
919 if (completed < 0)
920 return -1;
921 if (completed & 0x4)
922 break;
923
924 auto end = std::chrono::steady_clock::now();
925 std::chrono::duration<double> elapsed_seconds = end - start;
926 if (elapsed_seconds.count() > 0.5) //timeout
927 return -1;
928 }
929
930 const uint32_t addr2[] = { 0x72, 0x73 };
931 uint32_t vals2[2];
932 if (ReadRegisters(addr2, vals2, 2) != 0)
933 return -1;
934
935 double count = (vals2[0] | (vals2[1] << 16)); //cock counter
936 count *= fx3Clk / fx3Cnt; //estimate ref clock based on FX3 Clock
937 lime::debug("Estimated reference clock %1.4f MHz", count/1e6);
938 unsigned i = 0;
939 double delta = 100e6;
940
941 while (i < sizeof(clkTbl) / sizeof(*clkTbl))
942 if (delta < fabs(count - clkTbl[i]))
943 break;
944 else
945 delta = fabs(count - clkTbl[i++]);
946
947 if (i == 0)
948 return -1;
949 lime::info("Reference clock %1.2f MHz", clkTbl[i - 1] / 1e6);
950 return clkTbl[i - 1];
951 }
952
953 } //namespace lime
954