PYNQ: PYTHON PRODUCTIVITY FOR ZYNQ

Bitstream works ok when programmed by JTAG but not from Pynq

I am currently developing a Pynq project, using a Pynq-Z2. I have already followed the tuorials and successfully created and used bitstreams from Python using the leds and switches.

I have put together an audio IP block (which at present just passes audio through from line in to headphones). It works fine if used by itself and flashed to the board using JTAG.

I then put together a block diagram with a processor and AXI GPIO, as well as my audio block; at present there is no connection between them (this is to be developed later). This too still passes audio through fine if flashed over JTAG.

If however, I export the bitstream, hwh file and tcl file as described in the Pynq tutorial and upload them to a Jupyter Notebook folder, and then use the commands:
from pynq import Overlay
tutorial = Overlay(“design_1.bit”);
I see the green led flash, indicating that my bitstream has uploaded, but I get no audio passthrough output.

I’d be grateful if anyone can give me any insights as to what the problem might be and how to solve it.

A block diagram can be seen at

Instantiating the Overlay will do things like read meta info about the design, which will set PL clocks. I wonder if the clocks are not being set properly.
Have you constrained the clocks in your design properly?

I’m assuming each time you load with JTAG that this is after a PYNQ image has booted?
Did you try doing the load in different orders? i.e. Load using Overlay() and then download via JTAG, and also try the reverse without restarting the board?

Could you post your block diagram?

Cathal

Thanks Cathal.

I wondered about clocks too.

The current design just uses, externally, a separate 100MHz clock tied to a pin, and the following constraints; there is also a 48MHz clock generated from it then divided by 2 for the master clock snet to the Audio Codec.

create_clock -period 10.000 -name clk_100 [get_ports clk_100]
set_false_path -from [get_clocks zed_audio_clk_48M] -to [get_clocks clk_100]
set_false_path -from [get_clocks clk_100] -to [get_clocks zed_audio_clk_48M]
set_property -dict { PACKAGE_PIN H16   IOSTANDARD LVCMOS33 } [get_ports { clk_100 }]

I too wondered if clocks might by the cause of the problem, so tried switching from using clk_100 above to instead using the same 100MHz clock used for the PS and AXI. I still got no audio passthrough.

My block diagram is posted in that link to the Xilinx site above - just click on it and scroll down.

You mention that instantiating the overlay sets PL clocks. I’ve looked through the documentation, but I cannot find anywhere a full statement of exactly what does happen, and that as a result, you should or should not do various things in your own bitstreams. Does that documentation exist? If it does, I’d be grateful for a reference.

When I loaded it with JTAG, I didn’t bother with the PYNQ image at all. I just set the jumper for loading from JTAG, powered up, and flashed my bitstream into it to check it works OK at least in terms of passing audio through. I’m not too sure how to flash via JTAG without changing the jumper, - can I just change it after PYNQ is running?

Another possibility that occurs to me is that, as PNYQ already loads the base overlay at start up, maybe some part of the base overlay is not being cleared before a user overlay is loaded. I’d hope that isn’t the case, but I am rather clutching at straws in the absence of any documented restrictions.

Anyway, thanks again.

You mention that instantiating the overlay sets PL clocks. I’ve looked through the documentation, but I cannot find anywhere a full statement of exactly what does happen, and that as a result, you should or should not do various things in your own bitstreams. Does that documentation exist? If it does, I’d be grateful for a reference.

https://pynq.readthedocs.io/en/v2.5/overlay_design_methodology/overlay_design.html#zynq-ps-settings

EDIT: in the documentation only tcl is mentioned, but it will work with the hwh as well

What is your clock_100 connected to?

If you are using the PL “Ethernet” clock, this clock is unstable unless an Ethernet cable is plugging in. If you are using PYNQ this should be OK - assuming you have the cable plugged in.

For reference, the boot jumper determines the boot source for the board [SD|flash|JTAG]
If you set to SD and boot the board, you can still load a bitstream via JTAG later.

You could try chipscope this block to see what is going on and if you have any activity on the block.

The base overlay “not being cleared” shouldn’t be an issue.

Cathal

1 Like

Thanks gnatale - but that link says that Pynq should set the clocks up as per the overlay’s request. So this implies that I dont have to take care of anything, and that the necessary info will be acquired from the tcl, or hwh, file.

“The PL clocks can be programmed at runtime to match the requirements of the overlay. This is managed automatically by the PYNQ Overlay class.
During the process of downloading a new overlay, the clock configuration will be parsed from the overlay’s Tcl file. The new clock settings for the overlay will be applied automatically before the overlay is downloaded.”

Thanks again Cathal, As the extract from my constraint file shows, clk_100 is connected to pin H16. Whenever I have tried this, Ethernet has been plugged in, so that’s not an issue.

As I said (implictly) above, I also tried using FCLK_CLK0, which Pynq reports as running at 100MHz, but that did not work either.

Thanks for pointing out that I had a misunderstanding about the jumper, which is just for selecting the boot source.

