cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
dimiter
Contributor
Contributor
1,083 Views
Registered: ‎06-10-2018

Vitis Vision cores AXI4 Stream buggy

Jump to solution

I'm trying to create streaming interfaces for the Vitis vision cores. Specifically I'm trying to replicate the Vitis resize IP core used on PYNQ.

The generated cores contain streaming interfaces however they cause the DMA transfer to stall on the receive side. The issue was isolated with the Vitis Vison cores.  A custom HLS core without the sidebands works.

The resize IP passes C simulation but fails on hardware. The PYNQ HLS resize example uses custom interfaces with a buggy version of Vitis vison library. Compiling that against the current version gives errors.

 

Attached are the modified Vitis resize HLS files and python script.

The cores were also tested with baremetal library and it fails after starting the Vitis resize IP. AXI4 lite communication proceeds correctly but streaming data stalls. DMA is configured as 32 bit word width with data width converter.

 

This implies that all Vitis vision at the moment cannot be used with a streaming interface unlike what the website states.

 

Resize_ip.c

 

 

void resize_accel(hls::stream< xf::cv::ap_axiu<24, 1, 1, 1> > &srcPtr, hls::stream< xf::cv::ap_axiu<24, 1, 1, 1> > &dstPtr, int rows_in, int cols_in,  int rows_out,  int cols_out) {
// clang-format off

    #pragma HLS INTERFACE axis port=srcPtr
    #pragma HLS INTERFACE axis port=dstPtr

    #pragma HLS INTERFACE s_axilite port=rows_in              
    #pragma HLS INTERFACE s_axilite port=cols_in              
    #pragma HLS INTERFACE s_axilite port=rows_out              
    #pragma HLS INTERFACE s_axilite port=cols_out              
    #pragma HLS INTERFACE s_axilite port=return
    // clang-format on

    xf::cv::Mat<TYPE, HEIGHT, WIDTH, NPC_T> in_mat(rows_in, cols_in);

    xf::cv::Mat<TYPE, NEWHEIGHT, NEWWIDTH, NPC_T> out_mat(rows_out, cols_out);

// clang-format off
    #pragma HLS DATAFLOW
    // clang-format on


    xf::cv::AXIvideo2xfMat<INPUT_PTR_WIDTH,TYPE,HEIGHT,WIDTH,NPC_T>(srcPtr, in_mat);

    xf::cv::resize<INTERPOLATION, TYPE, HEIGHT, WIDTH, NEWHEIGHT, NEWWIDTH, NPC_T, MAXDOWNSCALE>(in_mat, out_mat);
    
    xf::cv::xfMat2AXIvideo<OUTPUT_PTR_WIDTH,TYPE,NEWHEIGHT,NEWWIDTH,NPC_T>(out_mat, dstPtr);    

}

 

 

 

Resize_ip test.c

 

 

#include "common/xf_headers.hpp"
#include "xf_resize_config.h"

