The Digilent Basys3 board is a very capable board to get started developing FPGA projects with. It provides the users with an Artix 35T device, USB-UART, Four Pmods - Including one configured for the XADC, 12 bit VGA and switches, LED and Seven Segment Display.
This project is designed to demonstrate just how capable the Basys3 board is, to do that we are going to create a simple oscilloscope which can use the XDAC Pmod input channels and the VGA display to display the waveform.
To do this we are going to use a MicroBlaze controller to run the application and control the measurement of the XADC and determine where to plot the data on the VGA screen.
The VGA Display will be 640 by 480, 12 bit RGB to render this in software memory would require 3, 686, 400 bits. This exceeds the 1, 800, 000 bits of BRAM available in the FPGA. The processor is unable also to run at the speed necessary to be able to achieve the required frame rate.
We will get around this issue by using the processor to determine the data point plots, while the logic renders the frame for display in real time. To do this we are going to be using a High Level Synthesis Core which we create first.
High Level Synthesis CoreTo get started was re going to create a HLS core which can plot up to 10 samples in the VGA display (you can of course change this later). The HLS core will generate a AXI Stream which is 640 pixels by 480 lines. To update the display on each frame there will be sample_x / _y registers which define the location of the sample data, a register to define the size of the data point, and a final register to define the data point color.
Creating HLS streams requires a simple definition using the ap_fixed.h and hls_video.h libraries.
We will have a 32 bit pixel, which includes 8 bits for each RGB but also a 8 bit alpha channel for blending.
The hud.h file includes the following lines
#include "hls_video.h"
#include <ap_fixed.h>
#include "string.h"
#define WIDTH 32 //32 as alpha channel
typedef ap_uint<8> pixel_type;
typedef hls::stream<ap_axiu<WIDTH,1,1,1> > axis;
typedef ap_axiu<WIDTH,1,1,1> video_stream;
void hud_gen(axis& op,
int row,
int column,
int plot_x_1,
int plot_y_1,
int plot_x_2,
int plot_y_2,
int plot_x_3,
int plot_y_3,
int plot_x_4,
int plot_y_4,
int plot_x_5,
int plot_y_5,
int plot_x_6,
int plot_y_6,
int plot_x_7,
int plot_y_7,
int plot_x_8,
int plot_y_8,
int plot_x_9,
int plot_y_9,
int plot_x_10,
int plot_y_10,
int plot_x_11,
int plot_y_11,
int plot_x_12,
int plot_y_12,
int plot_x_13,
int plot_y_13,
int plot_x_14,
int plot_y_14,
int plot_x_15,
int plot_y_15,
int plot_x_16,
int plot_y_16,
int plot_x_17,
int plot_y_17,
int plot_x_18,
int plot_y_18,
int plot_x_19,
int plot_y_19,
int plot_x_20,
int plot_y_20,
int plot_size,
uint32_t plot_colour ) ;
While the main body of code looks like
#include "hud.h"
//#include "char.h"
void hud_gen(axis& op,
int row,
int column,
int plot_x_1,
int plot_y_1,
int plot_x_2,
int plot_y_2,
int plot_x_3,
int plot_y_3,
int plot_x_4,
int plot_y_4,
int plot_x_5,
int plot_y_5,
int plot_x_6,
int plot_y_6,
int plot_x_7,
int plot_y_7,
int plot_x_8,
int plot_y_8,
int plot_x_9,
int plot_y_9,
int plot_x_10,
int plot_y_10,
int plot_x_11,
int plot_y_11,
int plot_x_12,
int plot_y_12,
int plot_x_13,
int plot_y_13,
int plot_x_14,
int plot_y_14,
int plot_x_15,
int plot_y_15,
int plot_x_16,
int plot_y_16,
int plot_x_17,
int plot_y_17,
int plot_x_18,
int plot_y_18,
int plot_x_19,
int plot_y_19,
int plot_x_20,
int plot_y_20,
int plot_size,
uint32_t plot_colour ) {
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE s_axilite port=plot_y_1
#pragma HLS INTERFACE s_axilite port=plot_x_1
#pragma HLS INTERFACE s_axilite port=plot_y_2
#pragma HLS INTERFACE s_axilite port=plot_x_2
#pragma HLS INTERFACE s_axilite port=plot_y_3
#pragma HLS INTERFACE s_axilite port=plot_x_3
#pragma HLS INTERFACE s_axilite port=plot_y_4
#pragma HLS INTERFACE s_axilite port=plot_x_4
#pragma HLS INTERFACE s_axilite port=plot_y_5
#pragma HLS INTERFACE s_axilite port=plot_x_5
#pragma HLS INTERFACE s_axilite port=plot_y_6
#pragma HLS INTERFACE s_axilite port=plot_x_6
#pragma HLS INTERFACE s_axilite port=plot_y_7
#pragma HLS INTERFACE s_axilite port=plot_x_7
#pragma HLS INTERFACE s_axilite port=plot_y_8
#pragma HLS INTERFACE s_axilite port=plot_x_8
#pragma HLS INTERFACE s_axilite port=plot_y_9
#pragma HLS INTERFACE s_axilite port=plot_x_9
#pragma HLS INTERFACE s_axilite port=plot_y_10
#pragma HLS INTERFACE s_axilite port=plot_x_10
#pragma HLS INTERFACE s_axilite port=plot_y_11
#pragma HLS INTERFACE s_axilite port=plot_x_11
#pragma HLS INTERFACE s_axilite port=plot_y_12
#pragma HLS INTERFACE s_axilite port=plot_x_12
#pragma HLS INTERFACE s_axilite port=plot_y_13
#pragma HLS INTERFACE s_axilite port=plot_x_13
#pragma HLS INTERFACE s_axilite port=plot_y_14
#pragma HLS INTERFACE s_axilite port=plot_x_14
#pragma HLS INTERFACE s_axilite port=plot_y_15
#pragma HLS INTERFACE s_axilite port=plot_x_15
#pragma HLS INTERFACE s_axilite port=plot_y_16
#pragma HLS INTERFACE s_axilite port=plot_x_16
#pragma HLS INTERFACE s_axilite port=plot_y_17
#pragma HLS INTERFACE s_axilite port=plot_x_17
#pragma HLS INTERFACE s_axilite port=plot_y_18
#pragma HLS INTERFACE s_axilite port=plot_x_18
#pragma HLS INTERFACE s_axilite port=plot_y_19
#pragma HLS INTERFACE s_axilite port=plot_x_19
#pragma HLS INTERFACE s_axilite port=plot_y_20
#pragma HLS INTERFACE s_axilite port=plot_x_20
#pragma HLS INTERFACE s_axilite port=column
#pragma HLS INTERFACE s_axilite port=row
#pragma HLS INTERFACE s_axilite port=plot_size
#pragma HLS INTERFACE s_axilite port=plot_colour
#pragma HLS INTERFACE axis register both port=op
int i = 0;
int y = 0;
int x = 0;
//int bar_pos_x = 10;
//int bar_width = 30;
video_stream hud_int;
row_loop:for (y =0; y<row; y++){
column_loop:for (x =0; x < column; x++) {
if (y == 0 && x == 0 ){
hud_int.user = 1;
}
else{
if (x == (column-1) ){
hud_int.last = 1;
}
else{
hud_int.last = 0;
hud_int.user = 0;
if ((( x >= (plot_x_1 - plot_size)) & (x <= plot_x_1 + plot_size)) & (( y >= (plot_y_1 - plot_size)) & (y <= plot_y_1 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_2 - plot_size)) & (x <= plot_x_2 + plot_size)) & (( y >= (plot_y_2 - plot_size)) & (y <= plot_y_2 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_3 - plot_size)) & (x <= plot_x_3 + plot_size)) & (( y >= (plot_y_3 - plot_size)) & (y <= plot_y_3 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_4 - plot_size)) & (x <= plot_x_4 + plot_size)) & (( y >= (plot_y_4 - plot_size)) & (y <= plot_y_4 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_5 - plot_size)) & (x <= plot_x_5 + plot_size)) & (( y >= (plot_y_5 - plot_size)) & (y <= plot_y_5 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_6 - plot_size)) & (x <= plot_x_6 + plot_size)) & (( y >= (plot_y_6 - plot_size)) & (y <= plot_y_6 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_7 - plot_size)) & (x <= plot_x_7 + plot_size)) & (( y >= (plot_y_7 - plot_size)) & (y <= plot_y_7 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_8 - plot_size)) & (x <= plot_x_8 + plot_size)) & (( y >= (plot_y_8 - plot_size)) & (y <= plot_y_8 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_9 - plot_size)) & (x <= plot_x_9 + plot_size)) & (( y >= (plot_y_9 - plot_size)) & (y <= plot_y_9 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_10 - plot_size)) & (x <= plot_x_10 + plot_size)) & (( y >= (plot_y_10 - plot_size)) & (y <= plot_y_10 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_11 - plot_size)) & (x <= plot_x_11 + plot_size)) & (( y >= (plot_y_11 - plot_size)) & (y <= plot_y_11 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_12 - plot_size)) & (x <= plot_x_12 + plot_size)) & (( y >= (plot_y_12 - plot_size)) & (y <= plot_y_12 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_13 - plot_size)) & (x <= plot_x_13 + plot_size)) & (( y >= (plot_y_13 - plot_size)) & (y <= plot_y_13 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_14 - plot_size)) & (x <= plot_x_14 + plot_size)) & (( y >= (plot_y_14 - plot_size)) & (y <= plot_y_14 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_15 - plot_size)) & (x <= plot_x_15 + plot_size)) & (( y >= (plot_y_15 - plot_size)) & (y <= plot_y_15 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_16 - plot_size)) & (x <= plot_x_16 + plot_size)) & (( y >= (plot_y_16 - plot_size)) & (y <= plot_y_16 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_17 - plot_size)) & (x <= plot_x_17 + plot_size)) & (( y >= (plot_y_17 - plot_size)) & (y <= plot_y_17 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_18 - plot_size)) & (x <= plot_x_18 + plot_size)) & (( y >= (plot_y_18 - plot_size)) & (y <= plot_y_18 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_19 - plot_size)) & (x <= plot_x_19 + plot_size)) & (( y >= (plot_y_19 - plot_size)) & (y <= plot_y_19 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else if ((( x >= (plot_x_20 - plot_size)) & (x <= plot_x_20 + plot_size)) & (( y >= (plot_y_20 - plot_size)) & (y <= plot_y_20 + plot_size))){
hud_int.data = 0x7f0000ff;//0x7f0000ff; //should be green and high alpha
}
else{
if (( y >= 0 & y < 3 ) | ( y>= column-3 & y < column) | (x >= 0 & x < 3)){
hud_int.data = 0x7f0000ff;
} else {
hud_int.data = 0;
}
}
}
}
op.write(hud_int);
}
}
}
Notice how I use two loops to create the X and Y elements of the image in the stream. Within the inner loop we address the start of frame and end of line side band signals which are on the TUser and TLast signals.
The next step is to simulate the circuit using C to ensure the behaviour is as we want
The Test Bench created which can be used for C and Co Simulation
#include "hud.h"
#include <hls_opencv.h>
int main (int argc, char** argv) {
IplImage* src;
IplImage* dst;
axis dst_axi;
int y;
dst = cvCreateImage(cvSize(640,480),IPL_DEPTH_32S, 1);
//hud_gen( dst_axi, 480, 640, 240, 320, 5, 0x7f0000ff, 600, 30);
hud_gen( dst_axi,
480,
640,
0,
141,
32,
158,
64,
140,
96,
145,
128,
150,
160,
140,
192,
130,
224,
145,
256,
156,
288,
135,
320,
130,
352,
140,
384,
149,
416,
139,
448,
130,
480,
140,
512,
160,
544,
140,
576,
145,
608,
150,
5,
0x7f0000ff );
AXIvideo2IplImage(dst_axi, dst);
cvSaveImage("op.bmp", dst);
cvReleaseImage(&dst);
}
Running the C Simulation provides us a BMP image which should demonstrate the points plotted
In this example the data points are the white points plotted.
With the performance happy the next step is to synthesize and package the IP block for use in the new Vivado project.
Following HLS synthesis the predicted resource usage is
Now we have the IP block we are going to be able to add it to our project and start the Vivado design.
Vivado DesignTo get started with the Vivado design we need to add in the following IP to a new project created to target the Basys3 board.
- MicroBlaze - 64KB data and instruction memory
- AXI Lite UART
- Video Timing Controller - configured for generation only
- Video Test Pattern Generator - max rows and columns 800, 800
- XADC - Enable Vaux6, 7, 14 and 15
- Clock Wizard - 20 MHz (MicroBlaze), 25.175 MHz (Pixel Clock), 50 MHz (Logic Clock)
- Video Mixer - max rows and columns 800, 800
- Video AXIS to Video Out
- HUD IP created in HLS previously
- GPIO Connected to the push buttons - future expansion for a cursor
When creating the block diagram, leverage the block automation to configure the MicroBlaze - adding in the Memory, debug and rest structures. Leverage also the connection automation to connect the AXI interconnect.
The end diagram will look similar to the below diagram when showing the interface view.
The complete design is below
I will place the complete design on my git hub for exploration and modification.
The image path merges the HLS IP previously created with the TPG (allows setting of background color). These are merged using the Video Mixer core which merges the two streams using alpha blending.
The resultant output stream is converted back to parallel video output format Pixel, VSync, HSync etc. timed for the 640, 480 display. The timing of the AXI Stream to video is under the control of the video timing generator.
In this approach the SW application can set the background using the TPG and define the plots using the HLS IP.
To make sure the design works with all VGA monitors we need to ensure the RGB signals are 0 during the blanking period.
As such I use a AND gate logic IP block gated with the Video out enable provided by the AXI stream to video out block. The VGA output on the Basys3 uses the 3 outputs for each channel RGB. To provide a reusable design we have used 8 bits pixels which are more common in the design to allow porting to different boards.
The XDC used for the project is below
##7 segment display
set_property PACKAGE_PIN W7 [get_ports {seven_seg[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seven_seg[0]}]
set_property PACKAGE_PIN W6 [get_ports {seven_seg[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seven_seg[1]}]
set_property PACKAGE_PIN U8 [get_ports {seven_seg[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seven_seg[2]}]
set_property PACKAGE_PIN V8 [get_ports {seven_seg[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seven_seg[3]}]
set_property PACKAGE_PIN U5 [get_ports {seven_seg[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seven_seg[4]}]
set_property PACKAGE_PIN V5 [get_ports {seven_seg[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seven_seg[5]}]
set_property PACKAGE_PIN U7 [get_ports {seven_seg[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seven_seg[6]}]
#set_property PACKAGE_PIN V7 [get_ports dp]
#set_property IOSTANDARD LVCMOS33 [get_ports dp]
set_property PACKAGE_PIN U2 [get_ports {seven_seg_led_an[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seven_seg_led_an[0]}]
set_property PACKAGE_PIN U4 [get_ports {seven_seg_led_an[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seven_seg_led_an[1]}]
set_property PACKAGE_PIN V4 [get_ports {seven_seg_led_an[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seven_seg_led_an[2]}]
set_property PACKAGE_PIN W4 [get_ports {seven_seg_led_an[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seven_seg_led_an[3]}]
set_property PACKAGE_PIN W5 [get_ports sys_clock]
set_property IOSTANDARD LVCMOS33 [get_ports sys_clock]
#create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk]
##VGA Connector
set_property PACKAGE_PIN G19 [get_ports {vgaRed[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vgaRed[0]}]
set_property PACKAGE_PIN H19 [get_ports {vgaRed[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vgaRed[1]}]
set_property PACKAGE_PIN J19 [get_ports {vgaRed[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vgaRed[2]}]
set_property PACKAGE_PIN N19 [get_ports {vgaRed[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vgaRed[3]}]
set_property PACKAGE_PIN N18 [get_ports {vgaBlue[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vgaBlue[0]}]
set_property PACKAGE_PIN L18 [get_ports {vgaBlue[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vgaBlue[1]}]
set_property PACKAGE_PIN K18 [get_ports {vgaBlue[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vgaBlue[2]}]
set_property PACKAGE_PIN J18 [get_ports {vgaBlue[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vgaBlue[3]}]
set_property PACKAGE_PIN J17 [get_ports {vgaGreen[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vgaGreen[0]}]
set_property PACKAGE_PIN H17 [get_ports {vgaGreen[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vgaGreen[1]}]
set_property PACKAGE_PIN G17 [get_ports {vgaGreen[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vgaGreen[2]}]
set_property PACKAGE_PIN D17 [get_ports {vgaGreen[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vgaGreen[3]}]
set_property PACKAGE_PIN P19 [get_ports Hsync]
set_property IOSTANDARD LVCMOS33 [get_ports Hsync]
set_property PACKAGE_PIN R19 [get_ports Vsync]
set_property IOSTANDARD LVCMOS33 [get_ports Vsync]
set_property DRIVE 8 [get_ports {vgaBlue[3]}]
set_property DRIVE 8 [get_ports {vgaBlue[2]}]
set_property DRIVE 8 [get_ports {vgaBlue[1]}]
set_property DRIVE 8 [get_ports {vgaBlue[0]}]
set_property DRIVE 8 [get_ports {vgaGreen[3]}]
set_property DRIVE 8 [get_ports {vgaGreen[2]}]
set_property DRIVE 8 [get_ports {vgaGreen[1]}]
set_property DRIVE 8 [get_ports {vgaGreen[0]}]
set_property DRIVE 8 [get_ports {vgaRed[3]}]
set_property DRIVE 8 [get_ports {vgaRed[2]}]
set_property DRIVE 8 [get_ports {vgaRed[1]}]
set_property DRIVE 8 [get_ports {vgaRed[0]}]
set_property DRIVE 8 [get_ports Hsync]
set_property DRIVE 8 [get_ports Vsync]
set_property C_CLK_INPUT_FREQ_HZ 300000000 [get_debug_cores dbg_hub]
set_property C_ENABLE_CLK_DIVIDER false [get_debug_cores dbg_hub]
set_property C_USER_SCAN_CHAIN 1 [get_debug_cores dbg_hub]
connect_debug_port dbg_hub/clk [get_nets clk]
With this complete the application can be built and the XSA exported.
Resource usage
The development of the software is straight forward, the HLS IP core when it generates comes with drivers for the SW development.
The software application must do the following
- Initialize the XADC
- Initialize the TPG
- Initialize the Mixer
- Initialize the Video Timing Controller
- Initialize the HLS IP
- Set up the Mixer to mix two 640 by 480 streams
- Set up the TPG to output the background color required
- Set up the Video Timing Controller for the 640 by 480 timing
- Loop Reading the XADC and Updating the
The application code is below
#include <stdio.h>
#include <stdlib.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xvtc.h"
#include "vga_modes.h"
#include "xv_tpg.h"
#include "xvidc.h"
#include "xv_mix.h"
#include "xhud_gen.h"
#include "xgpio.h"
XVtc VtcInst;
XVtc_Config *vtc_config ;
XV_tpg tpg;
XV_tpg_Config *tpg_config;
XGpio_Config *gpio_config;
XGpio gpio;
VideoMode video;
int main()
{
XVtc_Timing vtcTiming;
XVtc_SourceSelect SourceSelect;
XV_mix xv_mix;
XV_mix_Config *xv_config;
XHud_gen_Config *XV_Hud_cfg;
XHud_gen xv_hud;
init_platform();
print("Hello World\n\r");
print("Successfully ran Hello World application");
gpio_config = XGpio_LookupConfig(XPAR_GPIO_0_DEVICE_ID);
XGpio_CfgInitialize(&gpio,gpio_config, gpio_config->BaseAddress);
XGpio_SetDataDirection(&gpio,1,0xFFFFFFFF);
XGpio_SetDataDirection(&gpio,2,0x00000000);
vtc_config = XVtc_LookupConfig(XPAR_VTC_0_DEVICE_ID);
XVtc_CfgInitialize(&VtcInst, vtc_config, vtc_config->BaseAddress);
video = VMODE_640x480;
vtcTiming.HActiveVideo = video.width; /**< Horizontal Active Video Size */
vtcTiming.HFrontPorch = video.hps - video.width; /**< Horizontal Front Porch Size */
vtcTiming.HSyncWidth = video.hpe - video.hps; /**< Horizontal Sync Width */
vtcTiming.HBackPorch = video.hmax - video.hpe + 1; /**< Horizontal Back Porch Size */
vtcTiming.HSyncPolarity = video.hpol; /**< Horizontal Sync Polarity */
vtcTiming.VActiveVideo = video.height; /**< Vertical Active Video Size */
vtcTiming.V0FrontPorch = video.vps - video.height; /**< Vertical Front Porch Size */
vtcTiming.V0SyncWidth = video.vpe - video.vps; /**< Vertical Sync Width */
vtcTiming.V0BackPorch = video.vmax - video.vpe + 1;; /**< Horizontal Back Porch Size */
vtcTiming.V1FrontPorch = video.vps - video.height; /**< Vertical Front Porch Size */
vtcTiming.V1SyncWidth = video.vpe - video.vps; /**< Vertical Sync Width */
vtcTiming.V1BackPorch = video.vmax - video.vpe + 1;; /**< Horizontal Back Porch Size */
vtcTiming.VSyncPolarity = video.vpol; /**< Vertical Sync Polarity */
vtcTiming.Interlaced = 0;
memset((void *)&SourceSelect, 0, sizeof(SourceSelect));
SourceSelect.VBlankPolSrc = 1;
SourceSelect.VSyncPolSrc = 1;
SourceSelect.HBlankPolSrc = 1;
SourceSelect.HSyncPolSrc = 1;
SourceSelect.ActiveVideoPolSrc = 1;
SourceSelect.ActiveChromaPolSrc= 1;
SourceSelect.VChromaSrc = 1;
SourceSelect.VActiveSrc = 1;
SourceSelect.VBackPorchSrc = 1;
SourceSelect.VSyncSrc = 1;
SourceSelect.VFrontPorchSrc = 1;
SourceSelect.VTotalSrc = 1;
SourceSelect.HActiveSrc = 1;
SourceSelect.HBackPorchSrc = 1;
SourceSelect.HSyncSrc = 1;
SourceSelect.HFrontPorchSrc = 1;
SourceSelect.HTotalSrc = 1;
XVtc_RegUpdateEnable(&VtcInst);
XVtc_SetGeneratorTiming(&VtcInst, &vtcTiming);
XVtc_SetSource(&VtcInst, &SourceSelect);
XVtc_EnableGenerator(&VtcInst);
xv_config = XV_mix_LookupConfig(XPAR_XV_MIX_0_DEVICE_ID);
XV_mix_CfgInitialize(&xv_mix,xv_config,xv_config->BaseAddress);
XV_mix_Set_HwReg_width(&xv_mix, (u32)640);
XV_mix_Set_HwReg_height(&xv_mix, (u32) 480);
XV_mix_Set_HwReg_layerEnable(&xv_mix,(u32)3);
XV_mix_Set_HwReg_layerStartX_0(&xv_mix,(u32)0);
XV_mix_Set_HwReg_layerStartY_0(&xv_mix,0);
XV_mix_Set_HwReg_layerWidth_0(&xv_mix,(u32)640);
XV_mix_Set_HwReg_layerHeight_0(&xv_mix,(u32)480);
XV_mix_Set_HwReg_layerAlpha_0(&xv_mix, 225);
XV_mix_Set_HwReg_layerStartX_1(&xv_mix,(u32)0);
XV_mix_Set_HwReg_layerStartY_1(&xv_mix,0);
XV_mix_Set_HwReg_layerWidth_1(&xv_mix,(u32)640);
XV_mix_Set_HwReg_layerHeight_1(&xv_mix,(u32)480);
XV_mix_Set_HwReg_layerAlpha_1(&xv_mix, 225);
XV_mix_EnableAutoRestart(&xv_mix);
XV_mix_Start(&xv_mix);
XV_Hud_cfg = XHud_gen_LookupConfig(XPAR_HUD_GEN_0_DEVICE_ID);
XHud_gen_CfgInitialize(&xv_hud,XV_Hud_cfg);
XHud_gen_Set_row(&xv_hud, (u32) 480);
XHud_gen_Set_column(&xv_hud, (u32) 640);
// XHud_gen_Set_ball_y(&xv_hud, (u32) (640/2));
// XHud_gen_Set_ball_x(&xv_hud, (u32) (280/2));
XHud_gen_Set_plot_size(&xv_hud, (u32) 5);
XHud_gen_Set_plot_colour(&xv_hud, (u32) 0x7fffffff);
XHud_gen_EnableAutoRestart(&xv_hud);
XHud_gen_Start(&xv_hud);
XVtc_Enable(&VtcInst);
u32 height,width,status;
tpg_config = XV_tpg_LookupConfig(XPAR_XV_TPG_0_DEVICE_ID);
XV_tpg_CfgInitialize(&tpg, tpg_config, tpg_config->BaseAddress);
status = XV_tpg_IsReady(&tpg);
printf("TPG Status %u \n\r", (unsigned int) status);
XV_tpg_Set_height(&tpg, (u32) video.height);
XV_tpg_Set_width(&tpg, (u32) video.width);
height = XV_tpg_Get_height(&tpg);
width = XV_tpg_Get_width(&tpg);
XV_tpg_Set_colorFormat(&tpg,XVIDC_CSF_RGB);
XV_tpg_Set_maskId(&tpg, 0x0);
XV_tpg_Set_motionSpeed(&tpg, 0x4);
printf("info from tpg %u %u \n\r", (unsigned int)height, (unsigned int)width);
XV_tpg_Set_bckgndId(&tpg,XTPG_BKGND_SOLID_BLUE);//XTPG_BKGND_COLOR_BARS); //);
status = XV_tpg_Get_bckgndId(&tpg);
printf("Status %x \n\r", (unsigned int) status);
XV_tpg_EnableAutoRestart(&tpg);
XV_tpg_Start(&tpg);
status = XV_tpg_IsIdle(&tpg);
printf("Status %u \n\r", (unsigned int) status);
XHud_gen_Set_plot_x_1(&xv_hud, 64);
XHud_gen_Set_plot_y_1(&xv_hud, 441);
XHud_gen_Set_plot_x_2(&xv_hud, 128);
XHud_gen_Set_plot_y_2(&xv_hud, 458);
XHud_gen_Set_plot_x_3(&xv_hud, 192);
XHud_gen_Set_plot_y_3(&xv_hud, 273);
XHud_gen_Set_plot_x_4(&xv_hud, 256);
XHud_gen_Set_plot_y_4(&xv_hud, 58);
XHud_gen_Set_plot_x_5(&xv_hud, 320);
XHud_gen_Set_plot_y_5(&xv_hud, 9);
XHud_gen_Set_plot_x_6(&xv_hud, 384);
XHud_gen_Set_plot_y_6(&xv_hud, 172);
XHud_gen_Set_plot_x_7(&xv_hud, 448);
XHud_gen_Set_plot_y_7(&xv_hud, 397);
XHud_gen_Set_plot_x_8(&xv_hud, 512);
XHud_gen_Set_plot_y_8(&xv_hud, 477);
XHud_gen_Set_plot_x_9(&xv_hud, 576);
XHud_gen_Set_plot_y_9(&xv_hud, 338);
XHud_gen_Set_plot_x_10(&xv_hud, 640);
XHud_gen_Set_plot_y_10(&xv_hud, 109);
cleanup_platform();
return 0;
}
When output this gives a nice colourful display which acts as a basic scope on the VGA Display.
We can create a simple project which shows how to plot points on the VGA output. Future development would could be
- Add Labels and markers
- Add cursor to report sample value on screen
- Line drawing between the points
Of course we need to be careful of the logic resources required as this project is pretty demanding on the device resources.
Comments