@@ -51,29 +51,29 @@ class DDR3():
51
51
52
52
"""
53
53
54
+ BLOCK_SIZE = 2048 # 1/2 the incoming FIFO depth in bytes (size of the BlockPipeIn)
55
+ # number of channels that the DDR is striped between (for DACs)
56
+ NUM_CHANNELS = 8
57
+ UPDATE_PERIOD = 400e-9 # 2.5 MHz -- requires SCLK ~ 50 MHZ
58
+ PORT1_INDEX = 0x3_7f_ff_f8
59
+ NUM_ADC_CHANNELS = 8 # number of 2 byte chunks in DDR
60
+ ADC_PERIOD = 200e-9
61
+
62
+ # the index is the DDR address that the circular buffer stops at.
63
+ # need to write all the way up to this stoping point otherwise the SPI output will glitch
64
+ SAMPLE_SIZE = int ((PORT1_INDEX + 8 )/ 4 )
65
+
54
66
def __init__ (self , fpga , endpoints = None , data_version = 'TIMESTAMPS' ):
55
67
if endpoints is None :
56
68
endpoints = Endpoint .get_chip_endpoints ('DDR3' )
57
69
self .fpga = fpga
58
70
self .endpoints = endpoints
59
- self .parameters = {'BLOCK_SIZE' : 2048 , # 1/2 the incoming FIFO depth in bytes (size of the BlockPipeIn)
60
- # number of channels that the DDR is striped between (for DACs)
61
- 'channels' : 8 ,
62
- 'update_period' : 400e-9 , # 2.5 MHz -- requires SCLK ~ 50 MHZ
63
- 'port1_index' : 0x3_7f_ff_f8 ,
64
- 'adc_channels' : 8 , # number of 2 byte chunks in DDR
65
- 'adc_period' : 200e-9
66
- }
67
-
68
- # the index is the DDR address that the circular buffer stops at.
69
- # need to write all the way up to this stoping point otherwise the SPI output will glitch
70
- self .parameters ['sample_size' ] = int ((self .parameters ['port1_index' ] + 8 )/ 4 )
71
- self .parameters ['data_version' ] = data_version # sets deswizzling mode
71
+ self .data_version = data_version # sets deswizzling mode
72
72
73
73
self .data_arrays = []
74
- for i in range (self . parameters [ 'channels' ] ):
74
+ for i in range (DDR3 . NUM_CHANNELS ):
75
75
self .data_arrays .append (np .zeros (
76
- self . parameters [ 'sample_size' ] ).astype (np .uint16 ))
76
+ DDR3 . SAMPLE_SIZE ).astype (np .uint16 ))
77
77
78
78
self .clear_adc_debug ()
79
79
@@ -97,7 +97,8 @@ def clear_adc_debug(self):
97
97
self .fpga .clear_wire_bit (self .endpoints ['ADC_DEBUG' ].address ,
98
98
self .endpoints ['ADC_DEBUG' ].bit_index_low )
99
99
100
- def make_flat_voltage (self , amplitude ):
100
+ @staticmethod
101
+ def make_flat_voltage (amplitude ):
101
102
"""Return a constant unit16 array of value amplitude.
102
103
103
104
Array length based on the sample_size parameter. The conversion from
@@ -115,11 +116,12 @@ def make_flat_voltage(self, amplitude):
115
116
to be assigned to DDR data array
116
117
"""
117
118
118
- amplitude = np .ones (self . parameters [ 'sample_size' ] )* amplitude
119
+ amplitude = np .ones (DDR3 . SAMPLE_SIZE )* amplitude
119
120
amplitude = amplitude .astype (np .uint16 )
120
121
return amplitude
121
122
122
- def closest_frequency (self , freq ):
123
+ @staticmethod
124
+ def closest_frequency (freq ):
123
125
"""Determine closest frequency so the waveform evenly divides into the length of the DDR3
124
126
125
127
Parameters
@@ -133,22 +135,23 @@ def closest_frequency(self, freq):
133
135
The closest possible frequency
134
136
"""
135
137
136
- samples_per_period = (1 / freq ) / self . parameters [ 'update_period' ]
138
+ samples_per_period = (1 / freq ) / DDR3 . UPDATE_PERIOD
137
139
138
140
if samples_per_period <= 2 :
139
141
print ('Frequency is too high for the DDR update rate' )
140
142
return None
141
- total_periods = self . parameters [ 'sample_size' ] / samples_per_period
143
+ total_periods = DDR3 . SAMPLE_SIZE / samples_per_period
142
144
# round and recalculate frequency
143
145
round_total_periods = np .round (total_periods )
144
- round_samples_per_period = self . parameters [ 'sample_size' ] / \
146
+ round_samples_per_period = DDR3 . SAMPLE_SIZE / \
145
147
round_total_periods
146
148
new_frequency = 1 / \
147
- (self . parameters [ 'update_period' ] * round_samples_per_period )
149
+ (DDR3 . UPDATE_PERIOD * round_samples_per_period )
148
150
149
151
return new_frequency
150
152
151
- def make_sine_wave (self , amplitude , frequency ,
153
+ @staticmethod
154
+ def make_sine_wave (amplitude , frequency ,
152
155
offset = 0x2000 , actual_frequency = True ):
153
156
"""Return a sine-wave array for writing to DDR.
154
157
@@ -179,10 +182,10 @@ def make_sine_wave(self, amplitude, frequency,
179
182
print ('Error: amplitude in sine-wave is too large' )
180
183
return - 1
181
184
if actual_frequency :
182
- frequency = self .closest_frequency (frequency )
185
+ frequency = DDR3 .closest_frequency (frequency )
183
186
184
- t = np .arange (0 , self . parameters [ 'update_period' ] * self . parameters [ 'sample_size' ] ,
185
- self . parameters [ 'update_period' ] )
187
+ t = np .arange (0 , DDR3 . UPDATE_PERIOD * DDR3 . SAMPLE_SIZE ,
188
+ DDR3 . UPDATE_PERIOD )
186
189
# print('length of time axis after creation ', len(t))
187
190
ddr_seq = (amplitude )* np .sin (t * frequency * 2 * np .pi ) + offset
188
191
if any (ddr_seq < 0 ) or any (ddr_seq > (2 ** 16 - 1 )):
@@ -191,7 +194,8 @@ def make_sine_wave(self, amplitude, frequency,
191
194
ddr_seq = ddr_seq .astype (np .uint16 )
192
195
return ddr_seq , frequency
193
196
194
- def make_ramp (self , start , stop , step , actual_length = True ):
197
+ @staticmethod
198
+ def make_ramp (start , stop , step , actual_length = True ):
195
199
"""Create a ramp signal to write to the DDR.
196
200
197
201
The conversion from float or int voltage to int digital (binary) code
@@ -217,17 +221,18 @@ def make_ramp(self, start, stop, step, actual_length=True):
217
221
len_ramp_seq = len (ramp_seq )
218
222
if actual_length :
219
223
length = int (
220
- self . parameters [ 'sample_size' ] / np .round (self . parameters [ 'sample_size' ] / len_ramp_seq ))
224
+ DDR3 . SAMPLE_SIZE / np .round (DDR3 . SAMPLE_SIZE / len_ramp_seq ))
221
225
stop = start + length * step
222
226
ramp_seq = np .arange (start , stop , step )
223
- num_tiles = self . parameters [ 'sample_size' ] // len (ramp_seq )
224
- extras = self . parameters [ 'sample_size' ] % len (ramp_seq )
227
+ num_tiles = DDR3 . SAMPLE_SIZE // len (ramp_seq )
228
+ extras = DDR3 . SAMPLE_SIZE % len (ramp_seq )
225
229
ddr_seq = np .tile (ramp_seq , num_tiles )
226
230
ddr_seq = np .hstack ((ddr_seq , ramp_seq [0 :extras ]))
227
231
ddr_seq = ddr_seq .astype (np .uint16 )
228
232
return ddr_seq
229
233
230
- def make_step (self , low , high , length , actual_length = True , duty = 50 ):
234
+ @staticmethod
235
+ def make_step (low , high , length , actual_length = True , duty = 50 ):
231
236
"""Return a step signal (square wave) to write to the DDR.
232
237
233
238
The conversion from float or int voltage to int digital (binary) code
@@ -254,12 +259,12 @@ def make_step(self, low, high, length, actual_length=True, duty=50):
254
259
255
260
if actual_length :
256
261
length = int (
257
- self . parameters [ 'sample_size' ] / np .round (self . parameters [ 'sample_size' ] / length ))
262
+ DDR3 . SAMPLE_SIZE / np .round (DDR3 . SAMPLE_SIZE / length ))
258
263
l_first = int (length / 100 * duty )
259
264
l_end = int (length / 100 * (100 - duty ))
260
265
ramp_seq = np .concatenate ((np .ones (l_first )* low , np .ones (l_end )* high ))
261
- num_tiles = self . parameters [ 'sample_size' ] // len (ramp_seq )
262
- extras = self . parameters [ 'sample_size' ] % len (ramp_seq )
266
+ num_tiles = DDR3 . SAMPLE_SIZE // len (ramp_seq )
267
+ extras = DDR3 . SAMPLE_SIZE % len (ramp_seq )
263
268
ddr_seq = np .tile (ramp_seq , num_tiles )
264
269
ddr_seq = np .hstack ((ddr_seq , ramp_seq [0 :extras ]))
265
270
ddr_seq = ddr_seq .astype (np .uint16 )
@@ -269,10 +274,10 @@ def write_channels(self, set_ddr_read=True):
269
274
"""Write the channels as striped data to the DDR."""
270
275
271
276
data = np .zeros (
272
- int (len (self .data_arrays [0 ])* self . parameters [ 'channels' ] ))
277
+ int (len (self .data_arrays [0 ])* DDR3 . NUM_CHANNELS ))
273
278
data = data .astype (np .uint16 )
274
279
275
- for i in range (self . parameters [ 'channels' ] ):
280
+ for i in range (DDR3 . NUM_CHANNELS ):
276
281
if i % 2 == 0 : # extra order swap on the 32 bit wide pipe
277
282
data [(7 - i - 1 )::8 ] = self .data_arrays [i ]
278
283
else :
@@ -305,7 +310,7 @@ def write_buf(self, buf, set_ddr_read=True):
305
310
print ('Writing to DDR...' )
306
311
time1 = time .time ()
307
312
block_pipe_return = self .fpga .xem .WriteToBlockPipeIn (epAddr = self .endpoints ['BLOCK_PIPE_IN' ].address ,
308
- blockSize = self . parameters [ ' BLOCK_SIZE' ] ,
313
+ blockSize = DDR3 . BLOCK_SIZE ,
309
314
data = buf )
310
315
print (f'The length of the DDR write was { block_pipe_return } ' )
311
316
@@ -514,12 +519,12 @@ def read_adc_block(self, sample_size=None, source='ADC', DEBUG_PRINT=False):
514
519
"""
515
520
516
521
if sample_size is None :
517
- data = np .zeros ((self . parameters [ 'sample_size' ] ,), dtype = int )
522
+ data = np .zeros ((DDR3 . SAMPLE_SIZE ,), dtype = int )
518
523
data_buf = bytearray (data )
519
524
else :
520
525
data_buf = bytearray (sample_size )
521
526
522
- block_size = self . parameters [ ' BLOCK_SIZE' ]
527
+ block_size = DDR3 . BLOCK_SIZE
523
528
# check block size
524
529
if block_size % 16 != 0 :
525
530
print ('Error in read adc. Block size is not a multiple of 16' )
@@ -753,16 +758,16 @@ def save_data(self, data_dir, file_name, num_repeats=4, blk_multiples=40, append
753
758
else :
754
759
file_mode = 'w'
755
760
756
- chunk_size = int (self . parameters [ " BLOCK_SIZE" ] * blk_multiples / (
757
- self . parameters [ 'adc_channels' ] * 2 )) # readings per ADC
761
+ chunk_size = int (DDR3 . BLOCK_SIZE * blk_multiples / (
762
+ DDR3 . NUM_ADC_CHANNELS * 2 )) # readings per ADC
758
763
repeat = 0
759
764
adc_readings = chunk_size * num_repeats
760
765
print (f'Anticipated chunk size (readings per channel) { chunk_size } ' )
761
766
print (
762
- f'Reading { adc_readings * 2 / 1024 } kB per ADC channel for a total of { adc_readings * self . parameters [ "adc_period" ] * 1000 } ms of data' )
767
+ f'Reading { adc_readings * 2 / 1024 } kB per ADC channel for a total of { adc_readings * DDR3 . ADC_PERIOD * 1000 } ms of data' )
763
768
764
769
self .set_adc_read () # enable data into the ADC reading FIFO
765
- time .sleep (adc_readings * self . parameters [ 'adc_period' ] )
770
+ time .sleep (adc_readings * DDR3 . ADC_PERIOD )
766
771
767
772
# Save ADC DDR data to a file
768
773
with h5py .File (full_data_name , file_mode ) as file :
@@ -774,8 +779,8 @@ def save_data(self, data_dir, file_name, num_repeats=4, blk_multiples=40, append
774
779
# Make space for first round of new data. Not needed when not appending because the data set is created with chunk_size space
775
780
data_set .resize (data_set .shape [1 ] + chunk_size , axis = 1 )
776
781
else :
777
- data_set = file .create_dataset ("adc" , (self . parameters [ 'adc_channels' ] , chunk_size ), maxshape = (
778
- self . parameters [ 'adc_channels' ] , None ))
782
+ data_set = file .create_dataset ("adc" , (DDR3 . NUM_ADC_CHANNELS , chunk_size ), maxshape = (
783
+ DDR3 . NUM_ADC_CHANNELS , None ))
779
784
data_set .attrs ['bitfile_version' ] = self .fpga .bitfile_version
780
785
new_data_index = 0
781
786
@@ -787,11 +792,11 @@ def save_data(self, data_dir, file_name, num_repeats=4, blk_multiples=40, append
787
792
elif self .parameters ['data_version' ] == 'TIMESTAMPS' :
788
793
chan_data = self .deswizzle (d )
789
794
790
- if self . parameters [ 'adc_channels' ] == 4 :
795
+ if DDR3 . NUM_ADC_CHANNELS == 4 :
791
796
chan_stack = np .vstack (
792
797
(chan_data [0 ], chan_data [1 ], chan_data [2 ], chan_data [3 ]))
793
798
794
- if self . parameters [ 'adc_channels' ] == 8 :
799
+ if DDR3 . NUM_ADC_CHANNELS == 8 :
795
800
chan_stack = np .vstack ((chan_data [0 ], chan_data [1 ], chan_data [2 ], chan_data [3 ],
796
801
chan_data [4 ], chan_data [5 ], chan_data [6 ], chan_data [7 ]))
797
802
@@ -826,7 +831,7 @@ def read_adc(self, blk_multiples=2048):
826
831
"""
827
832
828
833
t , bytes_read_error = self .read_adc_block ( # just reads from the block pipe out
829
- sample_size = self . parameters [ " BLOCK_SIZE" ] * blk_multiples
834
+ sample_size = DDR3 . BLOCK_SIZE * blk_multiples
830
835
)
831
836
d = np .frombuffer (t , dtype = np .uint8 ).astype (np .uint32 )
832
837
print (f'Bytes read: { bytes_read_error } ' )
@@ -838,7 +843,7 @@ def set_index(self, factor, factor2=None):
838
843
This is now fixed to improve timing performance.
839
844
"""
840
845
print ('Set index is no longer used. Index is fixed to: {}' .format (
841
- self . parameters [ 'port1_index' ] ))
846
+ DDR3 . PORT1_INDEX ))
842
847
843
848
def write_setup (self , data_driven_clock = True ):
844
849
"""Set up DDR for writing."""
0 commit comments