Skip to content

Commit

Permalink
Add RFSoC4x2 Support (#17)
Browse files Browse the repository at this point in the history
* Add RFSoC4x2 Support

* Update README.md

* Update setup.py v0.4.2
  • Loading branch information
dnorthcote authored Jun 28, 2022
1 parent 6e7e173 commit 03c00fa
Show file tree
Hide file tree
Showing 21 changed files with 20,247 additions and 4 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
all: rfsoc2x2 zcu111
all: rfsoc2x2 rfsoc4x2 zcu111

rfsoc2x2:
$(MAKE) -C boards/RFSoC2x2/rfsoc_sam/

rfsoc4x2:
$(MAKE) -C boards/RFSoC4x2/rfsoc_sam/

zcu111:
$(MAKE) -C boards/ZCU111/rfsoc_sam/
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<img src="strathsdr_banner.png" width="100%">

# Spectrum Analyser on PYNQ
This repository hosts an RFSoC Spectrum Analyser tool compatible with [PYNQ image v2.7](https://github.com/Xilinx/PYNQ/releases) for the ZCU111 and RFSoC2x2 development board.
This repository hosts an RFSoC Spectrum Analyser tool compatible with [PYNQ image v2.7](https://github.com/Xilinx/PYNQ/releases) for the ZCU111, RFSoC2x2, and RFSoC4x2 development board.

<p align="center">
<img src="./demonstration.gif" width="75%" height="75%" />
Expand All @@ -25,7 +25,7 @@ Currently, this project is in version 0.4.1. We are working on improving aspects

## Quick Start
Follow the instructions below to install the Spectrum Analyser now. **You will need to give your board access to the internet**.
* Power on your RFSoC2x2 or ZCU111 development board with an SD Card containing a fresh PYNQ v2.7 image.
* Power on your RFSoC development board with an SD Card containing a fresh PYNQ v2.7 image.
* Navigate to Jupyter Labs by opening a browser (preferably Chrome) and connecting to `http://<board_ip_address>:9090/lab`.
* We need to open a terminal in Jupyter Lab. Firstly, open a launcher window as shown in the figure below:

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added boards/RFSoC4x2/rfsoc_sam/bitstream/rfsoc_sam.bit
Binary file not shown.
17,416 changes: 17,416 additions & 0 deletions boards/RFSoC4x2/rfsoc_sam/bitstream/rfsoc_sam.hwh

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions boards/RFSoC4x2/rfsoc_sam/constraints.xdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## RFSoC4x2 Constraints

# An off-chip clock to handle clock conversion
set_property PACKAGE_PIN G13 [get_ports sys_clk_clk_p]
set_property PACKAGE_PIN G12 [get_ports sys_clk_clk_n]
set_property IOSTANDARD DIFF_SSTL12 [get_ports sys_clk_clk_p]
set_property IOSTANDARD DIFF_SSTL12 [get_ports sys_clk_clk_n]
15 changes: 15 additions & 0 deletions boards/RFSoC4x2/rfsoc_sam/drivers/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
__author__ = "David Northcote"
__organisation__ = "The Univeristy of Strathclyde"
__support__ = "https://github.com/strath-sdr/rfsoc_sam"


NUM_ADC_TILES = 4
NUM_DAC_TILES = 4
NUM_ADC_BLOCKS = 2
NUM_DAC_BLOCKS = 2

MAX_SAMPLE_FREQUENCY = 4915.2
PLL_FREQUENCY = 409.6
#MAX_SAMPLE_FREQUENCY = 5000
#PLL_FREQUENCY = 400.0
IL_FACTOR = 8
194 changes: 194 additions & 0 deletions boards/RFSoC4x2/rfsoc_sam/drivers/overlay.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
__author1__ = 'David Northcote'
__author2__ = 'Lewis McLaughlin'
__organisation__ = 'The University of Strathclyde'
__date__ = '18th February 2022'
__version_name__ = '<a href="https://www.google.com/search?q=the+cobbler" target="_blank" rel="noopener noreferrer">The Cobbler</a>'
__version_number__ = '0.4.1'
__channels__ = 'Quad-channel'
__board__ = 'RFSoC4x2'
__release__ = 'release'
__info__ = 'PYNQ on RFSoC: Spectrum Analyzer.'
__support__ = '<a href="https://github.com/strath-sdr/rfsoc_sam" target="_blank" rel="noopener noreferrer">https://github.com/strath-sdr/rfsoc_sam</a>'

about = ''.join(['<br><b>', __info__, '</b><br>', __channels__, ' ', __board__,
' ', __release__, '<br>', 'Version ', __version_number__,
': ', __version_name__, '<br>Date: ', __date__, '<br><br>',
'<b>Organisation:</b> <br>', __organisation__,
'<br><br>', '<b>Support</b>:<br>', __support__])


from pynq import Overlay, allocate
import xrfclk
import xrfdc
import os
from .hierarchies import *
from .quick_widgets import Image
from .constants import *
from ipywidgets import IntProgress
from IPython.display import display
from IPython.display import clear_output
import time
import threading

load_progress = 0
max_count = 100
load_bar = IntProgress(min=load_progress, max=max_count) # instantiate the bar


def generate_about():
global about
about = ''.join(['<br><b>', __info__, '</b><br>', __channels__, ' ', __board__,
' ', __release__, '<br>', 'Version ', __version_number__,
': ', __version_name__, '<br>Date: ', __date__, '<br><br>',
'<b>Organisation:</b> <br>', __organisation__,
'<br><br>', '<b>Support</b>:<br>', __support__])


class Overlay(Overlay):

def __init__(self, overlay_system='sam', init_rf_clks=True, **kwargs):

global __channels__

if not isinstance(overlay_system, str):
raise TypeError("Argument overlay_system must be of type string.")

if overlay_system == 'sam':
this_dir = os.path.dirname(__file__)
bitfile_name = os.path.join(this_dir, 'bitstream', 'rfsoc_sam.bit')
else:
raise ValueError(''.join(["Unknown overlay design ", overlay_system]))

super().__init__(bitfile_name, **kwargs)

if init_rf_clks:
self.init_rf_clks(lmx_freq=PLL_FREQUENCY)


def init_rf_clks(self, lmk_freq=245.76, lmx_freq=491.52):
"""Initialise the LMX and LMK clocks for RF-DC operation.
"""
xrfclk.set_ref_clks(lmk_freq=lmk_freq, lmx_freq=lmx_freq)


def _sam_generator(self, config=None):
def tab_handler(widget):
tab_idx = 3-widget['new']
for i in range(0, len(self.radio.receiver.channels)):
if i is not tab_idx:
self.radio.receiver.channels[i].frontend.stop()
self.radio.receiver.channels[tab_idx].frontend.start()

sam = self.radio.receiver._get_spectrum_analyser(config)
tab_name = [''.join(['Spectrum Analyzer ', j]) for j in ['A', 'B', 'C', 'D']]
children = [sam[i] for i in range(0, len(sam))]
children.reverse()
tab = ipw.Tab(children=children,
layout=ipw.Layout(height='initial',
width='initial'))
for i in range(0, len(children)):
tab.set_title(i, tab_name[i])
tab.observe(tab_handler, 'selected_index')
return tab


def _ctl_generator(self, config=None):
ctl = self.radio.transmitter._get_transmitter_control(config)
tab_name = [''.join(['Transmitter Control ', j]) for j in ['A', 'B']]
children = [ctl[i] for i in range(0, len(ctl))]
children.reverse()
tab = ipw.Tab(children=children,
layout=ipw.Layout(height='initial',
width='initial'))
for i in range(0, len(children)):
tab.set_title(i, tab_name[i])
return tab


def _app_generator(self, config_analyser=None, config_transmitter=None):
def tab_handler(widget):
tab_idx = 3-widget['new']
for i in range(0, len(self.radio.receiver.channels)):
if i is not tab_idx:
self.radio.receiver.channels[i].frontend.stop()
if tab_idx < len(self.radio.receiver.channels):
self.radio.receiver.channels[tab_idx].frontend.start()
sam = self.radio.receiver._get_spectrum_analyser(config_analyser)
ctl = self.radio.transmitter._get_transmitter_control(config_transmitter)
sam_tab_name = [''.join(['Spectrum Analyzer ', j]) for j in ['A', 'B', 'C', 'D']]
ctl_tab_name = [''.join(['Transmitter Control ', j]) for j in ['A', 'B']]
tab_name = sam_tab_name + ctl_tab_name
sam_children = [sam[i] for i in range(0, len(sam))]
sam_children.reverse()
ctl_children = [ctl[i] for i in range(0, len(ctl))]
ctl_children.reverse()
children = sam_children + ctl_children
tab = ipw.Tab(children=children,
layout=ipw.Layout(height='initial',
width='initial'))
for i in range(0, len(children)):
tab.set_title(i, tab_name[i])
tab.observe(tab_handler, 'selected_index')
return tab


def spectrum_analyzer(self, config=None):
display(load_bar) # display the bar
thread = threading.Thread(target=self._update_progress)
thread.start()
sam_tab = self._sam_generator([config, config, config, config])
ctl_tab = self._ctl_generator(config=[{'transmit_enable' : True},
{'transmit_enable' : True},
{'transmit_enable' : True},
{'transmit_enable' : True}])

this_dir = os.path.dirname(__file__)
img = os.path.join(this_dir, 'assets', 'pynq_logo_light.png')
if config is not None:
if 'plotly_theme' in config:
if config['plotly_theme'] == 'plotly_dark':
img = os.path.join(this_dir, 'assets', 'pynq_logo_dark.png')
about_html = ipw.HTML(value=about)
pynq_image = Image(image_file=img,
width=300,
height=200)
sidebar = ipw.VBox([pynq_image.get_widget(), about_html, ])
app = ipw.HBox([sidebar, sam_tab, ipw.VBox([ipw.HBox([ctl_tab])])])
load_bar.value = 100
clear_output(wait=True)
return app


def spectrum_analyzer_application(self, config=None):
display(load_bar) # display the bar
thread = threading.Thread(target=self._update_progress)
thread.start()
app_tab = self._app_generator(config_analyser=[config, config, config, config],
config_transmitter=[{'transmit_enable' : True},
{'transmit_enable' : True},
{'transmit_enable' : True},
{'transmit_enable' : True}])
this_dir = os.path.dirname(__file__)
img = os.path.join(this_dir, 'assets', 'pynq_logo_light.png')
if config is not None:
if 'plotly_theme' in config:
if config['plotly_theme'] == 'plotly_dark':
img = os.path.join(this_dir, 'assets', 'pynq_logo_dark.png')
about_html = ipw.HTML(value=about)
pynq_image = Image(image_file=img,
width=300,
height=200)
sidebar = ipw.VBox([pynq_image.get_widget(), about_html, ])
app = ipw.HBox([sidebar, app_tab])
load_bar.value = 100
clear_output(wait=True)
return app


def _update_progress(self):
while load_bar.value != 100:
if load_bar.value < 100:
load_bar.value = load_bar.value + 1
time.sleep(1)
else:
pass
25 changes: 25 additions & 0 deletions boards/RFSoC4x2/rfsoc_sam/make_bitstream.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
set overlay_name "block_design"
set design_name "rfsoc_sam"

# Open project
open_project ./${overlay_name}/${overlay_name}.xpr
open_bd_design ./${overlay_name}/${overlay_name}.srcs/sources_1/bd/${design_name}/${design_name}.bd

# Add top wrapper and xdc files
make_wrapper -files [get_files ./${overlay_name}/${overlay_name}.srcs/sources_1/bd/${design_name}/${design_name}.bd] -top
add_files -norecurse ./${overlay_name}/${overlay_name}.gen/sources_1/bd/${design_name}/hdl/${design_name}_wrapper.vhd
set_property top ${design_name}_wrapper [current_fileset]
update_compile_order -fileset sources_1

# Set strategy
set_property strategy Performance_ExplorePostRoutePhysOpt [get_runs impl_1]

# Call implement
launch_runs impl_1 -to_step write_bitstream -jobs 12
wait_on_run impl_1

# Move and rename bitstream to final location
file copy -force ./${overlay_name}/${overlay_name}.runs/impl_1/${design_name}_wrapper.bit ./bitstream/${design_name}.bit

# copy hwh files
file copy -force ./${overlay_name}/${overlay_name}.gen/sources_1/bd/${design_name}/hw_handoff/${design_name}.hwh ./bitstream/${design_name}.hwh
18 changes: 18 additions & 0 deletions boards/RFSoC4x2/rfsoc_sam/make_block_design.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
set overlay_name "block_design"
set design_name "rfsoc_sam"
set iprepo_dir ./../../ip/iprepo

# Create project
create_project ${overlay_name} ./${overlay_name} -part xczu48dr-ffvg1517-2-e
set_property board_part xilinx.com:rfsoc4x2:part0:1.0 [current_project]
set_property target_language VHDL [current_project]

# Set IP repository paths
set_property ip_repo_paths $iprepo_dir [current_project]
update_ip_catalog

# Add constraints
add_files -fileset constrs_1 -norecurse ./constraints.xdc

# Make block design
source ./${design_name}.tcl
10 changes: 10 additions & 0 deletions boards/RFSoC4x2/rfsoc_sam/makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
all: block_design bitstream clean

block_design:
vivado -mode batch -source make_block_design.tcl -notrace

bitstream:
vivado -mode batch -source make_bitstream.tcl -notrace

clean:
rm -rf block_design *.jou *.log NA .Xil
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 03c00fa

Please sign in to comment.