int main(int argc, char** argv) {
    cv::Mat img, out_img, result_ocv, error;

    if (argc != 2) {
        printf("Usage : <executable> <input image> \n");
        return -1;
    }

#if GRAY
    img.create(cv::Size(WIDTH, HEIGHT), CV_8UC1);
    out_img.create(cv::Size(NEWWIDTH, NEWHEIGHT), CV_8UC1);
    result_ocv.create(cv::Size(NEWWIDTH, NEWHEIGHT), CV_8UC1);
    error.create(cv::Size(NEWWIDTH, NEWHEIGHT), CV_8UC1);
#else
    img.create(cv::Size(WIDTH, HEIGHT), CV_8UC3);
    result_ocv.create(cv::Size(NEWWIDTH, NEWHEIGHT), CV_8UC3);
    out_img.create(cv::Size(NEWWIDTH, NEWHEIGHT), CV_8UC3);
    error.create(cv::Size(NEWWIDTH, NEWHEIGHT), CV_8UC3);
#endif

#if GRAY
    // reading in the color image
    img = cv::imread(argv[1], 0);
#else
    img = cv::imread(argv[1], 1);
#endif

    if (!img.data) {
        return -1;
    }

    cv::imwrite("input.png", img);

    unsigned short in_width, in_height;
    unsigned short out_width, out_height;

    in_width = img.cols;
    in_height = img.rows;
    out_height = NEWHEIGHT;
    out_width = NEWWIDTH;

/*OpenCV resize function*/

#if INTERPOLATION == 0
    cv::resize(img, result_ocv, cv::Size(out_width, out_height), 0, 0, CV_INTER_NN);
#endif
#if INTERPOLATION == 1
    cv::resize(img, result_ocv, cv::Size(out_width, out_height), 0, 0, CV_INTER_LINEAR);
#endif
#if INTERPOLATION == 2
    cv::resize(img, result_ocv, cv::Size(out_width, out_height), 0, 0, CV_INTER_AREA);
#endif

    /* Call the top function */

    hls::stream< xf::cv::ap_axiu<24, 1, 1, 1> > _src;
    hls::stream< xf::cv::ap_axiu<24, 1, 1, 1> > _dst;

  // Call the top function
    static xf::cv::Mat<XF_8UC3, HEIGHT, WIDTH, NPC_T> 		imgInput(in_height, in_width);
    static xf::cv::Mat<XF_8UC3, NEWHEIGHT, NEWHEIGHT, NPC_T>  	imgOutput(out_height, out_width);


    imgInput.copyTo(img.data);

    xf::cv::xfMat2AXIvideo(imgInput, _src);
    resize_accel(_src, _dst,in_height,in_width,out_height,out_width);
    xf::cv::AXIvideo2xfMat(_dst, imgOutput);
    
    out_img.data = imgOutput.copyFrom();


    //resize_accel((ap_uint<INPUT_PTR_WIDTH>*)img.data, (ap_uint<OUTPUT_PTR_WIDTH>*)out_img.data, in_height, in_width, out_height, out_width);

    float err_per;
    cv::absdiff(result_ocv, out_img, error);
    xf::cv::analyzeDiff(error, 5, err_per);
    cv::imwrite("hls_out.png", out_img);
    cv::imwrite("resize_ocv.png", result_ocv);
    cv::imwrite("error.png", error);

    if (err_per > 0.0f) {
        printf("\nTest Failed\n");
       // return -1;
    }

    return 0;
}

 

 

 

 

 

from PIL import Image
import numpy as np
from IPython.display import display
from pynq import Overlay, allocate

resize_design = Overlay("resize.bit")

dma = resize_design.axi_dma_0
resizer = resize_design.resize_accel_0
image_path = "paris.jpg"
original_image = Image.open(image_path)
original_image.load()

input_array = np.array(original_image)

old_width, old_height = original_image.size
print("Image size: {}x{} pixels.".format(old_width, old_height))

input_image = Image.fromarray(input_array)
display(input_image)

resize_factor = 2
new_width = int(old_width/resize_factor)
new_height = int(old_height/resize_factor)

in_buffer = allocate(shape=(old_height, old_width, 3), dtype=np.uint8, cacheable=True)
out_buffer = allocate(shape=(new_height, new_width, 3), dtype=np.uint8, cacheable=True)

in_buffer[:] = input_array

buf_image = Image.fromarray(in_buffer)
display(buf_image)
print("Image size: {}x{} pixels.".format(old_width, old_height))

resizer.write(0x10, old_height)
resizer.write(0x18, old_width)
resizer.write(0x20, new_height)
resizer.write(0x28, new_width)

def run_kernel():
    dma.sendchannel.transfer(in_buffer)
    dma.recvchannel.transfer(out_buffer)    
    resizer.write(0x00,0x81) # start
    dma.sendchannel.wait()
    dma.recvchannel.wait()                  ############Fails here

run_kernel()

result = Image.fromarray(out_buffer)
display(result)
print("Resized in Hardware(PL): {}x{} pixels.".format(new_width, new_height))

 

 

