-
Notifications
You must be signed in to change notification settings - Fork 15
/
rf_xlnx_rfdc_imp.c
2109 lines (1856 loc) · 80.2 KB
/
rf_xlnx_rfdc_imp.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2022 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "../rf_helper.h"
#include "../rf_plugin.h"
#include "rf_xlnx_rfdc_imp.h"
#include "srsran/srsran.h"
#include "xrfdc.h"
#include "xrfdc_clk.h"
#include <sys/time.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <pthread.h>
enum LMK04208_CLK_SRC {
INTERNAL_CLK_REF = 0,
EXTERNAL_CLK_REF
};
unsigned int LMK04208_CKin[2][26] = {
{0x00160040,0x80140320,0x80140321,0x80140322,
0xC0140023,0x40140024,0x80141E05,0x03300006,0x01300007,0x06010008,
0x55555549,0x9102410A,0x0401100B,0x1B0C006C,0x2302886D,0x0200000E,
0x8000800F,0xC1550410,0x00000058,0x02C9C419,0x8FA8001A,0x10001E1B,
0x0021201C,0x0180033D,0x0200033E,0x003F001F },
{0x00160040,0x00143200,0x00143201,0x00140322,
0xC0140023,0x40140024,0x80141E05,0x01100006,0x01100007,0x06010008,
0x55555549,0x9102410A,0x0401100B,0x1B0C006C,0x2302884D,0x0200000E,
0x8000800F,0xC1550410,0x00000058,0x02C9C419,0x8FA8001A,0x10001F5B,
0x0021801C,0x0180033D,0x0200033E,0x003F001F }};
const unsigned int RFDC_DEVICE_ID = 0;
const unsigned int I2CBUS = 12;
const double RFDC_REF_SAMPLE_FREQ = 245.76f;
const double RFDC_REF_SAMPLE_FREQ_KHZ = 245760;
const double RFDC_PLL_FREQ = 1966.08f;
const unsigned int MIN_DATA_BUFFER_SIZE = 1000;
const unsigned int METADATA_NSAMPLES = 8; // 8 32bit samples
const double DEFAULT_TXRX_SRATE = 1920000.0f;
static cf_t zero_mem[64*1024] = {0};
static int lates = 0;
static int rx_data_buffer_size = MIN_DATA_BUFFER_SIZE;
static int tx_data_buffer_size = MIN_DATA_BUFFER_SIZE;
#define DEVNAME_RFDC "RFdc"
#define CONVERT_BUFFER_SIZE (1024*1024)
#define common_preamble1 0xbbbbaaaa
#define common_preamble2 0xddddcccc
#define common_preamble3 0xffffeeee
#define common_preamble3_short \
0x0000ffee
#define time_preamble1 0xabcddcba
#define time_preamble2 0xfedccdef
#define time_preamble3 0xdfcbaefd
#define PKT_HEADER_MAGIC 0x12345678
//#define PRINT_TIMESTAMPS 1
typedef enum srs_dma_dir {
RX_DMA,
TX_DMA
} srs_dma_direction;
typedef enum srs_dma_buffer_pool_size {
SMALL_BUFF_POOL_SIZE = 4,
DEFAULT_BUFF_POOL_SIZE = 8
} srs_dma_pool_size_t;
/* structure holding buffers allocation request */
struct buffers_alloc_request {
unsigned int num_of_buffers;
unsigned int buffer_size;
};
typedef struct dma_buffer_pool_desc {
unsigned num_of_buffers;
unsigned buffer_size;
unsigned long **addresses;
} dma_buffers_desc_t;
typedef struct user_dma_buf_pointer {
int id;
int tx_size;
} user_dma_buf_ptr;
struct dma_buffers {
int dma_device_fd; // File descriptor for interfacing srs_dma device
volatile uint32_t* ts_enabler_mem; // Pointer to registers memory of 'adc_timestamp_enabler_packetizer' block
dma_buffers_desc_t dma_buffer_pool_desc; // Pool of DMA buffers
srs_dma_direction direction; // RX or TX operation
size_t sample_size; // Specifies size of a sample (depends of number of channels used by the streamer)
bool dma_queue_enabled; // Specifies whether buffer queue is enabled and DMA is active
user_dma_buf_ptr current_user_buffer; // Descriptor of the buffer owned by the user
};
typedef struct dma_buffers dma_buffers_t;
#define PAGE_SHIFT 12
#define SRS_DMA_IOC_MAGIC 'V'
#define SRS_DMA_ALLOC_BUFFERS _IOW(SRS_DMA_IOC_MAGIC, 0, struct buffers_alloc_request)
#define SRS_DMA_DESTROY_BUFFERS _IO(SRS_DMA_IOC_MAGIC, 1)
// rx
#define SRS_DMA_GET_RX_BUFFER _IOR(SRS_DMA_IOC_MAGIC, 2, struct user_dma_buf_pointer)
#define SRS_DMA_PUT_RX_BUFFER _IOW(SRS_DMA_IOC_MAGIC, 3, struct user_dma_buf_pointer)
// tx
#define SRS_DMA_GET_TX_BUFFER _IOR(SRS_DMA_IOC_MAGIC, 4, struct user_dma_buf_pointer)
#define SRS_DMA_SEND_TX_BUFFER _IOWR(SRS_DMA_IOC_MAGIC, 5, struct user_dma_buf_pointer)
// common
#define SRS_DMA_ENABLE_QUEUE _IO(SRS_DMA_IOC_MAGIC, 6)
#define SRS_DMA_DISABLE_QUEUE _IO(SRS_DMA_IOC_MAGIC, 7)
static void *reader_thread(void *arg);
static void *writer_thread(void *arg);
typedef struct {
uint64_t magic;
uint64_t timestamp;
uint32_t nof_samples;
bool end_of_burst;
} tx_header_t;
typedef struct {
void* parent;
long long _fs_hz;
int16_t _conv_buffer[CONVERT_BUFFER_SIZE];
ssize_t buf_count;
uint32_t nof_channels;
long buffer_size;
bool stream_active;
int items_in_buffer;
uint32_t tx_segment_time_len;
float secs;
float frac_secs;
int metadata_samples;
int preamble_location;
pthread_mutex_t stream_mutex;
pthread_cond_t stream_cvar;
pthread_t thread;
bool thread_completed;
tx_header_t prev_header;
srsran_ringbuffer_t ring_buffer;
struct dma_buffers _buf;
} xrfdc_streamer;
typedef struct {
bool use_timestamps;
xrfdc_streamer tx_streamer;
xrfdc_streamer rx_streamer;
srsran_rf_error_handler_t iio_error_handler;
void* iio_error_handler_arg;
volatile unsigned int* memory_map_ptr;
srsran_rf_info_t info;
XRFdc RFdcInst; // RFdc driver instance
struct metal_device* phy_deviceptr; // libmetal device descriptor
} rf_xrfdc_handler_t;
static int allocate_buffer_pool(dma_buffers_t *_buf,
const srs_dma_pool_size_t num_of_buffers,
const uint32_t buffer_length)
{
int i = 0, ret = 0;
int fd = _buf->dma_device_fd;
struct buffers_alloc_request alloc_req = {0};
alloc_req.num_of_buffers = num_of_buffers;
alloc_req.buffer_size = buffer_length * _buf->sample_size; // must be specified in Bytes
// allocate array holding DMA buffer addresses (position in array corresponds to buffer ID)
_buf->dma_buffer_pool_desc.addresses = malloc(num_of_buffers * sizeof(unsigned long *));
if (!_buf->dma_buffer_pool_desc.addresses) {
ERROR("failed to allocate memory for dma_buffer_pool_desc");
goto err_out;
}
// ask the driver to allocate memory suitable for DMA
ret = ioctl(fd, SRS_DMA_ALLOC_BUFFERS, &alloc_req);
if (ret < 0){
ERROR("SRS_DMA_ALLOC_BUFFERS ioctl() failed, errno=%d", errno);
return -1;
}
//request an address of each dma buffer from the kernel driver using mmap call
for (i = 0; i < num_of_buffers; i++) {
_buf->dma_buffer_pool_desc.addresses[i] =
(unsigned long *) mmap(0, buffer_length * _buf->sample_size,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, i << PAGE_SHIFT);
if (!_buf->dma_buffer_pool_desc.addresses[i]) {
ERROR("Error mapping dma buffer with id=%d", i);
goto err_out;
}
}
_buf->dma_buffer_pool_desc.buffer_size = buffer_length;
_buf->current_user_buffer.id = -1;
return 0;
err_out:
ioctl(fd, SRS_DMA_DESTROY_BUFFERS);
return -1;
}
static int open_srs_dma_device(xrfdc_streamer* streamer, bool is_rx_dma, uint32_t nof_channels)
{
char dev_name[16] = {0};
snprintf(dev_name, sizeof(dev_name), "/dev/srs_%cx_dma", is_rx_dma ? 'r' : 't');
int fd = open(dev_name, O_RDWR);
if (fd < 0) {
ERROR("Error opening device '%s'", dev_name);
return -1;
}
streamer->_buf.dma_device_fd = fd;
uint32_t nof_hw_rx_channels = 0;
// For ADC path map registers memory of the adc_timestamp_enabler_packetizer
if (is_rx_dma) {
int devmem;
if ((devmem = open("/dev/mem", O_RDWR | O_SYNC)) == -1) {
ERROR("Error accessing memory-maped registers in FPGA");
return -1;
}
streamer->_buf.ts_enabler_mem =
(uint32_t*)mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, devmem, 0xA0050000);
if (!streamer->_buf.ts_enabler_mem) {
ERROR("Error mapping ADC timestamp enabler registers");
return -1;
}
rf_xrfdc_handler_t* h = (rf_xrfdc_handler_t*)streamer->parent;
nof_hw_rx_channels = h->memory_map_ptr[264];
if (!nof_hw_rx_channels) {
INFO("Warning: nof RX DMA channels reported by FPGA is 0, automatically setting it to 1");
nof_hw_rx_channels = 1;
}
if (nof_channels != nof_hw_rx_channels) {
ERROR("Requested number of RX channels doesn't match FPGA implementation (supports %u channels)",
nof_hw_rx_channels);
return -1;
}
}
streamer->nof_channels = (!is_rx_dma) ? 1 : nof_channels;
streamer->_buf.sample_size = is_rx_dma ? sizeof(uint16_t) * 2 * nof_channels : sizeof(uint16_t) * 2;
streamer->_buf.direction = (is_rx_dma) ? RX_DMA : TX_DMA;
streamer->_buf.dma_queue_enabled = false;
return 0;
}
static void srs_dma_cleanup_resources(dma_buffers_t* buf)
{
if (!buf) {
ERROR("%s called with buffer object = NULL", __func__);
return;
}
// unmap DMA buffers
uint32_t buffer_size = buf->dma_buffer_pool_desc.buffer_size;
if (buf->dma_buffer_pool_desc.addresses) {
for (int i = 0; i < buf->dma_buffer_pool_desc.num_of_buffers; i++) {
munmap((void*)buf->dma_buffer_pool_desc.addresses[i], buffer_size * 4);
}
free(buf->dma_buffer_pool_desc.addresses);
buf->dma_buffer_pool_desc.addresses = NULL;
buf->dma_buffer_pool_desc.num_of_buffers = 0;
buf->dma_buffer_pool_desc.buffer_size = 0;
}
buf->dma_queue_enabled = false;
}
static void close_srs_dma_device(xrfdc_streamer *streamer)
{
if (!streamer) {
ERROR("%s called with streamer object = NULL", __func__);
return;
}
srs_dma_cleanup_resources(&streamer->_buf);
// close file descriptor
close(streamer->_buf.dma_device_fd);
// for ADC path, unmap registers memory
if (streamer->_buf.direction == RX_DMA) {
munmap((void *) streamer->_buf.ts_enabler_mem, 0x1000);
}
}
static int srs_dma_destroy_buffers(dma_buffers_t *buf)
{
int ret = 0;
srs_dma_cleanup_resources(buf);
ret = ioctl(buf->dma_device_fd, SRS_DMA_DESTROY_BUFFERS);
if (ret < 0) {
ERROR("SRS_DMA_DESTROY_BUFFERS ioctl() failed, errno=%d", errno);
}
return ret;
}
static int srs_dma_allocate_buffers(dma_buffers_t *buf, const unsigned buf_length)
{
if (allocate_buffer_pool(buf, DEFAULT_BUFF_POOL_SIZE, buf_length) < 0) {
return -1;
}
if (buf->direction == TX_DMA) {
// get first free data buffer from the DMA pool
struct user_dma_buf_pointer user_dma_buf_info = {};
int ret = ioctl(buf->dma_device_fd, SRS_DMA_GET_TX_BUFFER, &user_dma_buf_info);
if (ret < 0) {
ERROR("SRS_DMA_GET_TX_BUFFER ioctl() failed, errno=%d", errno);
return ret;
}
memcpy(&buf->current_user_buffer, &user_dma_buf_info, sizeof(user_dma_buf_info));
}
return 0;
}
static int srs_dma_start_streaming(dma_buffers_t *buf)
{
int ret = 0;
ret = ioctl(buf->dma_device_fd, SRS_DMA_ENABLE_QUEUE);
if (ret < 0) {
ERROR("SRS_DMA_ENABLE_QUEUE ioctl() failed, errno=%d", errno);
return ret;
}
// for ADC path, enable "adc_timestamp_enabler_packetizer" IP
if (buf->direction == RX_DMA) {
buf->ts_enabler_mem[0] = buf->dma_buffer_pool_desc.buffer_size;
buf->ts_enabler_mem[1] = 1; // enable TS insertion and packetizing
}
buf->dma_queue_enabled = true;
return ret;
}
static int srs_dma_stop_streaming(dma_buffers_t* buf)
{
int ret = 0;
if (!buf->dma_queue_enabled)
return 0;
// disable TS insertion and packetizing
if (buf->direction == RX_DMA) {
buf->ts_enabler_mem[1] = 0;
}
ret = ioctl(buf->dma_device_fd, SRS_DMA_DISABLE_QUEUE);
if (ret < 0) {
ERROR("SRS_DMA_DISABLE_QUEUE ioctl() failed, errno=%d", errno);
}
// reset ADC fifo
if (buf->direction == RX_DMA) {
INFO("RF_RFdc: resetting RX FIFO");
while (buf->ts_enabler_mem[1]) {
usleep(100);
}
// reset only after packetizing logic was stopped
buf->ts_enabler_mem[2] = 1;
}
buf->dma_queue_enabled = false;
return ret;
}
static void* srs_dma_get_data_ptr(dma_buffers_t* buf)
{
unsigned buf_id = buf->current_user_buffer.id;
return buf->dma_buffer_pool_desc.addresses[buf_id];
}
static int srs_dma_receive_data(dma_buffers_t* buf)
{
struct user_dma_buf_pointer user_dma_buf_info = {};
// if the user owns valid buffer - return it to DMA device
if (buf->current_user_buffer.id != -1) {
int ret = ioctl(buf->dma_device_fd, SRS_DMA_PUT_RX_BUFFER, &buf->current_user_buffer);
if (ret < 0) {
INFO("SRS_DMA_PUT_RX_BUFFER ioctl() failed, errno=%d", errno);
return ret;
}
}
// get data buffer from DMA
int ret = ioctl(buf->dma_device_fd, SRS_DMA_GET_RX_BUFFER, &user_dma_buf_info);
if (ret < 0) {
INFO("SRS_DMA_GET_RX_BUFFER ioctl() failed, errno=%d", errno);
return ret;
}
memcpy(&buf->current_user_buffer, &user_dma_buf_info, sizeof(user_dma_buf_info));
return buf->dma_buffer_pool_desc.buffer_size;
}
static int srs_dma_send_data(dma_buffers_t* buf, const int tx_size)
{
struct user_dma_buf_pointer user_dma_buf_info = buf->current_user_buffer;
user_dma_buf_info.tx_size = tx_size; // Bytes
// send data buffer to DMA, obtain next buffer ID through the same parameter
int ret = ioctl(buf->dma_device_fd, SRS_DMA_SEND_TX_BUFFER, &user_dma_buf_info);
if (ret < 0) {
INFO("SRS_DMA_SEND_TX_BUFFER ioctl() failed, errno=%d", errno);
return ret;
}
memcpy(&buf->current_user_buffer, &user_dma_buf_info, sizeof(user_dma_buf_info));
return tx_size;
}
int refill_buffer(xrfdc_streamer* streamer, ssize_t* items_in_buffer)
{
ssize_t nbytes_rx = 0;
int nsamples = srs_dma_receive_data(&streamer->_buf);
if (nsamples < 0) {
*items_in_buffer = 0;
return nsamples;
}
// on success srs_dma_receive_data() returns number of received IQ samples in bytes
nbytes_rx = nsamples * streamer->_buf.sample_size;
*items_in_buffer = nsamples;
return nbytes_rx;
}
static void log_late(rf_xrfdc_handler_t *h, bool is_rx) {
if (h->iio_error_handler) {
srsran_rf_error_t error;
bzero(&error, sizeof(srsran_rf_error_t));
error.opt = is_rx ? 1 : 0;
error.type = SRSRAN_RF_ERROR_LATE;
h->iio_error_handler(h->iio_error_handler_arg, error);
}
}
void rf_xrfdc_suppress_stdout(void* h)
{
// do nothing
}
void rf_xrfdc_register_error_handler(void *h, srsran_rf_error_handler_t new_handler, void* arg)
{
rf_xrfdc_handler_t *handler = (rf_xrfdc_handler_t*) h;
handler->iio_error_handler = new_handler;
handler->iio_error_handler_arg = arg;
}
bool rf_xrfdc_has_rssi(void *h)
{
return false;
}
float rf_xrfdc_get_rssi(void *h)
{
return 0.0f;
}
const char* rf_xrfdc_devname(void* h)
{
return DEVNAME_RFDC;
}
/*
static void RFdc_IRQ_callback(void *CallBackRef, u32 Type, int Tile, u32 Block, u32 Event)
{
//rf_xrfdc_handler_t *handler = (rf_xrfdc_handler_t*) CallBackRef;
// Check the type of interrupt event
if (Type == XRFDC_DAC_TILE) {
INFO("Interrupt occurred for DAC%d_%d:", Tile, Block);
if (Event & (XRFDC_IXR_FIFOUSRDAT_OF_MASK | XRFDC_IXR_FIFOUSRDAT_UF_MASK)) {
INFO("\tFIFO Actual Overflow");
}
if (Event & (XRFDC_IXR_FIFOMRGNIND_OF_MASK | XRFDC_IXR_FIFOMRGNIND_UF_MASK)){
INFO("\tFIFO Marginal Overflow");
}
if (Event & XRFDC_DAC_IXR_INTP_STG_MASK) {
INFO("\tInterpolation Stages Overflow");
}
if (Event & XRFDC_IXR_QMC_GAIN_PHASE_MASK) {
INFO("\tQMC gain/phase correction has overflowed/saturated");
}
if (Event & XRFDC_IXR_QMC_OFFST_MASK) {
INFO("\tQMC offset correction has overflowed/saturated");
}
} else {
INFO("Interrupt occurred for ADC%d_%d:", Tile, Block);
if(Event & (XRFDC_IXR_FIFOUSRDAT_OF_MASK | XRFDC_IXR_FIFOUSRDAT_UF_MASK)) {
INFO("\tFIFO Actual Overflow");
}
if(Event & (XRFDC_IXR_FIFOMRGNIND_OF_MASK | XRFDC_IXR_FIFOMRGNIND_UF_MASK)){
INFO("\tFIFO Marginal Overflow");
}
if(Event & XRFDC_ADC_IXR_DMON_STG_MASK){
INFO("\tDecimation Stages Overflow");
}
if(Event & XRFDC_ADC_OVR_VOLTAGE_MASK){
INFO("\tADC buffer over voltage event");
}
if(Event & XRFDC_ADC_OVR_RANGE_MASK){
INFO("\tADC over range event");
}
if(Event & XRFDC_ADC_FIFO_OVR_MASK){
INFO("\tRF-ADC/RF-DAC FIFO over/underflow");
}
}
}
*/
static int configure_rfdc_controller(rf_xrfdc_handler_t *handler, const char *clock_source)
{
int Status = 0;
XRFdc *RFdcInstPtr = &handler->RFdcInst;
XRFdc_Config *ConfigPtr = NULL;
XRFdc_IPStatus IPStatusPtr = {};
XRFdc_Mixer_Settings *adcMixerSettings = NULL;
/* Define our desired ADC mixer configuration (mimics what we set in Vivado) */
XRFdc_Mixer_Settings adcMixerSettings_ch0 = {
.CoarseMixFreq = XRFDC_COARSE_MIX_OFF, //we are not using a coarse mixer type
.MixerType = XRFDC_MIXER_TYPE_FINE, //we are using a fine mixer type
.MixerMode = XRFDC_MIXER_MODE_R2C, //we will receive a real signal and return an I/Q pai
.Freq = -491.52, //we want our signal to be centered at 2.4576 GHz (NCO freq) -> 2457.6 (Fc) - 1966.08 MHz (Fc) = 491.52 MHz
.PhaseOffset = 0, //NCO phase = 0
.FineMixerScale = XRFDC_MIXER_SCALE_AUTO, //the fine mixer scale will be auto updated
.EventSource = XRFDC_EVNT_SRC_TILE
};
XRFdc_Mixer_Settings adcMixerSettings_ch1 = {
.CoarseMixFreq = XRFDC_COARSE_MIX_OFF, //we are not using a coarse mixer type
.MixerType = XRFDC_MIXER_TYPE_FINE, //we are using a fine mixer type
.MixerMode = XRFDC_MIXER_MODE_R2C, //we will receive a real signal and return an I/Q pai
.Freq = -433.92, //we want our signal to be centered at 2.400 GHz (NCO freq) -> 2400 (Fc) - 1966.08 MHz (Fc) = 433.92 MHz
.PhaseOffset = 0, //NCO phase = 0
.FineMixerScale = XRFDC_MIXER_SCALE_AUTO, //the fine mixer scale will be auto updated
.EventSource = XRFDC_EVNT_SRC_TILE
};
/* Define our desired DAC mixer configuration (mimics what we set in Vivado) */
XRFdc_Mixer_Settings dacMixerSettings = {
.CoarseMixFreq = XRFDC_COARSE_MIX_OFF, //we are not using a coarse mixer type
.MixerType = XRFDC_MIXER_TYPE_FINE, //we are using a fine mixer type
.MixerMode = XRFDC_MIXER_MODE_C2R, //we will receive an I/Q pair and return a real signal
.Freq = 433.92, //we want our signal to be centered at 2.400 GHz (NCO freq) -> 2400 (Fc) - 1966.08 MHz (Fc) = 433.92 MHz
.PhaseOffset = 0, //NCO phase = 0
.FineMixerScale = XRFDC_MIXER_SCALE_AUTO, //the fine mixer scale will be auto updated
.EventSource = XRFDC_EVNT_SRC_TILE
};
u32 DataWidth = 0;
u32 GetFabricRate = 0;
u32 NyquistZonePtr = 0;
u8 CalibrationMode = 0;
int DataConnectedI = 0;
int DataConnectedQ = 0;
XRFdc_BlockStatus BlockStatus = {};
// look for 'clock source' parameter in the arguments list
u32 ref_clock_source = INTERNAL_CLK_REF;
if (clock_source != NULL) {
if (!strcmp(clock_source, "external")) {
ref_clock_source = EXTERNAL_CLK_REF;
}
}
struct metal_init_params init_param = METAL_INIT_DEFAULTS;
if (metal_init(&init_param)) {
ERROR("ERROR: Failed to run libmetal initialization");
return -1;
}
// Initialize the RFdc driver
ConfigPtr = XRFdc_LookupConfig(RFDC_DEVICE_ID);
if (ConfigPtr == NULL) {
ERROR("ERROR: Couldn't look up RFdc configuration");
return -1;
}
handler->phy_deviceptr = NULL;
Status = XRFdc_RegisterMetal(RFdcInstPtr, RFDC_DEVICE_ID, &handler->phy_deviceptr);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: Failed to register libmetal device");
return -1;
}
INFO("RF_RFdc: RFdc driver successfully registered and mapped to Libmetal");
/* Initializes the controller */
Status = XRFdc_CfgInitialize(RFdcInstPtr, ConfigPtr);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: Failed to initialize RFdc controller");
return -1;
}
INFO("RF_RFdc: RFdc controller successfully initialized");
printf("Configuring LMK04208 to use %s clock source\n", ref_clock_source == EXTERNAL_CLK_REF ? "external" : "internal");
// Configuring the clocks
LMK04208ClockConfig(I2CBUS, &LMK04208_CKin[ref_clock_source]);
// The ADCs expect a 245.76 MHz reference signal (as set in Vivado)
LMX2594ClockConfig(I2CBUS, RFDC_REF_SAMPLE_FREQ_KHZ);
INFO("RF_RFdc: Clock configuration successfully finished");
u16 ADC_Tile = 0;
//u16 ADC_Tile = 1;
u16 DAC_Tile = 1;
// Explicitly wake up ADC tile 0 (does not change Vivado-provided parameters)
Status = XRFdc_StartUp(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: Failed to wake up ADC tile 1");
return -1;
}
INFO("RF_RFdc: ADC tile %d succesfully started up", ADC_Tile);
/*explicitly wake up DAC tile 1 (does not change Vivado-provided parameters)*/
Status = XRFdc_StartUp(RFdcInstPtr, XRFDC_DAC_TILE, DAC_Tile);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: Failed to wake up DAC tile 1");
return -1;
}
INFO("RF_RFdc: DAC tile %d succesfully started up", DAC_Tile);
// Capture the RFdc IP status (to be printed later for a specific tile)
Status = XRFdc_GetIPStatus(RFdcInstPtr, &IPStatusPtr);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: RFdc status reports FAILURE");
return -1;
}
/** ----------------- ADC ------------------------- **
* **
* We'll explicitly configure ADC tile 1, **
* for which we have enabled channels 0 and 1 in Vivado **
** --------------------------------------------------- **/
/** ---------------------------------------*/
/** === Common ADC tile configuration === */
/** ---------------------------------------*/
// Explicitly configure the PLL
// (overriding the parameters provided through Vivado)
Status = XRFdc_DynamicPLLConfig(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, XRFDC_INTERNAL_PLL_CLK, RFDC_REF_SAMPLE_FREQ, RFDC_PLL_FREQ);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: failed to set Dynamic PLL configuration (ADC)");
return -1;
}
INFO("RF_RFdc: PLL succesfully configured for ADC tile %d", ADC_Tile);
// Explicitly enable the ADC FIFO
Status = XRFdc_SetupFIFO(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, 1);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: failed to enable the ADC FIFO");
return -1;
}
INFO("RF_RFdc: ADC FIFO succesfully enabled for ADC tile %d",ADC_Tile);
// Print out the previously captured IP status [related to that ADC tile only]
INFO("RF_RFdc: ADC tile %u status:", ADC_Tile);
INFO("\tRF_RFdc: Tile enabled: %u", IPStatusPtr.ADCTileStatus[ADC_Tile].IsEnabled);
INFO("\tRF_RFdc: Tile state: %u", IPStatusPtr.ADCTileStatus[ADC_Tile].TileState);
INFO("\tRF_RFdc: Tile block status mask: %u", IPStatusPtr.ADCTileStatus[ADC_Tile].BlockStatusMask);
INFO("\tRF_RFdc: Tile power-up state: %u", IPStatusPtr.ADCTileStatus[ADC_Tile].PowerUpState);
INFO("\tRF_RFdc: Tile PLL state: %u", IPStatusPtr.ADCTileStatus[ADC_Tile].PLLState);
// Configure the clock divider for the PL as required
Status = XRFdc_SetFabClkOutDiv(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, XRFDC_FAB_CLK_DIV2);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: Failed to configure ADC tile clock dividers");
return -1;
}
INFO("RF_RFdc: Clock divider for the PL succesfully set to 0x%u (2) for ADC tile %d", XRFDC_FAB_CLK_DIV2, ADC_Tile);
u32 ClockSource = 0;
u16 FabClkDivPtr = 0;
u32 LockStatusPtr = 0;
u8 FIFOEnablePtr = 0;
XRFdc_PLL_Settings PLLSettings = {};
// Print out the clock divider for the PL
Status = XRFdc_GetFabClkOutDiv(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, &FabClkDivPtr);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: GetFabClkOutDiv failed");
return -1;
}
INFO("RF_RFdc: Clock divider for the PL: 0x%u", FabClkDivPtr);
// Print out the clock source
Status = XRFdc_GetClockSource(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, &ClockSource);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: GetClockSource failed");
return -1;
}
INFO("RF_RFdc: ADC clock source: %d", ClockSource);
// Print out the PLL configuration
Status = XRFdc_GetPLLConfig(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, &PLLSettings);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: GetPLLConfig failed");
return -1;
}
INFO("RF_RFdc: PLL configuration:");
INFO("\tRF_RFdc: PLL enabled (%u)", PLLSettings.Enabled);
INFO("\tRF_RFdc: PLL reference clock frequency (%f)", PLLSettings.RefClkFreq);
INFO("\tRF_RFdc: PLL sample rate (%f)", PLLSettings.SampleRate);
INFO("\tRF_RFdc: PLL reference clock divider (%d)", PLLSettings.RefClkDivider);
INFO("\tRF_RFdc: PLL feedback divider (%d)", PLLSettings.FeedbackDivider);
INFO("\tRF_RFdc: PLL output divider (%d)", PLLSettings.OutputDivider);
// Print out the PLL lock status
Status = XRFdc_GetPLLLockStatus(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, &LockStatusPtr);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: GetPLLLockStatus failed");
return -1;
}
INFO("RF_RFdc: PLL lock status: %u", LockStatusPtr);
// Print out the FIFO status
Status = XRFdc_GetFIFOStatus(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, &FIFOEnablePtr);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: GetFIFOStatus failed");
return -1;
}
INFO("RF_RFdc: ADC FIFO status: %u", FIFOEnablePtr);
/** ---------------------------------------------*/
/** === channel specific configuration (ADC) === */
/** ---------------------------------------------*/
for (u16 Block = 0; Block < 4; Block++) {
if (!XRFdc_IsADCBlockEnabled(RFdcInstPtr, ADC_Tile, Block)) {
continue;
}
INFO("RF_RFdc: ADC tile %u channel %u is enabled", ADC_Tile, Block);
// Explicitly set the ADC decimation factor (overriding the parameters provided through Vivado)
Status = XRFdc_SetDecimationFactor(RFdcInstPtr, ADC_Tile, Block, XRFDC_INTERP_DECIM_8X);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: Failed to set ADC decimation factor");
return -1;
}
INFO("RF_RFdc: ADC decimation factor succesfully configured for ADC tile %d channel %d", ADC_Tile, Block);
/** these function calls must be used at startup to initialize the phase of the fine mixer to a valid state */
// Set our desired NCO configuration;
// NOTE: for some reason the vivado-set configuration was not applied or rewritten at some point
adcMixerSettings = (Block == 0) ? &adcMixerSettings_ch0 : &adcMixerSettings_ch1;
Status = XRFdc_SetMixerSettings(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, Block, adcMixerSettings);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: Failed to set ADC NCO settings");
return -1;
}
// Reset NCO phase of the DDC
XRFdc_ResetNCOPhase(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, Block);
//Generate a Tile Event
XRFdc_UpdateEvent(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, Block, XRFDC_EVENT_MIXER);
INFO("RF_RFdc: ADC mixer succesfully configured");
/** end of mixer configuration */
// Explicitly set the Nyquist zone
/* Status = XRFdc_SetNyquistZone(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, Block, XRFDC_EVEN_NYQUIST_ZONE);
if (Status != XRFDC_SUCCESS) {
fprintf(stderr, "ERROR: Failed to set ADC Nyquist Zone\n");
return -1;
}
INFO("RF_RFdc: ADC Nyquist zone succesfully set to 2 (even) for ADC tile %d", ADC_Tile);
*/
Status = XRFdc_SetNyquistZone(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, Block, XRFDC_ODD_NYQUIST_ZONE);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: Failed to set ADC Nyquist Zone");
return -1;
}
INFO("RF_RFdc: ADC Nyquist zone succesfully set to 1 (odd) for ADC tile %d", ADC_Tile);
// Read the number of samples per axi4-stream cycle
Status = XRFdc_GetFabRdVldWords(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, Block, &GetFabricRate);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: GetFabRdVldWords failed");
return -1;
}
INFO("RF_RFdc: ADC tile %u channel %u number of read samples per axi4-stream cycle: %u", ADC_Tile, Block, GetFabricRate);
// Read the number of samples per axi4-stream cycle
Status = XRFdc_GetFabWrVldWords(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, Block, &GetFabricRate);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: GetFabWrVldWords failed");
return -1;
}
INFO("RF_RFdc: ADC tile %u channel %u number of write samples per axi4-stream cycle: %u", ADC_Tile, Block, GetFabricRate);
// Print out the block configuration
Status = XRFdc_GetBlockStatus(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, Block, &BlockStatus);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: GetBlockStatus failed");
return -1;
}
INFO("RF_RFdc: ADC block configuration:");
INFO("\tRF_RFdc: ADC Sampling Frequency: %.03f", BlockStatus.SamplingFreq);
INFO("\tRF_RFdc: Analog datapath status: %u", BlockStatus.AnalogDataPathStatus);
INFO("\tRF_RFdc: Digital datapath status: %u", BlockStatus.DigitalDataPathStatus);
INFO("\tRF_RFdc: Datapath clock status: %u", BlockStatus.DataPathClocksStatus);
INFO("\tRF_RFdc: FIFO flags enabled: %u", BlockStatus.IsFIFOFlagsEnabled);
INFO("\tRF_RFdc: FIFO flags asserted: %u", BlockStatus.IsFIFOFlagsAsserted);
// Print out the configured mixer frequency
Status = XRFdc_GetMixerSettings(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, Block, adcMixerSettings);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: GetMixerSettings failed");
return -1;
}
INFO("RF_RFdc: ADC Mixer Frequency: %.03f", adcMixerSettings->Freq);
// Print out the ADC input data type
if (XRFdc_GetDataType(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, Block)) {
INFO("RF_RFdc: ADC input data type: real");
} else {
INFO("RF_RFdc: ADC input data type: I/Q");
}
// Print out the data width
DataWidth = XRFdc_GetDataWidth(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, Block);
INFO("RF_RFdc: ADC data width: %d", DataWidth);
// Print out the digital path status
bool adc_dig_path_en = XRFdc_IsADCDigitalPathEnabled(RFdcInstPtr, ADC_Tile, Block);
INFO("RF_RFdc: Digital path is %sabled", adc_dig_path_en ? "en" : "dis");
// Print out the FIFO status
bool adc_fifo_en = XRFdc_IsFifoEnabled(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, Block);
INFO("RF_RFdc: ADC FIFO is %sabled", adc_fifo_en ? "en" : "dis");
// Print out the connected I amd Q data
DataConnectedI = XRFdc_GetConnectedIData(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, Block);
DataConnectedQ = XRFdc_GetConnectedQData(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, Block);
INFO("RF_RFdc: ADC connected I data: %d, ADC connected Q data: %d", DataConnectedI, DataConnectedQ);
// Print out the Nyquist zone
Status = XRFdc_GetNyquistZone(RFdcInstPtr, XRFDC_ADC_TILE, ADC_Tile, Block, &NyquistZonePtr);
if (Status != XRFDC_SUCCESS) {
ERROR("RF_RFdc: GetNyquistZone failed");
return -1;
}
INFO("RF_RFdc: ADC Nyquist zone: %u", NyquistZonePtr);
Status = XRFdc_GetCalibrationMode(RFdcInstPtr, ADC_Tile, Block, &CalibrationMode);
if (Status != XRFDC_SUCCESS) {
ERROR("RF_RFdc: XRFdc_GetCalibrationMode failed");
return -1;
}
INFO("RF_RFdc: ADC calibration mode: %u", CalibrationMode);
}
/** ----------------- DAC ------------------ **
* **
* We'll explicitly configure DAC tile 1, **
* for which we have enabled channel 0 in Vivado **
** -------------------------------------------- **/
u32 DecoderModePtr = 0;
u16 InvSincModePtr = 0;
u32 DACMixedMode = 0;
/** ---------------------------------------*/
/** === Common DAC tile configuration === */
/** ---------------------------------------*/
// Explicitly configure the PLL (overriding the parameters provided through Vivado)
Status = XRFdc_DynamicPLLConfig(RFdcInstPtr, XRFDC_DAC_TILE, DAC_Tile, XRFDC_INTERNAL_PLL_CLK, RFDC_REF_SAMPLE_FREQ, RFDC_PLL_FREQ);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: failed to set Dynamic PLL configuration (DAC)");
return -1;
}
INFO("RF_RFdc: PLL succesfully configured for DAC tile %d", DAC_Tile);
// Explicitly enable the DAC FIFO
Status = XRFdc_SetupFIFO(RFdcInstPtr, XRFDC_DAC_TILE, DAC_Tile, 1);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: failed to enable the DAC FIFO");
return -1;
}
INFO("RF_RFdc: DAC FIFO succesfully enabled for DAC tile %d", DAC_Tile);
// Print out the previously captured IP status [related to that DAC tile only]
INFO("RF_RFdc: DAC tile %u status:", DAC_Tile);
INFO("\tRF_RFdc: Tile enabled: %u", IPStatusPtr.DACTileStatus[DAC_Tile].IsEnabled);
INFO("\tRF_RFdc: Tile state: %u", IPStatusPtr.DACTileStatus[DAC_Tile].TileState);
INFO("\tRF_RFdc: Tile block status mask: %u",IPStatusPtr.DACTileStatus[DAC_Tile].BlockStatusMask);
INFO("\tRF_RFdc: Tile power-up state: %u", IPStatusPtr.DACTileStatus[DAC_Tile].PowerUpState);
INFO("\tRF_RFdc: Tile PLL state: %u", IPStatusPtr.DACTileStatus[DAC_Tile].PLLState);
// Configure the clock divider for the PL as required
Status = XRFdc_SetFabClkOutDiv(RFdcInstPtr, XRFDC_DAC_TILE, DAC_Tile, XRFDC_FAB_CLK_DIV1);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: Failed to configure DAC tile clock dividers");
return -1;
}
INFO("RF_RFdc: Clock divider for the PL succesfully set to 0x%u (1) for DAC tile %d", XRFDC_FAB_CLK_DIV1, DAC_Tile);
// Print out the clock divider for the PL
Status = XRFdc_GetFabClkOutDiv(RFdcInstPtr, XRFDC_DAC_TILE, DAC_Tile, &FabClkDivPtr);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: GetFabClkOutDiv failed");
return -1;
}
INFO("RF_RFdc: Clock divider for the PL: 0x%u", FabClkDivPtr);
// Print out the clock source
Status = XRFdc_GetClockSource(RFdcInstPtr, XRFDC_DAC_TILE, DAC_Tile, &ClockSource);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: GetClockSource failed");
return -1;
}
INFO("RF_RFdc: DAC clock source: %d", ClockSource);
// Print out the PLL configuration
Status = XRFdc_GetPLLConfig(RFdcInstPtr, XRFDC_DAC_TILE, DAC_Tile, &PLLSettings);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: GetPLLConfig failed");
return -1;
}
INFO("RF_RFdc: PLL configuration:");
INFO("\tRF_RFdc: PLL enabled (%u)", PLLSettings.Enabled);
INFO("\tRF_RFdc: PLL reference clock frequency (%f)", PLLSettings.RefClkFreq);
INFO("\tRF_RFdc: PLL sample rate (%f)", PLLSettings.SampleRate);
INFO("\tRF_RFdc: PLL reference clock divider (%d)", PLLSettings.RefClkDivider);
INFO("\tRF_RFdc: PLL feedback divider (%d)", PLLSettings.FeedbackDivider);
INFO("\tRF_RFdc: PLL output divider (%d)", PLLSettings.OutputDivider);
// Print out the PLL lock status
Status = XRFdc_GetPLLLockStatus(RFdcInstPtr, XRFDC_DAC_TILE, DAC_Tile, &LockStatusPtr);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: GetPLLLockStatus failed");
return -1;
}
INFO("RF_RFdc: PLL lock status: %u", LockStatusPtr);
// Print out the FIFO status
Status = XRFdc_GetFIFOStatus(RFdcInstPtr, XRFDC_DAC_TILE, DAC_Tile, &FIFOEnablePtr);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: GetFIFOStatus failed");
return -1;
}
INFO("RF_RFdc: DAC FIFO status: %u", FIFOEnablePtr);
/** ---------------------------------------------*/
/** === channel specific configuration (DAC) === */
/** ---------------------------------------------*/
for (u16 Block = 0; Block < 4; Block++) {
if (!XRFdc_IsDACBlockEnabled(RFdcInstPtr, DAC_Tile, Block)) {
continue;
}
INFO("RF_RFdc: DAC tile %u channel %u is enabled", DAC_Tile, Block);
// Explicitly set the DAC interpolation factor (overriding the parameters provided through Vivado)
Status = XRFdc_SetInterpolationFactor(RFdcInstPtr, DAC_Tile, Block, XRFDC_INTERP_DECIM_8X);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: Failed to set DAC interpolation factor");
return -1;
}
INFO("RF_RFdc: DAC interpolation factor succesfully configured for DAC tile %d channel %d", DAC_Tile, Block);
/** these function calls must be used at startup to initialize the phase of the fine mixer to a valid state */
// Set our desired NCO configuration;
// NOTE: for some reason the vivado-set configuration was not applied or rewritten at some point
Status = XRFdc_SetMixerSettings(RFdcInstPtr, XRFDC_DAC_TILE, DAC_Tile, Block, &dacMixerSettings);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: Failed to set DAC NCO settings");
return -1;
}
// Reset NCO phase of the DUC
XRFdc_ResetNCOPhase(RFdcInstPtr, XRFDC_DAC_TILE, DAC_Tile, Block);
//Generate a Tile Event
XRFdc_UpdateEvent(RFdcInstPtr, XRFDC_DAC_TILE, DAC_Tile, Block, XRFDC_EVENT_MIXER);
INFO("RF_RFdc: DAC mixer succesfully configured");
/** end of DAC channel mixer configuration */
// Explicitly set the Nyquist zone
// TODO:
Status = XRFdc_SetNyquistZone(RFdcInstPtr, XRFDC_DAC_TILE, DAC_Tile, Block, XRFDC_EVEN_NYQUIST_ZONE);
if (Status != XRFDC_SUCCESS) {
ERROR("RF_RFdc: Failed to set DAC Nyquist Zone");
return -1;
}
INFO("RF_RFdc: DAC Nyquist zone succesfully set to 2 (even) for DAC tile %d", DAC_Tile);
/* Status = XRFdc_SetNyquistZone(RFdcInstPtr, XRFDC_DAC_TILE, DAC_Tile, Block, XRFDC_ODD_NYQUIST_ZONE);
if (Status != XRFDC_SUCCESS) {
ERROR("RF_RFdc: Failed to set DAC Nyquist Zone");
return -1;
}
INFO("RF_RFdc: DAC Nyquist zone succesfully set to 1 (odd) for DAC tile %d", DAC_Tile);
*/
// Explicitly set the decoder mode
Status = XRFdc_SetDecoderMode(RFdcInstPtr, DAC_Tile, Block, XRFDC_DECODER_MAX_SNR_MODE);
//Status = XRFdc_SetDecoderMode(RFdcInstPtr, Tile, Block, XRFDC_DECODER_MAX_LINEARITY_MODE);
if (Status != XRFDC_SUCCESS) {
ERROR("ERROR: Failed to set DAC decoder mode");
return -1;
}
INFO("RF_RFdc: DAC decoder mode succesfully set to %d (max SNR) for DAC tile %d", XRFDC_DECODER_MAX_SNR_MODE, DAC_Tile);
// Explicitly disable the inverse sinc FIR (we're on the second Nyquist zone)
Status = XRFdc_SetInvSincFIR(RFdcInstPtr, DAC_Tile, Block, 0);