How to create a simple oscilloscope using the Basys3 board
Source: InternetPublisher:无人共我 Keywords: fpga Updated: 2024/03/01
This project will involve everyone working together to create a simple oscilloscope using the Basys3 board, which will take about 4 hours.
Hardware components
Digilent Basys 3
Software applications and online services
Xilinx Vivado Design Suite
Xilinx Vitis Unified Software Platform
Project Introduction
The Digilent Basys3 board is a powerful board with which to start developing FPGA projects. It provides the user with an Artix 35T device, USB-UART, four Pmods - including one configured for XADC, 12-bit VGA and switches, LEDs and seven-segment display.
This project is intended to demonstrate the capabilities of the Basys3 board, for which we will create a simple oscilloscope that can display waveforms using the XDAC Pmod input channel and a VGA monitor.
To do this, we will use the MicroBlaze controller to run the application and control the XADC measurements and determine where to draw the data on the VGA screen.
A VGA monitor will be 640 x 480, and 12-bit RGB requires 3, 686, 400 bits to render in software memory. This exceeds the 1, 800, 000 bits of BRAM available in FPGAs. The processor also wasn't able to run at the speed needed to be able to achieve the required frame rates.
We will solve this problem by using the processor to determine the data point plot while logically rendering the frame for real-time display. To do this, we'll use the high-level synthesis core we first created.
The Advanced Synthesis Core
begins by recreating an HLS core that can draw up to 10 samples into a VGA monitor (of course, you can change this later). The HLS kernel will generate a 640 pixel x 480 line AXI stream. To update the display each frame, there will be sample_x/_y registers that define the location of the sample data, a register that defines the size of the data points, and a final register that defines the color of the data points.
Creating HLS streams requires 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, and an 8-bit alpha channel for blending.
The hud.h file includes the following lines
#include "hls_video.h" #include |
While the body of the 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 |
请注意我如何使用两个循环在流中创建图像的 X 和 Y 元素。在内部循环中,我们处理 TUser 和 TLast 信号上的帧开始和行尾边带信号。
下一步是使用 C 来模拟电路,以确保行为符合我们的要求
创建的测试台可用于 C 和 Co 仿真
#include "hud.h" #include |
运行 C 模拟为我们提供了一个 BMP 图像,它应该展示绘制的点
在此示例中,数据点是绘制的白点。
在性能满意的情况下,下一步是综合和封装IP块以用于新的Vivado项目。
在HLS综合之后,预测的资源使用情况为
现在我们有了IP块,我们将能够将其添加到我们的项目中并开始Vivado设计。
Vivado设计
要开始使用Vivado设计,我们需要将以下IP添加到针对Basys3板创建的新项目中。
MicroBlaze-64KB数据和指令存储器
AXILiteUART
视频时序控制器-仅配置为生成
视频测试模式生成器-最大行数和列数800、800
XADC-启用Vaux6、7、14和15
时钟向导-20MHz(MicroBlaze)、25.175MHz(像素时钟)、50MHz(逻辑时钟)
视频混合器-最大行数和列数800、800
视频轴到视频输出
之前在HLS中创建的HUDIP
GPIO连接到按钮-光标的未来扩展
创建框图时,利用块自动化来配置MicroBlaze-添加内存、调试和休息结构。还利用连接自动化来连接AXI互连。
显示界面视图时,端图将类似于下图。
完整的设计如下
我会将完整的设计放在我的github上进行探索和修改。
图像路径将先前创建的HLSIP与TPG合并(允许设置背景颜色)。这些使用视频混合器核心合并,该核心使用alpha混合合并两个流。
生成的输出流被转换回并行视频输出格式Pixel、VSync、HSync等,为640、480显示器定时。AXIStream到视频的时序由视频时序发生器控制。
在这种方法中,软件应用程序可以使用TPG设置背景并使用HLSIP定义绘图。
为了确保设计适用于所有VGA显示器,我们需要确保RGB信号在消隐期间为0。
因此,我使用了一个与门逻辑IP块,该IP块由AXI流提供的视频输出启用门控到视频输出块。Basys3上的VGA输出使用每个通道RGB的3个输出。为了提供可重复使用的设计,我们使用了在设计中更常见的8位像素,以允许移植到不同的板上。
该项目使用的XDC如下
##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_port s {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 Vsync ] set_property C_CLK_INPUT_FREQ_HZ 3000000 00 [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] |
Once completed, the application can be built and the XSA exported.
Resource usage
software development
Software development is simple, and the generated HLS IP core comes with drivers for SW development.
The software application must do the following
Initialize XADC
Initialize TPG
Initialize mixer
Initialize video timing controller
Initialize HLS IP
Set up the mixer to mix two 640 x 480 streams
Set TPG to output desired background color
Set up video timing controller for 640 x 480 timing
Loop to read XADC and update
The application code is as follows
#include |
When output, this provides a nice color display, as is the base range of a VGA display.
Alternatively, we can create a simple project to show how to draw points on the VGA output.
Future improvement directions may be as follows:
Add labels and tags
Added cursor to report sample values on screen
Line drawing between points
Of course, we need to pay attention to the required logical resources, as this project has high requirements on device resources.
- Make a Simple Darkness Detector Circuit
- How to Measure Turbidity of Liquids Using Arduino
- Convenient and fast power line break detection circuit
- A highly sensitive human proximity detector
- Homemade simple magnetic material tester
- Analysis of valid and fault conditions of differential signals
- Fire detector made with photodiode
- 5 tone detector circuit diagram
- Electric vehicle luminous voltmeter with undervoltage alarm
- PHGS-4 computer multi-channel industrial acidity meter circuit 01
- Bus door status detection circuit
- Object presence and displacement detection circuit
- New fast charging I start 2 charging detection circuit
- Three-phase power supply phase sequence detection circuit
- Gas concentration sensing detection circuit
- Light detection circuit
- RMS sensor detection circuit
- Hot spot sensor infrared detection circuit
- Photodiode pollution gas detection circuit
- Infrared remote control detection circuit