Hello,
Resorting to help after a month or so of learning curve
I’m trying to use the recently released PYNQ 2.7 image for the ZCU216 (here).
I’ve read through plenty of documentation on the examples and the CLK104. Namely this, this, and this.
From what I understand, the B2 and B3 pins on the LPA connector pinout (here) correspond to the E5 and E6 pins on the RFSoC, which in turn can be pulled in to the “dac2_clk” signal, which is associated with the DAC230 tile, correct?
I’d like to use only this reference clock (and not the SSMP cables), to drive the RF Data Converter. Is this possible? (According to the example here which uses only the LMK reference clock for the DACs/ADCs, I understand that it is).
Want I want to do (for now) is very simple: send out a constant tone through DAC230 (which is Tile 2 on the ZCU216 Gen3, I think).
My design:
My RFDC DAC230 and clocking config:
PL Clock is 100Mhz coming from the PS system. Design validation returns no errors. The bitstream generated without errors, and the dac2_clk pins are bound to the E5 and E6 I/Os:
I already have the SDcard booting with PYNQ 2.7 (I’ve tested other example overlays with simple I/O, or even the DMA loopback example, that all works fine). I scp my overlay and hwh into the board, change to root with “su -”, and call python (the bundled version is 3.8).
Following I do:
>>> import xrfclk
>>> import xrfdc
library loaded!
xrfclk.set_ref_clks(245.76)
Using an oscilloscope, I can check the OUTPUT_REF SMA on the CLK104 and see the 7.68Mhz clock being generated after this call. I’m assuming that as this point, the dac2_clk clock is at 245.76MHz (as per example 1 here).
At this point there are few doubts:
- Are the values of the DAC_REFCLK and ADC_REFCLK actually 245.76Mhz? (These are the outputs labeled DOut6 and DOut12 in the CLK104 documentation)
- What is the value of PL_CLK? Do I need to pull into the FPGA? What for and how?
- What is the value of PL_SYSREF? Do I need to pull into the FPGA? What for and how?
- What is the purpose of the CLK_SPI_MUX_SEL0 and CLK_SPI_MUX_SEL1 pins (which I can control using GPIO from the FPGA). Are they required? Other example designs I’ve seen do not use them. Do I need to set this these pins to 0b’01 to select the 10MHz oscillator (U4) on the CLK104, or is this selection controlled via SPI (and therefore using the xrfclk library when calling set_ref_clks).
Regardless, I can invoke the Overlay function (btw, the question mark operator on the overlay returns a syntax error from the Python interpreter with any overlay I use, help?). I do a quick test on the LEDs to make sure I can change the values, which I can.
Then:
>>> ol = Overlay("/home/xilinx/overlays/ex2v2/mpsoc_preset.bit", ignore_version=True)
>>> ol? # :(
File "<stdin>", line 1
ol?
^
SyntaxError: invalid syntax
>>> leds = ol.axi_gpio_0.channel1
>>> leds.write(45645, 0xfffffffff) # leds work :)
>>> rf = ol.usp_rf_data_converter_0
>>> rf.IPStatus
{'DACTileStatus': [{'IsEnabled': 1, 'TileState': 0, 'BlockStatusMask': 1, 'PowerUpState': 0, 'PLLState': 0}, {'IsEnabled': 0, 'TileState': 0, 'BlockStatusMask': 0, 'PowerUpState': 0, 'PLLState': 0}, {'IsEnabled': 1, 'TileState': 0, 'BlockStatusMask': 3, 'PowerUpState': 0, 'PLLState': 0}, {'IsEnabled': 1, 'TileState': 0, 'BlockStatusMask': 10, 'PowerUpState': 0, 'PLLState': 0}], 'ADCTileStatus': [{'IsEnabled': 0, 'TileState': 0, 'BlockStatusMask': 0, 'PowerUpState': 0, 'PLLState': 0}, {'IsEnabled': 0, 'TileState': 0, 'BlockStatusMask': 0, 'PowerUpState': 0, 'PLLState': 0}, {'IsEnabled': 1, 'TileState': 0, 'BlockStatusMask': 3, 'PowerUpState': 0, 'PLLState': 0}, {'IsEnabled': 0, 'TileState': 0, 'BlockStatusMask': 0, 'PowerUpState': 0, 'PLLState': 0}], 'State': 0}
If I check the IPStatus frequently (i.e., spam it), I notice that the “IsEnabled” flag of the tiles changes from 0 to 1, as well as the BlockStatusMask (hence why I’m assuming this is a clocking issue?).
>>> tile2= rf.dac_tiles[2]
>>> tile2
<xrfdc.RFdcDacTile object at 0xffff954f6700>
>>> tile2.PLLConfig
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/share/pynq-venv/lib/python3.8/site-packages/xrfdc/__init__.py", line 205, in _get
c_func(f"Get{name}", value)
File "/usr/local/share/pynq-venv/lib/python3.8/site-packages/xrfdc/__init__.py", line 333, in _call_function
return self._parent._call_function(name, self._type, self._index, *args)
File "/usr/local/share/pynq-venv/lib/python3.8/site-packages/xrfdc/__init__.py", line 402, in _call_function
_safe_wrapper(f"XRFdc_{name}", self._instance, *args)
File "/usr/local/share/pynq-venv/lib/python3.8/site-packages/xrfdc/__init__.py", line 71, in _safe_wrapper
raise RuntimeError(message)
RuntimeError: Function XRFdc_GetPLLConfig call failed
stdout: metal: error:
Requested tile (DAC 2) not available in XRFdc_GetPLLConfig
The same happens for all DAC and ADC tiles. Curiously, if I program the FPGA with existing overlays (e.g., rfsoc-sam, rfsoc-qpsk), I can query the tile status without this error, despite not having the SSMP cables connected, which these designs expect. (Note that I call the Overlay function directly on these bitstreams, since I don’t want all the Python GUI interfaces over Jupyter at this point). For example:
>>> ol = Overlay("/usr/local/share/pynq-venv/lib/python3.8/site-packages/rfsoc_qpsk/rfsoc_qpsk/bitstream/rfsoc_qpsk.bit")
>>> rf = ol.usp_rf_data_converter_0
>>> dac_tile = rf.dac_tiles[2]
>>> dac_tile
>>> dac_tile.PLLConfig
{'Enabled': 1, 'RefClkFreq': 409.6, 'SampleRate': 1.024, 'RefClkDivider': 1, 'FeedbackDivider': 20, 'OutputDivider': 8, 'FractionalMode': 0, 'FractionalData': 0, 'FractWidth': 0}
I guess my first question would be: is my block diagram and clocking correct? What is the simplest snippet of Python code I can write to send a tone out?
Many thanks!
Nuno