I tried firing up Pynq first, loading the overlay, then redownloading the bitstream over JTAG. I got no audio.
I also tried firing up Pynq, downloading the bitstream over JTAG (no audio), then loading the overlay (still no audio).

I only get audio if I leave Pynq completely out of the equation.

Well, here is an unhelpful but maybe informative data point.

Previously, the clk_100 port was just marked as a regular port in the IP Packager.
I changed it to be marked as a Clock port.

After doing that, loading the overlay with
audio_controller = Overlay("new.bit");
completely locks up Pynq - web pages dont respond, nor does ssh, ftp, etc.
Something odd is happening with clocks it seems.

I struggled with clocking in my first project, which was a frequency counter. The clk_100 input to your block definitely needs to be connected to the PS clock (FCLK_CLK0). You’ll need this later for AXI to work. Now you need a clock for whatever is to the left of the diagram you shared. I think the best way would be to connect the PS clock to an output pin and use it to drive that.

If you don’t use the PS clock to drive everything, you have two clock domains and need to deal with crossing the clock domain boundary. This is done by running each of your GPIO signals through a 2 or 3 bit register clocked like this:

module sync (
input clk_100,
input signal,
output synced_signal
);
reg [2:0] sync_register;
always @(posedge clk_100)
begin
sync_register <= {sync_register[1:0], signal};
end
assign synced_signal = sync_register[2];
endmodule

You’ll need to instantiate one of these for each of your GPIO lines.

Anyway, see if any of this helps, I’m a beginner here too.

Steve

thanks for your comments. I’ve already tried an alternative to the one in my block diagram with clk_100 connected to FCLK_CLK0, but that gave just the same outcome - worked as a standalone bitstream, not when loaded from Pynq.

The only way I’ll be using AXI in future is to send parameters to the Audio IP Block, to change its settings (interface for this is not yet present), and the timing of this wont be critical. Audio data will always be going from from the codec, into the audio processing block, then back to the codec, not involving the PS.

There is a clock domain crossing problem with the Audio MCLK signal, which is resolved inside the Audio IP itself.

However, I’ll look again at how the clk_100 is being buffered inside the Audio IP,

Thanks

At this stage I’d chipscope the IP to check the signals coming in and going out.

Can you share the design?

Cathal

After a discussion with @PeterOgden he pointed out that booting PYNQ on the Z2 does some config of the audio codec on this board at boot.

In your IP, are you doing a partial config of the codec or are you assuming some default? We think there might be a conflict here.

Cathal

(1) I’ve not used chipscope before - so if it doesn’t show what I expect, I’ll not be too confident that its showing useful debugging info, or if I am compounding the problem by faulty chipscope technique.

(2) My design is trivial, so far, in that it takes the hdl from here:
https://github.com/ems-kl/zedboard_audio
(selecting audio passthorugh as the top level code)
and uses the IP packager to wrap it it up as an IP,
I swap the zedboard constraints entries for corresponding Pynq Z2 ones
then I create a block diagram with

  • a processor and AXI GPIO wired to each other with authomation,
  • the audio IP block connected to external ports,
    as shown. Tha’ts it (so far).
    I’d be happy to let you have all the files if you could look at them. Thank you.

(3) The audio IP carefully initialises the codec before it starts reading and writing data from it. The design at
https://github.com/ems-kl/zedboard_audio
is actually a slight improvement of the code here
https://web.archive.org/web/20190621023314/http://hamsterworks.co.nz/mediawiki/index.php/Zedboard_Audio
which explains how the initialisation is carried out.

Can you try disabling the boot leds service with sudo systemctl disable boot_leds and restarting the board from a cold power on? That will stop PYNQ from loading any bitstream on boot and remove any possibility of conflict with the audio codec configuration. It might also be worth routing an output from the system clock to an LED to confirm that there is some activity on the clocking line.

Peter

Thank you Peter,

Disabling the boot leds service did the trick. Whatever the bitstream loaded at boot time is doing, it’s preventing my bitstream from re-initialising the audio codec.

If you could give me a pointer to where to see the source of this bitstream, I’ll see if I can figure it out, and if there is some way to work round it.

On the other hand, even after my bistream is loaded and going, I get some glitches and buzzing in the audio output (which I dont if the bistream is loaded directly without Pynq). Does Pynq mess around with the system clocks in some way?

Ralph

The bitstream is the base bitstream the source for which is the in boardssubfolder of the PYNQ git repo. We program the chip from software using a Linux I2C device and the code in audio_adau1761.cpp.

PYNQ doesn’t touch the system clock directly however it’s possible that Linux is doing some. The clock is generated by the Ethernet PHY and is notionally 125 MHz. The Linux driver might be doing something to the PHY that causes this clock to change but I’m not entirely sure.

Peter

OK, I believe the issue is the following. The codec is setup by audio_adau1761.cpp using a PLL master clock frequency of 10MHz, whereas I’m using 25MHz * (which is easy to get by dividing the 100MHz clock by 4). The code I am using fails to turn off the PLL before changing its configuration, as per the datasheet requirements, I suppose because it assumes it is programming the codec from a cold start.

Thanks everyone for your help in tracking down the issue. Onwards and upwards to writing my application!