1.png

 

 

0 Kudos
1 Solution

Accepted Solutions
dimiter
Contributor
Contributor
800 Views
Registered: ‎06-10-2018

Just to confirm , this issue is related to this bug

https://github.com/Xilinx/Vitis_Libraries/issues/28

 

To get around it one needs to use a custom datatype and /or custom converison functions.

 

struct axis_t {
ap_uint<8> data;
ap_int<1> last;
};

 

 

 

View solution in original post

0 Kudos
3 Replies
dimiter
Contributor
Contributor
1,005 Views
Registered: ‎06-10-2018

I tested the same IP in AXI mode (original form from library) and it does not work either. The core passes C simulation and COSIM but fails on hardware (Ultra96)

Any idea what is wrong with the Vitis Vision L1 cores?

 

Untitled.png

0 Kudos
dimiter
Contributor
Contributor
936 Views
Registered: ‎06-10-2018

Here is the procedure for anyone willing to replicate this bug:

Vivado 2020.1, Ubuntu 18.04, Vitis_hls or Vivado_hls

 

 

# STEP 1 - Install CMAKE

sudo apt-get install cmake

# STEP 2 - Install vitis vision


git clone https://github.com/Xilinx/Vitis_Libraries.git

 

# STEP 3 - Install OpenCv 3.4


mkdir ~/opencv_build && cd ~/opencv_build
#git clone https://github.com/opencv/opencv.git
#git clone https://github.com/opencv/opencv_contrib.git

wget -O opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/3.4.4.zip
wget -O opencv.zip https://github.com/opencv/opencv/archive/3.4.4.zip

cd ~/opencv_build/opencv
mkdir build && cd build

mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_CUDA=OFF -D INSTALL_PYTHON_EXAMPLES=ON -D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib/modules -D OPENCV_ENABLE_NONFREE=ON -D BUILD_EXAMPLES=ON ..

make -j4
sudo make install
sudo ldconfig

pkg-config --modversion opencv
ls /usr/local/python/cv2/python-3.6
cd /usr/local/python/cv2/python-3.6
sudo mv cv2.cpython-36m-x86_64-linux-gnu.so cv2.so

 

#STEP 4 - Modify threshold IP with streaming interface

Copy threshold folder to a folder called threshold_strm


Use attached zip file and change user with you user name on  run.tcl file with :

 

#source settings.tcl

set PROJ "threshold.prj"
set SOLN "sol1"

set XF_PROJ_ROOT "/home/user/Documents/Vitis_Libraries/vision/"
set OPENCV_INCLUDE "/usr/local/include/opencv2"
set OPENCV_LIB "/usr/local/lib"
set XPART "xczu9eg-ffvb1156-2-i"
set CSIM "1"
set CSYNTH "1"
set COSIM "0"
set VIVADO_SYN "0"
set VIVADO_IMPL "0"

 

 

 


STEP #5 - Test IP CSIM and COSIM

 

vivado_hsl -f script.tcl

 

STEP #6  Generate core

 

Modify width and height dimensions:

 

/* set the height and width */
#define HEIGHT 640
#define WIDTH 480

 

generate core again by issuing :

 

vivado_hsl -f script.tcl

 

STEP #6 Use Generated IP to build DMA loopback test with threshold IP in the middle.

Fails here one the DMA receive side.  This was tested with both Vitis SDK and pynq.

 

The core was generated with both Vitis_hls and Vivado_hls.

 

On Ubuntu , to pass cosim one has to add the gmp file to the include path..

 

 

 

0 Kudos
dimiter
Contributor
Contributor
801 Views
Registered: ‎06-10-2018

Just to confirm , this issue is related to this bug

https://github.com/Xilinx/Vitis_Libraries/issues/28

 

To get around it one needs to use a custom datatype and /or custom converison functions.

 

struct axis_t {
ap_uint<8> data;
ap_int<1> last;
};

 

 

 

View solution in original post

0 Kudos