Skip to content

Commit

Permalink
update with new pynq python code
Browse files Browse the repository at this point in the history
  • Loading branch information
reed-foster committed Oct 9, 2023
1 parent 17b1829 commit 8a7e798
Show file tree
Hide file tree
Showing 4 changed files with 466 additions and 137 deletions.
3 changes: 0 additions & 3 deletions pynq/dds_loopback.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ def __init__(self, bitfile_name=None, dbg=False, plot=False, n_buffers=1, phase_
time.sleep(0.5)
# get IPs
self.dma_recv = self.axi_dma_0.recvchannel
self.capture_trig = self.axi_gpio_capture.channel1[0]
self.trigger_mode = self.axi_gpio_trigger_sel.channel1[0]
self.adc_select = self.axi_gpio_adc_sel.channel1[0]
self.pinc = [self.dds_hier_0.axi_fifo_pinc_0, self.dds_hier_1.axi_fifo_pinc_1]
self.cos_scale = [self.dds_hier_0.axi_fifo_scale_0, self.dds_hier_1.axi_fifo_scale_1]
self.timer = self.axi_timer_0
Expand Down
185 changes: 168 additions & 17 deletions pynq/dds_loopback_overlay.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 4,
"id": "324a325c-5d95-466d-90e2-dcf2a57de200",
"metadata": {},
"outputs": [],
Expand All @@ -19,17 +19,10 @@
},
{
"cell_type": "code",
"execution_count": 2,
"id": "a3829ad0-0297-4923-8cc6-f2479660e698",
"execution_count": 5,
"id": "696ef386-adbb-4a9f-bb05-59140dc43762",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"loading bitfile hw/top_biastini_750kHz_SPI.bit\n"
]
},
{
"data": {
"application/javascript": [
Expand Down Expand Up @@ -69,16 +62,174 @@
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"loaded bitstream\n",
"set clocks\n"
]
"data": {
"text/plain": [
"\u001b[0;31mType:\u001b[0m NoiseOverlay\n",
"\u001b[0;31mString form:\u001b[0m <noise_buffer_overlay.NoiseOverlay object at 0xffff7d59fd60>\n",
"\u001b[0;31mFile:\u001b[0m /home/xilinx/jupyter_notebooks/dds_test/noise_buffer_overlay.py\n",
"\u001b[0;31mDocstring:\u001b[0m \n",
"Default documentation for overlay hw/top_biastini_32bitDDS_noise_buffer.bit. The following\n",
"attributes are available on this overlay:\n",
"\n",
"IP Blocks\n",
"----------\n",
"axi_dma_0 : pynq.lib.dma.DMA\n",
"noise_tracker/axi_fifo_noise_buf_cfg : axitxfifo.AxiStreamFifoDriver\n",
"dds_hier_0/axi_fifo_pinc_0 : axitxfifo.AxiStreamFifoDriver\n",
"dds_hier_0/axi_fifo_scale_0 : axitxfifo.AxiStreamFifoDriver\n",
"rf_data_converter : pynq.overlay.DefaultIP\n",
"lmh6401_hier/axi_fifo_lmh6401 : axitxfifo.AxiStreamFifoDriver\n",
"axi_timer_0 : axitimer.AxiTimerDriver\n",
"dds_hier_0/axi_fifo_dac_scale_0 : axitxfifo.AxiStreamFifoDriver\n",
"dds_hier_1/axi_fifo_dac_scale_1 : axitxfifo.AxiStreamFifoDriver\n",
"dds_hier_1/axi_fifo_pinc_1 : axitxfifo.AxiStreamFifoDriver\n",
"dds_hier_1/axi_fifo_scale_1 : axitxfifo.AxiStreamFifoDriver\n",
"axi_gpio_adcio : pynq.lib.axigpio.AxiGPIO\n",
"zynq_ultra_ps_e_0 : pynq.overlay.DefaultIP\n",
"\n",
"Hierarchies\n",
"-----------\n",
"dds_hier_0 : pynq.overlay.DefaultHierarchy\n",
"dds_hier_1 : pynq.overlay.DefaultHierarchy\n",
"lmh6401_hier : pynq.overlay.DefaultHierarchy\n",
"noise_tracker : pynq.overlay.DefaultHierarchy\n",
"dds_hier_0/dac_prescaler_wrapper_0 : pynq.overlay.DefaultHierarchy\n",
"dds_hier_0/dds_wrapper_0 : pynq.overlay.DefaultHierarchy\n",
"dds_hier_1/dac_prescaler_wrapper_1 : pynq.overlay.DefaultHierarchy\n",
"dds_hier_1/dds_wrapper_1 : pynq.overlay.DefaultHierarchy\n",
"lmh6401_hier/lmh6401_spi_wrapper_0 : pynq.overlay.DefaultHierarchy\n",
"noise_tracker/adc00_energy_downsample : pynq.overlay.DefaultHierarchy\n",
"noise_tracker/adc00_energy_downsample/axis_x2_wrapper_0 : pynq.overlay.DefaultHierarchy\n",
"noise_tracker/adc02_energy_downsample : pynq.overlay.DefaultHierarchy\n",
"noise_tracker/adc02_energy_downsample/axis_x2_wrapper_0 : pynq.overlay.DefaultHierarchy\n",
"noise_tracker/noise_event_tracker_0 : pynq.overlay.DefaultHierarchy\n",
"\n",
"Interrupts\n",
"----------\n",
"None\n",
"\n",
"GPIO Outputs\n",
"------------\n",
"None\n",
"\n",
"Memories\n",
"------------\n",
"PSDDR : Memory\n",
"\u001b[0;31mClass docstring:\u001b[0m\n",
"This class keeps track of a single bitstream's state and contents.\n",
"\n",
"The overlay class holds the state of the bitstream and enables run-time\n",
"protection of bindings.\n",
"\n",
"Our definition of overlay is: \"post-bitstream configurable design\".\n",
"Hence, this class must expose configurability through content discovery\n",
"and runtime protection.\n",
"\n",
"The overlay class exposes the IP and hierarchies as attributes in the\n",
"overlay. If no other drivers are available the `DefaultIP` is constructed\n",
"for IP cores at top level and `DefaultHierarchy` for any hierarchies that\n",
"contain addressable IP. Custom drivers can be bound to IP and hierarchies\n",
"by subclassing `DefaultIP` and `DefaultHierarchy`. See the help entries\n",
"for those class for more details.\n",
"\n",
"This class stores four dictionaries: IP, GPIO, interrupt controller\n",
"and interrupt pin dictionaries.\n",
"\n",
"Each entry of the IP dictionary is a mapping:\n",
"'name' -> {phys_addr, addr_range, type, config, state}, where\n",
"name (str) is the key of the entry.\n",
"phys_addr (int) is the physical address of the IP.\n",
"addr_range (int) is the address range of the IP.\n",
"type (str) is the type of the IP.\n",
"config (dict) is a dictionary of the configuration parameters.\n",
"state (str) is the state information about the IP.\n",
"\n",
"Each entry of the GPIO dictionary is a mapping:\n",
"'name' -> {pin, state}, where\n",
"name (str) is the key of the entry.\n",
"pin (int) is the user index of the GPIO, starting from 0.\n",
"state (str) is the state information about the GPIO.\n",
"\n",
"Each entry in the interrupt controller dictionary is a mapping:\n",
"'name' -> {parent, index}, where\n",
"name (str) is the name of the interrupt controller.\n",
"parent (str) is the name of the parent controller or '' if attached\n",
"directly to the PS.\n",
"index (int) is the index of the interrupt attached to.\n",
"\n",
"Each entry in the interrupt pin dictionary is a mapping:\n",
"'name' -> {controller, index}, where\n",
"name (str) is the name of the pin.\n",
"controller (str) is the name of the interrupt controller.\n",
"index (int) is the line index.\n",
"\n",
"Attributes\n",
"----------\n",
"bitfile_name : str\n",
" The absolute path of the bitstream.\n",
"dtbo : str\n",
" The absolute path of the dtbo file for the full bitstream.\n",
"ip_dict : dict\n",
" All the addressable IPs from PS. Key is the name of the IP; value is\n",
" a dictionary mapping the physical address, address range, IP type,\n",
" parameters, registers, and the state associated with that IP:\n",
" {str: {'phys_addr' : int, 'addr_range' : int, 'type' : str, 'parameters' : dict, 'registers': dict, 'state' : str}}.\n",
"gpio_dict : dict\n",
" All the GPIO pins controlled by PS. Key is the name of the GPIO pin;\n",
" value is a dictionary mapping user index (starting from 0),\n",
" and the state associated with that GPIO pin:\n",
" {str: {'index' : int, 'state' : str}}.\n",
"interrupt_controllers : dict\n",
" All AXI interrupt controllers in the system attached to\n",
" a PS interrupt line. Key is the name of the controller;\n",
" value is a dictionary mapping parent interrupt controller and the\n",
" line index of this interrupt:\n",
" {str: {'parent': str, 'index' : int}}.\n",
" The PS is the root of the hierarchy and is unnamed.\n",
"interrupt_pins : dict\n",
" All pins in the design attached to an interrupt controller.\n",
" Key is the name of the pin; value is a dictionary\n",
" mapping the interrupt controller and the line index used:\n",
" {str: {'controller' : str, 'index' : int}}.\n",
"pr_dict : dict\n",
" Dictionary mapping from the name of the partial-reconfigurable\n",
" hierarchical blocks to the loaded partial bitstreams:\n",
" {str: {'loaded': str, 'dtbo': str}}.\n",
"device : pynq.Device\n",
" The device that the overlay is loaded on\n",
"\u001b[0;31mInit docstring:\u001b[0m \n",
"Return a new Overlay object.\n",
"\n",
"An overlay instantiates a bitstream object as a member initially.\n",
"\n",
"Parameters\n",
"----------\n",
"bitfile_name : str\n",
" The bitstream name or absolute path as a string.\n",
"dtbo : str\n",
" The dtbo file name or absolute path as a string.\n",
"download : bool\n",
" Whether the overlay should be downloaded.\n",
"ignore_version : bool\n",
" Indicate whether or not to ignore the driver versions.\n",
"device : pynq.Device\n",
" Device on which to load the Overlay. Defaults to\n",
" pynq.Device.active_device\n",
"gen_cache: bool\n",
" if true generates a pickeled cache of the metadata\n",
"\n",
"Note\n",
"----\n",
"This class requires a HWH file to be next to bitstream file\n",
"with same name (e.g. `base.bit` and `base.hwh`).\n"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"ol = DDSOverlay(bitfile_name='hw/top_biastini_750kHz_SPI.bit',dbg=True,plot=True,n_buffers=1,download=True)"
"ol = DDSOverlay(bitfile_name='hw/top_biastini_750_kHz_SPI.bit',download=True)"
]
},
{
Expand Down
55 changes: 51 additions & 4 deletions pynq/noise_buffer_overlay.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def __init__(self, bitfile_name=None, dbg=False, plot=False, **kwargs):
self.timer = self.axi_timer_0
self.lmh6401 = self.lmh6401_hier.axi_fifo_lmh6401
self.noise_buffer = self.noise_tracker.axi_fifo_noise_buf_cfg
self.adc_gain = [self.noise_tracker.adc00_energy_downsample.axi_fifo_adc_gain, self.noise_tracker.adc02_energy_downsample.axi_fifo_adc_gain]

xrfclk.set_ref_clks(lmk_freq=122.88, lmx_freq=409.6)
if dbg:
Expand All @@ -40,18 +41,21 @@ def __init__(self, bitfile_name=None, dbg=False, plot=False, **kwargs):
self.timer.start_tmr()
self.axi_mm_width_words = 8 # 128-bit / 16 bit/word
self.noise_buffer_sample_depth = 2**15
self.noise_buffer_tstamp_depth = 2**10
self.dma_frame_size = (self.noise_buffer_sample_depth + self.noise_buffer_tstamp_depth) * self.axi_mm_width_words
self.dma_frame_size = self.noise_buffer_sample_depth * self.axi_mm_width_words
self.dma_frame_shape = (self.dma_frame_size,)
# we can use unsigned types since the noise will always be a positive number
# actually this is not quite true, since we're applying a lowpass filter after squaring the signal, we could end up with some close-to-zero values going below zero
self.dma_buffer = allocate(shape=self.dma_frame_shape, dtype=np.uint16)
self.dbg = dbg
self.plot = plot
self.t_sleep = 0.008
# seems like there are sometimes AXI transaction reorderings, so add a delay as a
# sort of "manual fence"
# having a single AXI-slave device with multiple registers instead of
# separate AXI GPIOs should prevent issues arising from transaction reordering
self.t_sleep = 0.008
# thresholds for sample discriminator
self.threshold_low = 0
self.threshold_high = 0

def set_freq_hz(self, freq_hz, channel = 0):
pinc = int((freq_hz/self.f_samp)*(2**self.phase_bits))
Expand Down Expand Up @@ -94,8 +98,51 @@ def set_vga_atten_dB(self, atten_dB, channel = 0):
print(f'packet = {hex(packet)}')
self.lmh6401.send_tx_pkt([packet])
time.sleep(self.t_sleep)

def set_adc_digital_gain(self, gain, channel = 0):
# scale is 2Q16, so quantize appropriately
quant = int(gain * 2**16)
if (quant >> 16) > 1 or (quant >> 16) < -2:
raise ValueError(f'cannot quantize {gain} to 2Q16')
if quant < 0:
quant += 2**18
# write to fifo
if self.dbg:
print(f'setting adc_gain scale_factor to {quant / 2**16 - (0 if quant < 2**17 else 4)} ({quant:05x})')
self.adc_gain[channel].send_tx_pkt([quant])
time.sleep(self.t_sleep)


def dma(self):
time.sleep(self.t_sleep)
self.dma_recv.transfer(self.dma_buffer)
time.sleep(self.t_sleep)
time.sleep(self.t_sleep)

def set_discriminator_threshold(self, thresh_high, thresh_low = None):
# configuration packet is 34 bits, so we need two words
# {mode, start, stop, threshold_high, threshold_low}
# always capture start: {1, 0, 16'b0, 16'b1}
# always capture stop: {0, 1, 16'b0, 16'b1}
if thresh_low is None:
thresh_low = thresh_high
self.threshold_low = int(thresh_low * 2**16)
self.threshold_high = int(thresh_high * 2**16)
packet = [(((self.threshold_high & 0xffff) << 16) | (self.threshold_low & 0xffff)), 0x0]
if self.dbg:
print(f'setting discriminator thresholds {thresh_low}-{thresh_high}')
print(f'packet = {[hex(p) for p in packet]}')
self.noise_buffer.send_tx_pkt(packet)

def start_capture(self):
packet = [(((self.threshold_high & 0xffff) << 16) | (self.threshold_low & 0xffff)), 0x2]
if self.dbg:
print(f'sending start command with discriminator thresholds {self.threshold_high & 0xffff}:{self.threshold_low & 0xffff}')
print(f'packet = {[hex(p) for p in packet]}')
self.noise_buffer.send_tx_pkt(packet)

def stop_capture(self):
packet = [(((self.threshold_high & 0xffff) << 16) | (self.threshold_low & 0xffff)), 0x1]
if self.dbg:
print(f'sending stop command with discriminator thresholds {self.threshold_high & 0xffff}:{self.threshold_low & 0xffff}')
print(f'packet = {[hex(p) for p in packet]}')
self.noise_buffer.send_tx_pkt(packet)
Loading

0 comments on commit 8a7e798

Please sign in to comment.