Writing an image to an IP using AXI4 Master

Hello all, I’ve been trying, a bit in vain, to implement some of the examples in the vitis vision library. I’ve made a custom IP out of the resize example with almost no changes save for me changing which size I want the resulting image to be, shown here:

And I also followed this tutorial on how to use the axi master interface:

Here is the code I’ve written, mostly copied from the tutorial:
Resize_test.ipynb (353.4 KB)

One thing I don’t really understand is, how do I write the input image to the IP? I assumed it was just like reading the output, ie, write to a buffer, but it seems to not work like that. When I try to put the image directly into my_ip.register_map.img_inp_1 it says it expects only one value, not an array. When i write to the input buffer, it seems to not complain, but the output buffer is always empty. I’m hesitant to blame the IP because xilinx created it. Here is how the IP is hooked up:

I know I should use a DMA or VDMA, and I tried to do that, but the streaming IP I made didn’t seem to give the correct T_LAST signal to the regular DMA, and there weren’t any good examples of how to use the VDMA, so I figured I’ll just do it the easy way to start with, so I can at least get something done, albeit in a worse way.

Any help would be appreciated! I am using a PYNQ-Z2, vitis/vivado 2024.1, the latest tools, etc.

Can you check the status register after you expect the IP has complete (i.e. at the end of the code you shared) to check the status?

my_ip.register_map

Cathal

It seems to be the exact same as when I declare it:

You are creating a (contiguous) memory buffer with this line:

py_buffer_in = allocate(shape=(480, 640, 3), dtype=‘uint8’)

You copy your image into this buffer.

You then send the address of the buffer to the IP:

my_ip.register_map.img_inp_1 = py_buffer_in.physical_address

The HLS IP has AXI Master interfaces, which allows it to access the memory buffer directly so you don’t explicitly transfer the data.

Assuming the IP is working correctly, then I’d suggest adding ILA probes to the Zynq HP ports to check 1) if the correct memory addresses are being accessed, and 2) if you see the right data being read/written from the IP.

Cathal

The writing and reading from the buffer makes sense to me now, seems pretty straight forward, but that makes this all the more frustrating haha!

I wonder if it could be that I am using two HP ports on the zynq? Perhaps I am not interfacing with them both correctly. Or maybe my interrupts aren’t configured correctly?

Using two HPs is OK. There is an internal switch to the memory. You can also use 1x HP and the “switch” would be in the AXI interconnect.
If you check diagram 5.1 here: https://docs.amd.com/r/en-US/ug585-zynq-7000-SoC-TRM/Slave-Interconnect you can see this. Open the pdf from the left for a better quality image.

There is a slightly more optimal way to connect if you check image 5.4. I believe it can be a little better to connect two ports to S0 and S2, or S1 and S3 (due to S0 and S1, and S2 and S3 sharing the master connection to memory). For your design, this detail should not matter.

I’d suggest you add the ILA to the two HPs to watch the traffic on the HPs and make sure the IP is doing what you expect. You should see AXI transactions to addresses in your memory buffers.

Cathal

I think I’ve successfully attached ILA probes to the HP ports of the zynq and recorded their output. I chose to look at the address of the input image to check if it was getting any data, and I think it is not. Assuming that i am reading the chart correctly, RDATA staying all zeroes indicates that no data is actually being passed to the IP, or maybe something is getting wrapped or truncated to all zeroes?

I set the other HP port to activate when it sees WDATA(write data?) being anything except zeroes, it stays all zeroes all the time.

My suspicion is that it has something to do with the input/output pointer address declaration in the HLS code. It says 'Input image Dimensions ’ but I wasn’t sure what that meant. When I leave it at 128, the original value, the IP simulates and everything nicely. When I change it to the new dimensions, it breaks. The original picture was 128x128, resized to 64x64. The one I use is 640x480 resized to 224x224. I’m not really sure what they meant by 'Input image Dimensions ’ if not the number of pixels. They use this in the calculation that they use for the depth of the m_axi pragmas, so it must be total number of pixels in the image?

Here is a picture of the address buffer being accessed, I think:

I also attached an ILA to the gmem1 and 2 ports. The gmem2, where the output image is supposed to go, has addresses and such, but the gmem1 does not, and has only constants. It looks like this: