The project is progressing well. I added some sensors to be able to monitor the environment through the heads-up display. I also built a customizable module with Vitis HLS to display up to 16-digit virtual seven-segment display modules overlaid on the live video feed. I wired everything up and programmed a bare-metal app for the MicroBlaze soft processor to orchestrate the updates.
Table of Contents
- Sensor Fusion for Firefighters Project Update
- General description of the heads-up environmental monitoring system
- Hardware needed
- Environmetal Sensors
- Design of an HLS hardware accelerated overlay screen
- Operation of the pixel generator for the overlay screen.
- Pixel Generation Scope View
- Constraints and trade-offs
- Synthetizing C or C++ function into RTL with Vitis HLS
- Fire Fighters Heads-Up Monitor Generator C++ Code
- HLS C Seven Segment Digits Font Definition
- Test bench for the Vitis HLS module
- C Synthesis
- Block Diagram Diagram Design with Vivado IP Integrator
- Connection of external outputs with Pmod connectors via the constraints file
- Environmental Monitor MicroBlaze Bare Metal Application with Vitis IDE
- Conclusions and Next Steps
- The Complete "Sensor Fusion for Firefighters" Blog Series
The Complete "Sensor Fusion for Firefighters" Blog Series
- Sensor Fusion for Firefighters. Introductory blog
- Sensor Fusion for Firefighters. Getting Started with the AMD Xilinx SP701
- Sensor Fusion for Firefighters. AMD Xilinx SP701 - MIPI Video Pipe Camera to HDMI Display
- Sensor Fusion for Firefighters. Displaying heads-up video on the live feed
- Sensor Fusion for Firefighters. Environmental monitor heads-up display on Xilinx Spartan-7 SP701 development board
- Sensor Fusion for Firefighters. Compass and Environmental HUD monitor with the Spartan-7
- Sensor Fusion for Firefighters. Thermal Vision, Compass and Environmental HUD monitor with the Spartan-7
- Sensor Fusion for Firefighters. Summary Blog
Sensor Fusion for Firefighters Project Update
I have added a PmodHYGRO, relative humidity sensor and a temperature sensor, and the SparkFun Environmental Combo Breakout - CCS811/BME280.
In the image the system connected to an HP 25x 24.5-inch Display through the HDMI port. Displaying eCO2 level in ppm (408 ppm), Temperature in Celsius (18ºC) and % rel Humidity (47%)
I had planned to include the PmodAQS module to measure air quality, but the order did not arrive on time, so I replaced it with a Sparkfun module that combines a BME280 sensor, a humidity sensor that measures relative humidity, barometric pressure, and ambient temperature and a CCS811 air quality sensor. I am not going to use the BME280 sensor at the moment because being so close to the CCS811 module, the readings are distorted by the heat dissipated by the CCS811 module.
In the following image you can see the current configuration. The Digilent PmodHYGRO module is connected to the Pmod 1 port of the AMD Xilinx SP701 development board, configured as an IIC port. The Sparkfun Environmental Combo Breakout - CCS811/BME280 module is connected to Pmod 6 port also configured as IIC port.
The PmodNAV module is also connected to the Pmod 3 port but at the moment I don't use it. It is only presented to the board.
The heads-up overlay module is configured as three blocks of 4, 2 and 2 seven-segment display modules.
The first block of four digits displays the real-time measurement of eCO2 or CO2 equivalent in the parts per million (PPM) captured by the CCS811 air quality sensor. The CCS811 also has a feature that allows it to fine-tune its readings if it has access to the current humidity and temperature. For this tuning I will use the readings of the PmodHYGRO that has been placed on the other end of the development board, instead of using the BME280 module of the combo.
The second block of two seven-segment digits displays the room temperature.
And the third block of two digits of seven segments shows the percentage of relative humidity.
The refreshment of the video image is amazing.
General description of the heads-up environmental monitoring system
The block diagram shows a simplified view of the system.
The video image is captured by the Omnivision OV5640 5-megapixel (MP) color image sensor of the Digilent PCAM 5C module.
The MIPI CSI-2 Rx Subsystem module captures images from the MIPI CSI-2 camera sensor and outputs AXI4-Stream video data ready for image processing.
The Sensor Demosaic reconstructs sub-sampled color data for images captured by the Omnivision OV5640 Bayer image sensor.
The AXI VDMA engine provides high-bandwidth direct memory access between memory and AXI4-Stream-video type target peripherals.
The Heads-Up Overlay Generator produces the overlay layer with sensor information displayed on blocks of virtual seven-segment display modules.
The Video Mixer combines the two video inputs the camera video feed and the AXIS stream generated by the Heads-Up Overlay Generator.
The MicroBlaze soft-processor is in charge of communicating with and configuring the sensors, camera, CCS811 air quality sensor and the HYGRO sensor and passing the information to the hardware accelerated HUD Overlay Generator module. It is also responsible for configuring the video mixer.
Hardware needed
To build the system you need:
- AMD Xilinx SP701 evaluation board and power supply
- JTAG USB Platform cable or USB cable Type A to micro - B
- HDMI cable
- HDMI Monitor: ELECROW 7" HDMI IPS Monitor - 1024x600
- Digilent Pcam 5C sensor module
- HDMI Monitor: HP 25x 24.5-inch Display
- Digilent PmodHYGRO Buy Now
- SparkFun Environmental Combo Breakout - CCS811/BME280 (Qwiic)
- or Digilent Pmod AQS
Environmetal Sensors
Digilent PmodHYGRO
The Digilent Pmod HYGRO is a relative humidity sensor with an integrated temperature sensor for highly accurate measurements at low power. With the TI HDC1080, we can determine the relative humidity of the environment with up to 14 bits of resolution.
I recently used this sensor connected to another development board with a Spartan-7 FPGA, you can read more in the following blog: Arty S7 50 Rapid Prototyping - Environmental Monitor
I have connected the sensor in port Pmod1. The SP701 development board has 6 Pmod expansion ports that follow the Digilent Pmod standard. All the PMOD ports are connected to the XC7S100 FPGA bank 16. The SP701 evaluation board implements six right-angle PMOD GPIO receptacles J14-J19. The 3.3V PMOD nets are wired to the XC7S100 FPGA 3.3V bank 16. The reference example for the MIPI CS rx IP module misdefines the voltage of this bank which is also the one the IIC expander port is connected to.
{gallery}Digilent PmodHYGRO |
---|
Digilent PmodHYGRO - Unboxing |
Digilent PmodHYGRO - Unboxing |
Digilent PmodHYGRO - Front |
Digilent PmodHYGRO - BACK |
CCS811 Air Quality Sensor
This sensor is a gas sensor that can detect a wide range of Volatile Organic Compounds (VOCs) and is intended for indoor air quality monitoring.
The CCS811 has a "standard" hot plate MOX sensor, as well as a small microcontroller that controls power to the plate, reads the analog voltage, and provides an I2C interface for reading.
It measures eCO2 concentration (calculated carbon dioxide equivalent) within a range of 400 to 8192 parts per million (ppm), and TVOC (Total Volatile Organic Compound) concentration within a range of 0 to 1187 parts billion (ppb).
According to the technical data sheet, it can detect Alcohols, Aldehydes, Ketones, Organic Acids, Amines, Aliphatic and Aromatic Hydrocarbons.
I have connected the sensor in the Pmod 6 port and the connection is compatible with the Digilent PmodAQS module.
The I2C address of the Environmental Combo Breakout is 0x77 / 0x5B and is jumper selectable to 0x76 / 0x5A.
The system is compatible with the Digilent PmodAQS.
Digilent Pmod AQS Schematics:
Design of an HLS hardware accelerated overlay screen
Following the heads-up display design presented in the previous blog (Sensor Fusion for Firefighters. Displaying heads-up video on the live feed - Blog) I have designed a new hardware accelerated block in Vitis HLS. The new module allows to show an overlay screen with up to 16 digits formed by 7 segments aligned and grouped in different ways.
This overlay screen will show the values of the sensors in real time without flickering and preventing the Microblaze from being in charge of building the image, something that with the characteristics of the MicroBlaze soft-processor on the Spartan-7 FPGA would not be feasible.
In the image the HDMI Heads Up Display (HUD) with 16 seven-segment virtual display modules on the AMD Xilinx SP701 development board.
The seven-segment digits can be grouped in different ways and the font is scalable horizontally and vertically.
Operation of the pixel generator for the overlay screen.
The heads-up display overlay is a pixel generation circuit. It produces a full screen of pixels. A pixel generation circuit is a video source that generates a graphic frame to be displayed on the screen. The inputs of the generator are x and y, representing the x- and y-coordinates of the current pixel. Based on the values of the coordinates and a font mapping a color-pixel is produced. The y signal is used to determine the region where the background frame and the seven segment display modules are painted. The x signal is used to determine the horizontal position of each seven segment display modules and which color-pixel is produced.
Two counters provide the x- and y-coordinate signals. The pixels are sent as an AXI Stream. An AXI Stream is a unidirectional bus used to transfer data from a master to a slave, as a stream of data it does not contain an address channel. To control flow and communicate video timing information over the AXI Stream the following signals are used:
- TReady - Asserted by the downstream peripheral when ready to receive data
- TValid - Asserted by transmitting peripheral when output data is valid
- TUser - Issued for start of Frame
- TLast - Issued for end of line
The AXIS stream has to be a contiguous block, so TValid does not assert or unassert during the active pixel period. The AXI stream output from the IP module will output pixel data as RGBA. Along with the RGB channels we also have a pixel-by-pixel alpha channel. The output AXIS stream has a width of 32 bits. The AXI stream output of the IP module will output pixel data as RGBA, including the amount of transparency of each pixel, Alpha Channel. This AXIS stream will be one of the inputs of a video mixer IP block. The video mixer will mix the live video and the overlay on a pixel-by-pixel basis.
Frame generator pseudocode:
void ff_monitor_gen(axis& op, int row, int column, int bcd_digits, int compass_angle) {
#pragma HLS INTERFACE axis register both port=op
int y = 0;
int x = 0;
...
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; // Issued for start of Frame
} else{
if (x == (column-1) ){
hud_int.last = 1; // Issued for end of line
}
else{
hud_int.last = 0;
hud_int.user = 0;
hud_int.data = pixel_generation(x,y);
}
op.write(hud_int);
}
}
}
Pixel Generation Scope View
In the design of the Vivado blocks I have included an Integrated Logic Analyzer (ILA) IP block that allows us to visualize the output of the frame generator at runtime.
Pixel generation with alpha channel set to 7F transparency to produce a blue pixel from the blue background of the characters.
Constraints and trade-offs
There is a tradeoff between the number of used resources, LUTs, RAM blocks and the requirement to meet AXI Stream signaling times. My first attempts were not successful.
I achieved a significant resource reduction using just 2100 LUTs for an overlay screen with 16x7-segment modules. But unfortunately it didn't meet the time requirements and it didn't work.
The next attempt was to do the opposite, prioritize response times and forget about resource utilization. Then the usage of LUTs went up to 11000 LUTs.
Finally I reached a compromise with some results I think quite good.
I have included in a Github repository the different attempts made. They are all functional but each of them tries to solve the problem in a different way: XilinxSP701SensorFusion/ff_monitor_hls
Synthetizing C or C++ function into RTL with Vitis HLS
The Vitis HLS tool synthesizes a C or C++ function into RTL code for implementation in the programmable logic (PL) region of the SP701 Spartan 7 FPGA. I used the Vivado IP flow, The RTL generated can be used as an IP directly within the Vivado tool or Model composer.
Fire Fighters Heads-Up Monitor Generator C++ Code
This is the final code used for the environmental monitor. It only uses 8 digits, four grouped to show the measurements provided by the air quality sensor and another two groups of two digits to show the temperature and relative humidity percentage provided by the sensors of the PmodHYGRO module
Pay special attention to the Pragma statements for optimization.
First, the 8 digits contained in the BCD representation are separated. Then two loops generate all the (x, y) coordinate pairs of all the pixels in the frame. Line by line the pixels are "painted" according to the implemented logic. Separate counters allow fonts to be scaled horizontally and vertically.
#include "ff_monitor.h" #include "char7segment2.h" #define COUNT_PIXEL 8 #define COUNT_LINE 6 #define YCHAR1 50 #define CHAR_WIDTH 5 #define BLOCK_SEPARATION 200 #define DIGIT_SEPARATION 15 #define DISPLAY_MARGINY 10 #define XCHAR0 + 800 #define XCHAR1 XCHAR0 + COUNT_PIXEL * CHAR_WIDTH + DIGIT_SEPARATION #define XCHAR2 XCHAR1 + COUNT_PIXEL * CHAR_WIDTH + DIGIT_SEPARATION #define XCHAR3 XCHAR2 + COUNT_PIXEL * CHAR_WIDTH + DIGIT_SEPARATION #define XCHAR4 XCHAR3 + COUNT_PIXEL * CHAR_WIDTH + DIGIT_SEPARATION + 500 #define XCHAR5 XCHAR4 + COUNT_PIXEL * CHAR_WIDTH + DIGIT_SEPARATION #define XCHAR6 XCHAR5 + COUNT_PIXEL * CHAR_WIDTH + DIGIT_SEPARATION + 100 #define XCHAR7 XCHAR6 + COUNT_PIXEL * CHAR_WIDTH + DIGIT_SEPARATION extern const unsigned int display_0[11][5]; extern const unsigned int display_1[11][5]; extern const unsigned int display_2[11][5]; extern const unsigned int display_3[11][5]; extern const unsigned int display_4[11][5]; extern const unsigned int display_5[11][5]; extern const unsigned int display_6[11][5]; extern const unsigned int display_7[11][5]; extern const unsigned int display_8[11][5]; extern const unsigned int display_9[11][5]; #define MAX_DIGITS 8 void drawDigitPixel(video_stream &hud_int, int line, int pixel, int digit); void updateCounters(int &pixel, int &count_pixel); void ff_monitor_gen(axis& op, int row, int column, int char_1, int char_2) { #pragma HLS INTERFACE s_axilite port=return #pragma HLS INTERFACE s_axilite port=char_1 #pragma HLS INTERFACE s_axilite port=char_2 #pragma HLS INTERFACE s_axilite port=column #pragma HLS INTERFACE s_axilite port=row #pragma HLS INTERFACE axis register both port=op int y = 0; int x = 0; unsigned char digits[MAX_DIGITS] = {0}; digits[0] = (unsigned char)((char_1 >> 28) & 0x0F); digits[1] = (unsigned char)((char_1 >> 24) & 0x0F); digits[2] = (unsigned char)((char_1 >> 20) & 0x0F); digits[3] = (unsigned char)((char_1 >> 16) & 0x0F); digits[4] = (unsigned char)((char_1 >> 12) & 0x0F); digits[5] = (unsigned char)((char_1 >> 8) & 0x0F); digits[6] = (unsigned char)((char_1 >> 4) & 0x0F); digits[7] = (unsigned char)((char_1 >> 0) & 0x0F); int line = 0; int pixel = 0; int count_line = 0; int count_pixel = 0; 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((y>YCHAR1-DISPLAY_MARGINY ) & (y<(YCHAR1+ 11 * (COUNT_LINE + 1) +DISPLAY_MARGINY )) ){ if((y>YCHAR1) & (y<(YCHAR1+ 11 * (COUNT_LINE + 1)))){ if(x>XCHAR0 & x < (COUNT_PIXEL + 1) * CHAR_WIDTH + XCHAR0 + 1){ drawDigitPixel(hud_int, line, pixel, digits[0]); updateCounters(pixel, count_pixel); } else if(x>XCHAR1 & x < (COUNT_PIXEL + 1) * CHAR_WIDTH + XCHAR1 + 1){ drawDigitPixel(hud_int, line, pixel, digits[1]); updateCounters(pixel, count_pixel); } else if(x>XCHAR2 & x < (COUNT_PIXEL + 1) * CHAR_WIDTH + XCHAR2 + 1){ drawDigitPixel(hud_int, line, pixel, digits[2]); updateCounters(pixel, count_pixel); } else if(x>XCHAR3 & x < (COUNT_PIXEL + 1) * CHAR_WIDTH + XCHAR3 + 1){ drawDigitPixel(hud_int, line, pixel, digits[3]); updateCounters(pixel, count_pixel); }else if(x>XCHAR4 & x < (COUNT_PIXEL + 1) * CHAR_WIDTH + XCHAR4 + 1){ drawDigitPixel(hud_int, line, pixel, digits[4]); updateCounters(pixel, count_pixel); } else if(x>XCHAR5 & x < (COUNT_PIXEL + 1) * CHAR_WIDTH + XCHAR5 + 1){ drawDigitPixel(hud_int, line, pixel, digits[5]); updateCounters(pixel, count_pixel); } else if(x>XCHAR6 & x < (COUNT_PIXEL + 1) * CHAR_WIDTH + XCHAR6 + 1){ drawDigitPixel(hud_int, line, pixel, digits[6]); updateCounters(pixel, count_pixel); } else if(x>XCHAR7 & x < (COUNT_PIXEL + 1) * CHAR_WIDTH + XCHAR7 + 1){ drawDigitPixel(hud_int, line, pixel, digits[7]); if (count_pixel == COUNT_PIXEL) { if ((pixel == (CHAR_WIDTH - 1)) & (count_line == COUNT_LINE)) { count_line = 0; pixel = 0; count_pixel = 0; line ++; } else if ((pixel == (CHAR_WIDTH - 1)) & (count_line < COUNT_LINE)) { count_line ++; pixel = 0; count_pixel = 0; } else { count_pixel = 0; pixel ++; } } else { count_pixel ++; } } else { ////// hud_int.data = BGN; } } else { hud_int.data = hud_int.data = BGN; } } else { hud_int.data = 0; } } } op.write(hud_int); } } } void drawDigitPixel(video_stream &hud_int, int line, int pixel, int digit) { #pragma HLS inline if (digit == 0) { hud_int.data = display_0[line][pixel]; } else if (digit == 1) { hud_int.data = display_1[line][pixel]; } else if (digit == 2) { hud_int.data = display_2[line][pixel]; } else if (digit == 3) { hud_int.data = display_3[line][pixel]; } else if (digit == 4) { hud_int.data = display_4[line][pixel]; } else if (digit == 5) { hud_int.data = display_5[line][pixel]; } else if (digit == 6) { hud_int.data = display_6[line][pixel]; } else if (digit == 7) { hud_int.data = display_7[line][pixel]; } else if (digit == 8) { hud_int.data = display_8[line][pixel]; } else if (digit == 9) { hud_int.data = display_9[line][pixel]; } else { hud_int.data = display_0[line][pixel]; } } void updateCounters(int &pixel, int &count_pixel) { #pragma HLS inline off if (count_pixel == COUNT_PIXEL) { count_pixel = 0; if (pixel == (CHAR_WIDTH - 1)) { pixel = 0; } else { pixel++; } } else { count_pixel++; } }
HLS C Seven Segment Digits Font Definition
The characters for display on the screen are stored as block RAM. I used small 5 pixels by 11-line arrays to define the character to be output.
Each value contains the RGB code for the pixels along with the Alpha value (transparency) for each pixel.
#define CPX 0xffff00ff #define BGN 0x7f808080 const unsigned int display_0[11][5] = { { CPX,CPX,CPX,CPX,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,CPX,CPX,CPX,CPX,} }; const unsigned int display_1[11][5] = { { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,} }; const unsigned int display_2[11][5] = { { CPX,CPX,CPX,CPX,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { CPX,CPX,CPX,CPX,CPX,}, { CPX,BGN,BGN,BGN,BGN,}, { CPX,BGN,BGN,BGN,BGN,}, { CPX,BGN,BGN,BGN,BGN,}, { CPX,BGN,BGN,BGN,BGN,}, { CPX,CPX,CPX,CPX,CPX,} }; const unsigned int display_3[11][5] = { { CPX,CPX,CPX,CPX,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { CPX,CPX,CPX,CPX,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { CPX,CPX,CPX,CPX,CPX,} }; const unsigned int display_4[11][5] = { { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,CPX,CPX,CPX,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,} }; const unsigned int display_5[11][5] = { { CPX,CPX,CPX,CPX,CPX,}, { CPX,BGN,BGN,BGN,BGN,}, { CPX,BGN,BGN,BGN,BGN,}, { CPX,BGN,BGN,BGN,BGN,}, { CPX,BGN,BGN,BGN,BGN,}, { CPX,CPX,CPX,CPX,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { CPX,CPX,CPX,CPX,CPX,} }; const unsigned int display_6[11][5] = { { CPX,CPX,CPX,CPX,CPX,}, { CPX,BGN,BGN,BGN,BGN,}, { CPX,BGN,BGN,BGN,BGN,}, { CPX,BGN,BGN,BGN,BGN,}, { CPX,BGN,BGN,BGN,BGN,}, { CPX,CPX,CPX,CPX,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,CPX,CPX,CPX,CPX,} }; const unsigned int display_7[11][5] = { { CPX,CPX,CPX,CPX,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,} }; const unsigned int display_8[11][5] = { { CPX,CPX,CPX,CPX,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,CPX,CPX,CPX,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,CPX,CPX,CPX,CPX,} }; const unsigned int display_9[11][5] = { { CPX,CPX,CPX,CPX,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,BGN,BGN,BGN,CPX,}, { CPX,CPX,CPX,CPX,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { BGN,BGN,BGN,BGN,CPX,}, { CPX,CPX,CPX,CPX,CPX,} };
Test bench for the Vitis HLS module
The first step in the synthesis of any block is to validate that the C function is correct. This step is performed by the test bench. The test bench captures the output image and save it as a BMP file.
#include "ff_monitor.h" #include <iostream> using namespace std; #include <stdio.h> const int BYTES_PER_PIXEL = 3; /// red, green, & blue const int FILE_HEADER_SIZE = 14; const int INFO_HEADER_SIZE = 40; void generateBitmapImage(unsigned char* image, int height, int width, char* imageFileName); unsigned char* createBitmapFileHeader(int height, int stride); unsigned char* createBitmapInfoHeader(int height, int width); void AXIvideo2Bmp(axis& AXI_video_strm, int h, int w ); int main (int argc, char** argv) { axis dst_axi; cout << "Starting simulation..!\r\n"; ff_monitor_gen(dst_axi, 1080, 1920, 0x12345678, 0x90123456); AXIvideo2Bmp(dst_axi, 1080, 1920); cout << "Finished!\r\n"; return 0; } void AXIvideo2Bmp(axis& AXI_video_strm, int h, int w ) { int i, j; ap_axiu<WIDTH,1,1,1> axi; bool sof = 0; int y, x; FILE *f; unsigned char *img = NULL; int filesize = 54 + 3*w*h; //w is your image width, h is image height, both int img = (unsigned char *)malloc(3*w*h); memset(img,0,3*w*h); for (i = 0; i < h; i++) { for (j = 0; j < (w); j++) { AXI_video_strm >> axi; if ((i == 0) && (j == 0)) { if (axi.user.to_int() == 1) { sof = 1; } else { j--; } } if (sof) { x=j; y=i; if (axi.data== 0) { img[(x+y*w)*3+2] = 0; img[(x+y*w)*3+1] = 0; img[(x+y*w)*3+0] = 0; } else { // RGBA to RGB Bitmap img[(x+y*w)*3+2] = (unsigned char) (axi.data >> 16) & 0xFF; /// red img[(x+y*w)*3+1] = (unsigned char) (axi.data ) & 0xFF; /// green img[(x+y*w)*3+0] = (unsigned char) (axi.data >> 8) & 0xFF; /// blue } } } } // BM Windows 3.1x, 95, NT, ... etc. // 54 The offset of the byte where the bitmap image data (pixel array) can be found. unsigned char bmpfileheader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0}; //BITMAPINFOHEADER Windows NT, 3.1x or later[2] // 40 the size of this header, in bytes // 1 color plane // bits per pixel 24 unsigned char bmpinfoheader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0}; unsigned char bmppad[3] = {0,0,0}; // The size of the BMP file in bytes bmpfileheader[ 2] = (unsigned char)(filesize ); bmpfileheader[ 3] = (unsigned char)(filesize>> 8); bmpfileheader[ 4] = (unsigned char)(filesize>>16); bmpfileheader[ 5] = (unsigned char)(filesize>>24); // the bitmap width in pixels (signed integer) bmpinfoheader[ 4] = (unsigned char)( w ); bmpinfoheader[ 5] = (unsigned char)( w>> 8); bmpinfoheader[ 6] = (unsigned char)( w>>16); bmpinfoheader[ 7] = (unsigned char)( w>>24); // the bitmap height in pixels (signed integer) bmpinfoheader[ 8] = (unsigned char)( h ); bmpinfoheader[ 9] = (unsigned char)( h>> 8); bmpinfoheader[10] = (unsigned char)( h>>16); bmpinfoheader[11] = (unsigned char)( h>>24); f = fopen("img.bmp","wb"); fwrite(bmpfileheader,1,14,f); fwrite(bmpinfoheader,1,40,f); for(int i=0; i<h; i++) { fwrite(img+(w*(h-i-1)*3),3,w,f); fwrite(bmppad,1,(4-(w*3)%4)%4,f); } free(img); fclose(f); }
Bmp file generated by the Test Bench, I'm discarding the alpha channel.
Now I'm working on a new module that allows to visualize both the data from environmental sensors and a compass to show the magnetic orientation of the device. More in the next blog.
C Synthesis
The C-Synthesis generates the RTL using HLS.
Early designs produced these results:
Working with optimization can improve the results of the final version.
Block Diagram Diagram Design with Vivado IP Integrator
Once the design of the block in Vitis HLS was finished, I exported the IP block and imported it from Vivado.
Starting from the design used in the previous blog, I removed all the blocks that were not necessary for the capture of the video image and its output via HDMI. All the part related to switching with the MIPI DSI output and the processing to accommodate the image signal to the MIPI DSI output has been removed to reserve the resources for the application.
I also added the Digilent IPs for the Pmod Hygro and Pmod AQS modules connected to two external ports.
Interfaces view:
Color Coded View:
Block design in pdf
Connection of external outputs with Pmod connectors via the constraints file
Through the constraints file we connect the two external outputs of the two environmental sensors with the Pmod connectors of the SP701 development board.
set_property PACKAGE_PIN C13 [get_ports "Pmod_out_0_pin1_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L10N_T1_16 set_property IOSTANDARD LVCMOS33 [get_ports "Pmod_out_0_pin1_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L10N_T1_16 set_property PACKAGE_PIN D14 [get_ports "Pmod_out_0_pin2_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L15N_T2_DQS_16 set_property IOSTANDARD LVCMOS33 [get_ports "Pmod_out_0_pin2_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L15N_T2_DQS_16 set_property PACKAGE_PIN B14 [get_ports "Pmod_out_0_pin3_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L6P_T0_16 set_property IOSTANDARD LVCMOS33 [get_ports "Pmod_out_0_pin3_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L6P_T0_16 set_property PACKAGE_PIN B15 [get_ports "Pmod_out_0_pin4_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L6N_T0_VREF_16 set_property IOSTANDARD LVCMOS33 [get_ports "Pmod_out_0_pin4_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L6N_T0_VREF_16 set_property PACKAGE_PIN A13 [get_ports "Pmod_out_0_pin7_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_0_16 set_property IOSTANDARD LVCMOS33 [get_ports "Pmod_out_0_pin7_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_0_16 set_property PACKAGE_PIN C14 [get_ports "Pmod_out_0_pin8_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L11P_T1_SRCC_16 set_property IOSTANDARD LVCMOS33 [get_ports "Pmod_out_0_pin8_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L11P_T1_SRCC_16 set_property PACKAGE_PIN A14 [get_ports "Pmod_out_0_pin9_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L1P_T0_16 set_property IOSTANDARD LVCMOS33 [get_ports "Pmod_out_0_pin9_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L1P_T0_16 set_property PACKAGE_PIN A15 [get_ports "Pmod_out_0_pin10_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L1N_T0_16 set_property IOSTANDARD LVCMOS33 [get_ports "Pmod_out_0_pin10_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L1N_T0_16 set_property PACKAGE_PIN F14 [get_ports "Pmod_out_1_pin1_io"] ;#PMOD6_PIN1_R set_property IOSTANDARD LVCMOS33 [get_ports "Pmod_out_1_pin1_io"] ;#PMOD6_PIN1_R set_property PACKAGE_PIN E15 [get_ports "Pmod_out_1_pin2_io"] ;#PMOD6_PIN2_R set_property IOSTANDARD LVCMOS33 [get_ports "Pmod_out_1_pin2_io"] ;#PMOD6_PIN2_R set_property PACKAGE_PIN C16 [get_ports "Pmod_out_1_pin3_io"] ;#PMOD6_PIN3_R set_property IOSTANDARD LVCMOS33 [get_ports "Pmod_out_1_pin3_io"] ;#PMOD6_PIN3_R set_property PACKAGE_PIN A17 [get_ports "Pmod_out_1_pin4_io"] ;#PMOD6_PIN4_R set_property IOSTANDARD LVCMOS33 [get_ports "Pmod_out_1_pin4_io"] ;#PMOD6_PIN4_R set_property PACKAGE_PIN F15 [get_ports "Pmod_out_1_pin7_io"] ;#PMOD6_PIN7_R set_property IOSTANDARD LVCMOS33 [get_ports "Pmod_out_1_pin7_io"] ;#PMOD6_PIN7_R set_property PACKAGE_PIN D15 [get_ports "Pmod_out_1_pin8_io"] ;#PMOD6_PIN8_R set_property IOSTANDARD LVCMOS33 [get_ports "Pmod_out_1_pin8_io"] ;#PMOD6_PIN8_R set_property PACKAGE_PIN B16 [get_ports "Pmod_out_1_pin9_io"] ;#PMOD6_PIN9_R set_property IOSTANDARD LVCMOS33 [get_ports "Pmod_out_1_pin9_io"] ;#PMOD6_PIN9_R set_property PACKAGE_PIN B17 [get_ports "Pmod_out_1_pin10_io"] ;#PMOD6_PIN10_R set_property IOSTANDARD LVCMOS33 [get_ports "Pmod_out_1_pin10_io"] ;#PMOD6_PIN10_R set_property PACKAGE_PIN AB1 [get_ports {ddr3_sram_dqs_n[1]}] set_property PACKAGE_PIN P5 [get_ports {ddr3_sram_dqs_p[0]}] set_property PACKAGE_PIN P4 [get_ports {ddr3_sram_dqs_n[0]}] set_property PACKAGE_PIN AA2 [get_ports {ddr3_sram_dqs_p[1]}] #Get parameters from base instance create_clock -period 5.000 [get_ports sys_diff_clock_clk_p] set_property IOSTANDARD LVDS_25 [get_ports sys_diff_clock_clk_n] set_property PACKAGE_PIN AE8 [get_ports sys_diff_clock_clk_p] set_property PACKAGE_PIN AE7 [get_ports sys_diff_clock_clk_n] set_property IOSTANDARD LVDS_25 [get_ports sys_diff_clock_clk_p] # set_property PACKAGE_PIN F17 [get_ports "iic_rtl_0_scl_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L23P_T3_16 # set_property IOSTANDARD LVCMOS33 [get_ports "iic_rtl_0_scl_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L23P_T3_16 # set_property PACKAGE_PIN F18 [get_ports "iic_rtl_0_sda_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L23N_T3_16 # set_property IOSTANDARD LVCMOS33 [get_ports "iic_rtl_0_sda_io"] ;# Bank 16 VCCO - VCCO_3V3 - IO_L23N_T3_16 # FT4232_B #set_property PACKAGE_PIN Y21 [get_ports "sout_0"] ; #set_property IOSTANDARD LVCMOS33 [get_ports "sout_0"] ; # #set_property PACKAGE_PIN Y22 [get_ports "sin_0"] ; #set_property IOSTANDARD LVCMOS33 [get_ports "sin_0"] ; # # FT4232_C # set_property PACKAGE_PIN AB25 [get_ports "sout_1"] ; # set_property IOSTANDARD LVCMOS18 [get_ports "sout_1"] ; # set_property PACKAGE_PIN AD26 [get_ports "sin_1"] ; # set_property IOSTANDARD LVCMOS18 [get_ports "sin_1"] ; set_property PACKAGE_PIN AA20 [get_ports reset_rtl_0] set_property IOSTANDARD LVCMOS18 [get_ports reset_rtl_0] set_property PACKAGE_PIN AE15 [get_ports reset] set_property IOSTANDARD LVCMOS18 [get_ports reset] # set_property PACKAGE_PIN AC7 [get_ports "mdio_mdc_mdio_io"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L6N_T0_VREF_33 # set_property IOSTANDARD LVCMOS25 [get_ports "mdio_mdc_mdio_io"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L6N_T0_VREF_33 # set_property PACKAGE_PIN AE1 [get_ports "mdio_mdc_mdc"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L14N_T2_SRCC_33 # set_property IOSTANDARD LVCMOS25 [get_ports "mdio_mdc_mdc"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L14N_T2_SRCC_33 #set_property PACKAGE_PIN AD1 [get_ports "phy_reset_out"]; #set_property IOSTANDARD LVCMOS25 [get_ports "phy_reset_out"]; # set_property PACKAGE_PIN AE2 [get_ports "ETH_INT"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L15P_T2_DQS_33 # set_property IOSTANDARD LVCMOSxx [get_ports "ETH_INT"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L15P_T2_DQS_33 #set_property PACKAGE_PIN AF4 [get_ports "rgmii_td[0]"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L21P_T3_DQS_33 #set_property IOSTANDARD LVCMOS25 [get_ports "rgmii_td[0]"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L21P_T3_DQS_33 #set_property PACKAGE_PIN AD3 [get_ports "rgmii_td[1]"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L9N_T1_DQS_33 #set_property IOSTANDARD LVCMOS25 [get_ports "rgmii_td[1]"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L9N_T1_DQS_33 #set_property PACKAGE_PIN AF5 [get_ports "rgmii_td[2]"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L21N_T3_DQS_33 #set_property IOSTANDARD LVCMOS25 [get_ports "rgmii_td[2]"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L21N_T3_DQS_33 #set_property PACKAGE_PIN AC4 [get_ports "rgmii_td[3]"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L5N_T0_33 #set_property IOSTANDARD LVCMOS25 [get_ports "rgmii_td[3]"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L5N_T0_33 #set_property PACKAGE_PIN AC3 [get_ports "rgmii_txc"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L5P_T0_33 #set_property IOSTANDARD LVCMOS25 [get_ports "rgmii_txc"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L5P_T0_33 #set_property PACKAGE_PIN AD4 [get_ports "rgmii_tx_ctl"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L10P_T1_33 #set_property IOSTANDARD LVCMOS25 [get_ports "rgmii_tx_ctl"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L10P_T1_33 # # #set_property PACKAGE_PIN AE3 [get_ports "rgmii_rd[0]"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L15N_T2_DQS_33 #set_property IOSTANDARD LVCMOS25 [get_ports "rgmii_rd[0]"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L15N_T2_DQS_33 #set_property PACKAGE_PIN AF2 [get_ports "rgmii_rd[1]"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L20P_T3_33 #set_property IOSTANDARD LVCMOS25 [get_ports "rgmii_rd[1]"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L20P_T3_33 #set_property PACKAGE_PIN AF3 [get_ports "rgmii_rd[2]"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L20N_T3_33 #set_property IOSTANDARD LVCMOS25 [get_ports "rgmii_rd[2]"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L20N_T3_33 #set_property PACKAGE_PIN AC2 [get_ports "rgmii_rd[3]"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L4N_T0_33 #set_property IOSTANDARD LVCMOS25 [get_ports "rgmii_rd[3]"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L4N_T0_33 #set_property PACKAGE_PIN AF7 [get_ports "rgmii_rx_ctl"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L22P_T3_33 #set_property IOSTANDARD LVCMOS25 [get_ports "rgmii_rx_ctl"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L22P_T3_33 #set_property PACKAGE_PIN AF8 [get_ports "rgmii_rxc"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L22N_T3_33 #set_property IOSTANDARD LVCMOS25 [get_ports "rgmii_rxc"] ;# Bank 33 VCCO - VCCO_2V5 - IO_L22N_T3_33 ########################################################################################## ## PMOD Loopback ## #set_property PACKAGE_PIN C13 [get_ports "PMOD_OUT_tri_o[0]"] ;#PMOD1_PIN1_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[0]"] ;#PMOD1_PIN1_R #set_property PACKAGE_PIN D14 [get_ports "PMOD_OUT_tri_o[1]"] ;#PMOD1_PIN2_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[1]"] ;#PMOD1_PIN2_R #set_property PACKAGE_PIN B14 [get_ports "PMOD_OUT_tri_o[2]"] ;#PMOD1_PIN3_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[2]"] ;#PMOD1_PIN3_R #set_property PACKAGE_PIN B15 [get_ports "PMOD_OUT_tri_o[3]"] ;#PMOD1_PIN4_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[3]"] ;#PMOD1_PIN4_R #set_property PACKAGE_PIN A13 [get_ports "PMOD_IN_tri_i[0]"] ;#PMOD1_PIN7_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[0]"] ;#PMOD1_PIN7_R #set_property PACKAGE_PIN C14 [get_ports "PMOD_IN_tri_i[1]"] ;#PMOD1_PIN8_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[1]"] ;#PMOD1_PIN8_R #set_property PACKAGE_PIN A14 [get_ports "PMOD_IN_tri_i[2]"] ;#PMOD1_PIN9_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[2]"] ;#PMOD1_PIN9_R #set_property PACKAGE_PIN A15 [get_ports "PMOD_IN_tri_i[3]"] ;#PMOD1_PIN10_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[3]"] ;#PMOD1_PIN10_R #set_property PACKAGE_PIN D16 [get_ports "PMOD_OUT_tri_o[4]"] ;#PMOD2_PIN1_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[4]"] ;#PMOD2_PIN1_R #set_property PACKAGE_PIN E18 [get_ports "PMOD_OUT_tri_o[5]"] ;#PMOD2_PIN2_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[5]"] ;#PMOD2_PIN2_R #set_property PACKAGE_PIN E20 [get_ports "PMOD_OUT_tri_o[6]"] ;#PMOD2_PIN3_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[6]"] ;#PMOD2_PIN3_R #set_property PACKAGE_PIN F19 [get_ports "PMOD_OUT_tri_o[7]"] ;#PMOD2_PIN4_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[7]"] ;#PMOD2_PIN4_R #set_property PACKAGE_PIN C17 [get_ports "PMOD_IN_tri_i[4]"] ;#PMOD2_PIN7_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[4]"] ;#PMOD2_PIN7_R #set_property PACKAGE_PIN D19 [get_ports "PMOD_IN_tri_i[5]"] ;#PMOD2_PIN8_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[5]"] ;#PMOD2_PIN8_R #set_property PACKAGE_PIN E16 [get_ports "PMOD_IN_tri_i[6]"] ;#PMOD2_PIN9_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[6]"] ;#PMOD2_PIN9_R #set_property PACKAGE_PIN G19 [get_ports "PMOD_IN_tri_i[7]"] ;#PMOD2_PIN10_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[7]"] ;#PMOD2_PIN10_R #set_property PACKAGE_PIN C22 [get_ports "PMOD_OUT_tri_o[8]"] ;#PMOD3_PIN1_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[8]"] ;#PMOD3_PIN1_R #set_property PACKAGE_PIN E21 [get_ports "PMOD_OUT_tri_o[9]"] ;#PMOD3_PIN2_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[9]"] ;#PMOD3_PIN2_R #set_property PACKAGE_PIN F20 [get_ports "PMOD_OUT_tri_o[10]"] ;#PMOD3_PIN3_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[10]"] ;#PMOD3_PIN3_R #set_property PACKAGE_PIN D18 [get_ports "PMOD_OUT_tri_o[11]"] ;#PMOD3_PIN4_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[11]"] ;#PMOD3_PIN4_R #set_property PACKAGE_PIN D21 [get_ports "PMOD_IN_tri_i[8]"] ;#PMOD3_PIN7_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[8]"] ;#PMOD3_PIN7_R #set_property PACKAGE_PIN D20 [get_ports "PMOD_IN_tri_i[9]"] ;#PMOD3_PIN8_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[9]"] ;#PMOD3_PIN8_R #set_property PACKAGE_PIN C19 [get_ports "PMOD_IN_tri_i[10]"] ;#PMOD3_PIN9_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[10]"] ;#PMOD3_PIN9_R #set_property PACKAGE_PIN E17 [get_ports "PMOD_IN_tri_i[11]"] ;#PMOD3_PIN10_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[11]"] ;#PMOD3_PIN10_R #set_property PACKAGE_PIN A23 [get_ports "PMOD_OUT_tri_o[12]"] ;#PMOD4_PIN1_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[12]"] ;#PMOD4_PIN1_R #set_property PACKAGE_PIN A24 [get_ports "PMOD_OUT_tri_o[13]"] ;#PMOD4_PIN2_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[13]"] ;#PMOD4_PIN2_R #set_property PACKAGE_PIN B24 [get_ports "PMOD_OUT_tri_o[14]"] ;#PMOD4_PIN3_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[14]"] ;#PMOD4_PIN3_R #set_property PACKAGE_PIN C23 [get_ports "PMOD_OUT_tri_o[15]"] ;#PMOD4_PIN4_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[15]"] ;#PMOD4_PIN4_R #set_property PACKAGE_PIN B22 [get_ports "PMOD_IN_tri_i[12]"] ;#PMOD4_PIN7_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[12]"] ;#PMOD4_PIN7_R #set_property PACKAGE_PIN A25 [get_ports "PMOD_IN_tri_i[13]"] ;#PMOD4_PIN8_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[13]"] ;#PMOD4_PIN8_R #set_property PACKAGE_PIN C24 [get_ports "PMOD_IN_tri_i[14]"] ;#PMOD4_PIN9_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[14]"] ;#PMOD4_PIN9_R #set_property PACKAGE_PIN C21 [get_ports "PMOD_IN_tri_i[15]"] ;#PMOD4_PIN10_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[15]"] ;#PMOD4_PIN10_R #set_property PACKAGE_PIN A18 [get_ports "PMOD_OUT_tri_o[16]"] ;#PMOD5_PIN1_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[16]"] ;#PMOD5_PIN1_R #set_property PACKAGE_PIN A19 [get_ports "PMOD_OUT_tri_o[17]"] ;#PMOD5_PIN2_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[17]"] ;#PMOD5_PIN2_R #set_property PACKAGE_PIN A20 [get_ports "PMOD_OUT_tri_o[18]"] ;#PMOD5_PIN3_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[18]"] ;#PMOD5_PIN3_R #set_property PACKAGE_PIN B21 [get_ports "PMOD_OUT_tri_o[19]"] ;#PMOD5_PIN4_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[19]"] ;#PMOD5_PIN4_R #set_property PACKAGE_PIN C18 [get_ports "PMOD_IN_tri_i[16]"] ;#PMOD5_PIN7_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[16]"] ;#PMOD5_PIN7_R #set_property PACKAGE_PIN B19 [get_ports "PMOD_IN_tri_i[17]"] ;#PMOD5_PIN8_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[17]"] ;#PMOD5_PIN8_R #set_property PACKAGE_PIN B20 [get_ports "PMOD_IN_tri_i[18]"] ;#PMOD5_PIN9_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[18]"] ;#PMOD5_PIN9_R #set_property PACKAGE_PIN A22 [get_ports "PMOD_IN_tri_i[19]"] ;#PMOD5_PIN10_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[19]"] ;#PMOD5_PIN10_R #set_property PACKAGE_PIN F14 [get_ports "PMOD_OUT_tri_o[20]"] ;#PMOD6_PIN1_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[20]"] ;#PMOD6_PIN1_R #set_property PACKAGE_PIN E15 [get_ports "PMOD_OUT_tri_o[21]"] ;#PMOD6_PIN2_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[21]"] ;#PMOD6_PIN2_R #set_property PACKAGE_PIN C16 [get_ports "PMOD_OUT_tri_o[22]"] ;#PMOD6_PIN3_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[22]"] ;#PMOD6_PIN3_R #set_property PACKAGE_PIN A17 [get_ports "PMOD_OUT_tri_o[23]"] ;#PMOD6_PIN4_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_OUT_tri_o[23]"] ;#PMOD6_PIN4_R #set_property PACKAGE_PIN F15 [get_ports "PMOD_IN_tri_i[20]"] ;#PMOD6_PIN7_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[20]"] ;#PMOD6_PIN7_R #set_property PACKAGE_PIN D15 [get_ports "PMOD_IN_tri_i[21]"] ;#PMOD6_PIN8_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[21]"] ;#PMOD6_PIN8_R #set_property PACKAGE_PIN B16 [get_ports "PMOD_IN_tri_i[22]"] ;#PMOD6_PIN9_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[22]"] ;#PMOD6_PIN9_R #set_property PACKAGE_PIN B17 [get_ports "PMOD_IN_tri_i[23]"] ;#PMOD6_PIN10_R #set_property IOSTANDARD LVCMOS33 [get_ports "PMOD_IN_tri_i[23]"] ;#PMOD6_PIN10_R ################################################################################################## ## ## Xilinx, Inc. 2010 www.xilinx.com ## Wed Jan 2 19:07:19 2019 ## Generated by MIG Version 4.2 ## ################################################################################################## ## File name : example_top.xdc ## Details : Constraints file ## FPGA Family: SPARTAN7 ## FPGA Part: XC7S100-FGGA676 ## Speedgrade: -2 ## Design Entry: VERILOG ## Frequency: 400 MHz ## Time Period: 2500 ps ################################################################################################## ################################################################################################## ## Controller 0 ## Memory Device: DDR3_SDRAM->Components->MT41K256M16XX-107 ## Data Width: 16 ## Time Period: 2500 ## Data Mask: 1 ################################################################################################## ############## NET - IOSTANDARD ################## ################################################################################################## ## ## Xilinx, Inc. 2010 www.xilinx.com ## Sun Dec 16 14:08:23 2018 ## Generated by MIG Version 4.2 ## ################################################################################################## ## File name : example_top.xdc ## Details : Constraints file ## FPGA Family: SPARTAN7 ## FPGA Part: XC7S100-FGGA676 ## Speedgrade: -2 ## Design Entry: VERILOG ## Frequency: 303.02999999999997 MHz ## Time Period: 3300 ps ################################################################################################## ################################################################################################## ## Controller 0 ## Memory Device: DDR3_SDRAM->Components->MT41K256M16XX-107 ## Data Width: 16 ## Time Period: 3300 ## Data Mask: 1 ################################################################################################## ############## NET - IOSTANDARD ################## ## PadFunction: #set_property IOSTANDARD LVCMOS33 [get_ports {init_calib_complete}] #set_property PACKAGE_PIN M24 [get_ports {init_calib_complete}] # ## PadFunction: #set_property IOSTANDARD LVCMOS33 [get_ports {tg_compare_error}] #set_property PACKAGE_PIN L24 [get_ports {tg_compare_error}] # set_property INTERNAL_VREF 0.675 [get_iobanks 34] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_addr[0]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_addr[10]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_addr[11]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_addr[12]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_addr[13]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_addr[14]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_addr[1]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_addr[2]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_addr[3]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_addr[4]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_addr[5]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_addr[6]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_addr[7]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_addr[8]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_addr[9]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_ba[0]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_ba[1]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_ba[2]}] set_property IOSTANDARD SSTL135 [get_ports ddr3_sram_cas_n] set_property IOSTANDARD DIFF_SSTL135 [get_ports {ddr3_sram_ck_n[0]}] set_property IOSTANDARD DIFF_SSTL135 [get_ports {ddr3_sram_ck_p[0]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_cke[0]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dm[0]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dm[1]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dq[0]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dq[10]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dq[11]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dq[12]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dq[13]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dq[14]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dq[15]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dq[1]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dq[2]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dq[3]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dq[4]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dq[5]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dq[6]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dq[7]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dq[8]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_dq[9]}] set_property IOSTANDARD DIFF_SSTL135 [get_ports {ddr3_sram_dqs_n[0]}] set_property IOSTANDARD DIFF_SSTL135 [get_ports {ddr3_sram_dqs_n[1]}] set_property IOSTANDARD DIFF_SSTL135 [get_ports {ddr3_sram_dqs_p[0]}] set_property IOSTANDARD DIFF_SSTL135 [get_ports {ddr3_sram_dqs_p[1]}] set_property IOSTANDARD SSTL135 [get_ports {ddr3_sram_odt[0]}] set_property IOSTANDARD SSTL135 [get_ports ddr3_sram_ras_n] set_property IOSTANDARD SSTL135 [get_ports ddr3_sram_reset_n] set_property IOSTANDARD SSTL135 [get_ports ddr3_sram_we_n] ############################################################################## set_property PACKAGE_PIN Y5 [get_ports {ddr3_sram_addr[0]}] set_property PACKAGE_PIN W4 [get_ports {ddr3_sram_addr[10]}] set_property PACKAGE_PIN V6 [get_ports {ddr3_sram_addr[11]}] set_property PACKAGE_PIN W5 [get_ports {ddr3_sram_addr[12]}] set_property PACKAGE_PIN AB5 [get_ports {ddr3_sram_addr[13]}] set_property PACKAGE_PIN V7 [get_ports {ddr3_sram_addr[14]}] set_property PACKAGE_PIN U5 [get_ports {ddr3_sram_addr[1]}] set_property PACKAGE_PIN AA3 [get_ports {ddr3_sram_addr[2]}] set_property PACKAGE_PIN U6 [get_ports {ddr3_sram_addr[3]}] set_property PACKAGE_PIN AA5 [get_ports {ddr3_sram_addr[4]}] set_property PACKAGE_PIN U7 [get_ports {ddr3_sram_addr[5]}] set_property PACKAGE_PIN AA7 [get_ports {ddr3_sram_addr[6]}] set_property PACKAGE_PIN T7 [get_ports {ddr3_sram_addr[7]}] set_property PACKAGE_PIN Y8 [get_ports {ddr3_sram_addr[8]}] set_property PACKAGE_PIN AB4 [get_ports {ddr3_sram_addr[9]}] set_property PACKAGE_PIN T4 [get_ports {ddr3_sram_ba[0]}] set_property PACKAGE_PIN AA4 [get_ports {ddr3_sram_ba[1]}] set_property PACKAGE_PIN W3 [get_ports {ddr3_sram_ba[2]}] set_property PACKAGE_PIN U4 [get_ports ddr3_sram_cas_n] set_property PACKAGE_PIN W6 [get_ports {ddr3_sram_ck_p[0]}] set_property PACKAGE_PIN Y6 [get_ports {ddr3_sram_ck_n[0]}] set_property PACKAGE_PIN Y7 [get_ports {ddr3_sram_cke[0]}] set_property PACKAGE_PIN R5 [get_ports {ddr3_sram_dm[0]}] set_property PACKAGE_PIN Y3 [get_ports {ddr3_sram_dm[1]}] set_property PACKAGE_PIN R2 [get_ports {ddr3_sram_dq[0]}] set_property PACKAGE_PIN Y1 [get_ports {ddr3_sram_dq[10]}] set_property PACKAGE_PIN U1 [get_ports {ddr3_sram_dq[11]}] set_property PACKAGE_PIN AB2 [get_ports {ddr3_sram_dq[12]}] set_property PACKAGE_PIN V1 [get_ports {ddr3_sram_dq[13]}] set_property PACKAGE_PIN AC1 [get_ports {ddr3_sram_dq[14]}] set_property PACKAGE_PIN V3 [get_ports {ddr3_sram_dq[15]}] set_property PACKAGE_PIN R3 [get_ports {ddr3_sram_dq[1]}] set_property PACKAGE_PIN P1 [get_ports {ddr3_sram_dq[2]}] set_property PACKAGE_PIN T5 [get_ports {ddr3_sram_dq[3]}] set_property PACKAGE_PIN R1 [get_ports {ddr3_sram_dq[4]}] set_property PACKAGE_PIN R7 [get_ports {ddr3_sram_dq[5]}] set_property PACKAGE_PIN P3 [get_ports {ddr3_sram_dq[6]}] set_property PACKAGE_PIN T2 [get_ports {ddr3_sram_dq[7]}] set_property PACKAGE_PIN Y2 [get_ports {ddr3_sram_dq[8]}] set_property PACKAGE_PIN W1 [get_ports {ddr3_sram_dq[9]}] set_property PACKAGE_PIN T3 [get_ports {ddr3_sram_odt[0]}] set_property PACKAGE_PIN U2 [get_ports ddr3_sram_ras_n] set_property PACKAGE_PIN P6 [get_ports ddr3_sram_reset_n] set_property PACKAGE_PIN V4 [get_ports ddr3_sram_we_n] ################################################################################### #csi-phy ##For SP701 swapped pins set_property PACKAGE_PIN AC12 [get_ports {mipi_phy_if_0_data_lp_p[1]}] set_property PACKAGE_PIN AE12 [get_ports {mipi_phy_if_0_data_lp_n[1]}] set_property PACKAGE_PIN AF10 [get_ports {mipi_phy_if_0_data_lp_p[0]}] set_property PACKAGE_PIN AF9 [get_ports {mipi_phy_if_0_data_lp_n[0]}] set_property PACKAGE_PIN AC9 [get_ports mipi_phy_if_0_clk_lp_p] set_property PACKAGE_PIN AD8 [get_ports mipi_phy_if_0_clk_lp_n] set_property PACKAGE_PIN AD10 [get_ports {mipi_phy_if_0_data_hs_p[0]}] set_property PACKAGE_PIN AD9 [get_ports {mipi_phy_if_0_data_hs_n[0]}] set_property PACKAGE_PIN AA9 [get_ports {mipi_phy_if_0_data_hs_p[1]}] set_property PACKAGE_PIN AB9 [get_ports {mipi_phy_if_0_data_hs_n[1]}] set_property PACKAGE_PIN AA10 [get_ports mipi_phy_if_0_clk_hs_p] set_property PACKAGE_PIN AB10 [get_ports mipi_phy_if_0_clk_hs_n] ##Use for Switching between IO standards set_property IOSTANDARD HSUL_12 [get_ports {mipi_phy_if_0_data_lp_n[1]}] set_property IOSTANDARD HSUL_12 [get_ports {mipi_phy_if_0_data_lp_p[1]}] set_property IOSTANDARD HSUL_12 [get_ports {mipi_phy_if_0_data_lp_n[0]}] set_property IOSTANDARD HSUL_12 [get_ports {mipi_phy_if_0_data_lp_p[0]}] set_property IOSTANDARD HSUL_12 [get_ports mipi_phy_if_0_clk_lp_n] set_property IOSTANDARD HSUL_12 [get_ports mipi_phy_if_0_clk_lp_p] set_property IOSTANDARD LVDS_25 [get_ports {mipi_phy_if_0_data_hs_n[1]}] set_property IOSTANDARD LVDS_25 [get_ports mipi_phy_if_0_clk_hs_n] set_property IOSTANDARD LVDS_25 [get_ports {mipi_phy_if_0_data_hs_p[1]}] set_property IOSTANDARD LVDS_25 [get_ports mipi_phy_if_0_clk_hs_p] set_property IOSTANDARD LVDS_25 [get_ports {mipi_phy_if_0_data_hs_n[0]}] set_property IOSTANDARD LVDS_25 [get_ports {mipi_phy_if_0_data_hs_p[0]}] #csi-gpio set_property PACKAGE_PIN AF12 [get_ports {GPIO_sensor_tri_o[0]}] set_property IOSTANDARD LVCMOS25 [get_ports {GPIO_sensor_tri_o[0]}] #csi-iic0 set_property PACKAGE_PIN F17 [get_ports IIC_expander_scl_io] set_property IOSTANDARD LVCMOS33 [get_ports IIC_expander_scl_io] set_property PULLUP true [get_ports IIC_expander_scl_io] set_property PACKAGE_PIN F18 [get_ports IIC_expander_sda_io] set_property IOSTANDARD LVCMOS33 [get_ports IIC_expander_sda_io] set_property PULLUP true [get_ports IIC_expander_sda_io] #csi-iic1 set_property PACKAGE_PIN AD13 [get_ports IIC_sensor_scl_io] set_property IOSTANDARD LVCMOS25 [get_ports IIC_sensor_scl_io] set_property PULLUP true [get_ports IIC_sensor_scl_io] set_property PACKAGE_PIN AE13 [get_ports IIC_sensor_sda_io] set_property IOSTANDARD LVCMOS25 [get_ports IIC_sensor_sda_io] set_property PULLUP true [get_ports IIC_sensor_sda_io] #uart set_property PACKAGE_PIN Y21 [get_ports rs232_uart_txd] set_property IOSTANDARD LVCMOS33 [get_ports rs232_uart_txd] set_property PACKAGE_PIN Y22 [get_ports rs232_uart_rxd] set_property IOSTANDARD LVCMOS33 [get_ports rs232_uart_rxd] #dsi-phy #dsi-gpio #0-LED_EN #1-PWN set_property PACKAGE_PIN AF24 [get_ports {GPIO_dsi_tri_o[0]}] set_property PACKAGE_PIN AB26 [get_ports {GPIO_dsi_tri_o[1]}] set_property IOSTANDARD LVCMOS18 [get_ports {GPIO_dsi_tri_o[*]}] set_property INTERNAL_VREF 0.6 [get_iobanks 33] ##HDMI set_property PACKAGE_PIN J24 [get_ports IIC_0_scl_io] set_property IOSTANDARD LVCMOS33 [get_ports IIC_0_scl_io] set_property PACKAGE_PIN K23 [get_ports IIC_0_sda_io] set_property IOSTANDARD LVCMOS33 [get_ports IIC_0_sda_io] #R/CR colorspace set_property PACKAGE_PIN D26 [get_ports {vid_data[23]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[23]}] set_property PACKAGE_PIN H24 [get_ports {vid_data[22]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[22]}] set_property PACKAGE_PIN B26 [get_ports {vid_data[21]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[21]}] set_property PACKAGE_PIN B25 [get_ports {vid_data[20]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[20]}] set_property PACKAGE_PIN H26 [get_ports {vid_data[19]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[19]}] set_property PACKAGE_PIN D24 [get_ports {vid_data[18]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[18]}] set_property PACKAGE_PIN F25 [get_ports {vid_data[17]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[17]}] set_property PACKAGE_PIN D23 [get_ports {vid_data[16]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[16]}] #GREEN/Y colorspace set_property PACKAGE_PIN E25 [get_ports {vid_data[7]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[7]}] set_property PACKAGE_PIN E23 [get_ports {vid_data[6]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[6]}] set_property PACKAGE_PIN E22 [get_ports {vid_data[5]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[5]}] set_property PACKAGE_PIN D25 [get_ports {vid_data[4]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[4]}] set_property PACKAGE_PIN J26 [get_ports {vid_data[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[3]}] set_property PACKAGE_PIN G22 [get_ports {vid_data[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[2]}] set_property PACKAGE_PIN M21 [get_ports {vid_data[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[1]}] set_property PACKAGE_PIN M20 [get_ports {vid_data[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[0]}] #B / CB colorspace set_property PACKAGE_PIN L20 [get_ports {vid_data[15]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[15]}] set_property PACKAGE_PIN F23 [get_ports {vid_data[14]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[14]}] set_property PACKAGE_PIN G24 [get_ports {vid_data[13]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[13]}] set_property PACKAGE_PIN G25 [get_ports {vid_data[12]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[12]}] set_property PACKAGE_PIN G26 [get_ports {vid_data[11]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[11]}] set_property PACKAGE_PIN K20 [get_ports {vid_data[10]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[10]}] set_property PACKAGE_PIN J23 [get_ports {vid_data[9]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[9]}] set_property PACKAGE_PIN F24 [get_ports {vid_data[8]}] set_property IOSTANDARD LVCMOS33 [get_ports {vid_data[8]}] set_property PACKAGE_PIN F22 [get_ports video_clk_out] set_property IOSTANDARD LVCMOS33 [get_ports video_clk_out] set_property PACKAGE_PIN L23 [get_ports vid_active_video] set_property IOSTANDARD LVCMOS33 [get_ports vid_active_video] set_property PACKAGE_PIN C26 [get_ports vid_hsync] set_property IOSTANDARD LVCMOS33 [get_ports vid_hsync] set_property PACKAGE_PIN E26 [get_ports vid_vsync] set_property IOSTANDARD LVCMOS33 [get_ports vid_vsync] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_ddr3_infrastructure/rstdiv0_sync_r_reg[0]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_ddr3_infrastructure/rstdiv0_sync_r_reg[1]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_ddr3_infrastructure/rstdiv0_sync_r_reg[2]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_ddr3_infrastructure/rstdiv0_sync_r_reg[3]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_ddr3_infrastructure/rstdiv0_sync_r_reg[4]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_ddr3_infrastructure/rstdiv0_sync_r_reg[5]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_ddr3_infrastructure/rstdiv0_sync_r_reg[6]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_ddr3_infrastructure/rstdiv0_sync_r_reg[7]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_ddr3_infrastructure/rstdiv0_sync_r_reg[8]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_ddr3_infrastructure/rstdiv0_sync_r_reg[9]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_ddr3_infrastructure/rstdiv0_sync_r_reg[10]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_ddr3_infrastructure/rstdiv0_sync_r_reg[11]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_iodelay_ctrl/rst_ref_sync_r_reg[0][0]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_iodelay_ctrl/rst_ref_sync_r_reg[0][1]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_iodelay_ctrl/rst_ref_sync_r_reg[0][2]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_iodelay_ctrl/rst_ref_sync_r_reg[0][3]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_iodelay_ctrl/rst_ref_sync_r_reg[0][4]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_iodelay_ctrl/rst_ref_sync_r_reg[0][5]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_iodelay_ctrl/rst_ref_sync_r_reg[0][6]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_iodelay_ctrl/rst_ref_sync_r_reg[0][7]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_iodelay_ctrl/rst_ref_sync_r_reg[0][8]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_iodelay_ctrl/rst_ref_sync_r_reg[0][9]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_iodelay_ctrl/rst_ref_sync_r_reg[0][10]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_iodelay_ctrl/rst_ref_sync_r_reg[0][11]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_iodelay_ctrl/rst_ref_sync_r_reg[0][12]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_iodelay_ctrl/rst_ref_sync_r_reg[0][13]}] set_property ASYNC_REG true [get_cells {design_1_i/mig_7series_1/u_design_1_mig_7series_1_0_mig/u_iodelay_ctrl/rst_ref_sync_r_reg[0][14]}] 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]
Environmental Monitor MicroBlaze Bare Metal Application with Vitis IDE
We already have our hardware designed with Vitis Vivado. The next step is to export the design as an .xsa file including the bitstream to be able to program the FPGA from Vitis IDE.
The .xsa file contains the Board Support Package (BSP) with all the drivers and examples needed for rapid prototyping in C or C++.
Since we have opted for a solution using hardware accelerators, I decided to create a bare metal application without including an operating system that is simply in charge of configuring the camera, configurable IP blocks and communicating with the sensors and our heads-up display block.
Vitis C Code
#include "xparameters.h" #include "xiic.h" #include "xil_exception.h" #include "function_prototype.h" #include "pcam_5C_cfgs.h" #include "xstatus.h" #include "sleep.h" #include "xiic_l.h" #include "xil_io.h" #include "xil_types.h" #include "xv_tpg.h" #include "xil_cache.h" #include "stdio.h" #include "xv_mix.h" #include "xff_monitor_gen.h" #include "PmodHYGRO.h" #include "PmodAQS.h" #define U32TOBCD(u) ((((u/10000000)%10)<<28)| (((u/1000000)%10)<<24)|\ (((u/100000)%10)<<20) | (((u/10000)%10)<<16)|\ (((u/1000)%10)<<12) | (((u/100)%10)<<8)|\ (((u/10)%10)<<4)|(u%10)) #define U16TOBCD(u) ((((u/1000)%10)<<12) | (((u/100)%10)<<8)|\ (((u/10)%10)<<4)|(u%10)) #define U8TOBCD(u) ((((u/10)%10)<<4)|(u%10)) #ifdef __MICROBLAZE__ #define TIMER_FREQ_HZ XPAR_CPU_M_AXI_DP_FREQ_HZ #else #define TIMER_FREQ_HZ 100000000 #endif /************************** Constant Definitions *****************************/ #define PAGE_SIZE 16 #define IIC_BASE_ADDRESS XPAR_IIC_2_BASEADDR #define EEPROM_TEST_START_ADDRESS 0x80 #define IIC_SWITCH_ADDRESS 0x74 #define IIC_ADV7511_ADDRESS 0x39 typedef u8 AddressType; typedef struct { u8 addr; u8 data; u8 init; } HDMI_REG; #define NUMBER_OF_HDMI_REGS 16 HDMI_REG hdmi_iic[NUMBER_OF_HDMI_REGS] = { {0x41, 0x00, 0x10}, {0x98, 0x00, 0x03}, {0x9A, 0x00, 0xE0}, {0x9C, 0x00, 0x30}, {0x9D, 0x00, 0x61}, {0xA2, 0x00, 0xA4}, {0xA3, 0x00, 0xA4}, {0xE0, 0x00, 0xD0}, {0xF9, 0x00, 0x00}, {0x18, 0x00, 0xE7}, {0x55, 0x00, 0x00}, {0x56, 0x00, 0x28}, {0xD6, 0x00, 0xC0}, {0xAF, 0x00, 0x4}, {0xF9, 0x00, 0x00} }; u8 EepromIicAddr; /* Variable for storing Eeprom IIC address */ int IicLowLevelDynEeprom(); u8 EepromReadByte(AddressType Address, u8 *BufferPtr, u8 ByteCount); u8 EepromWriteByte(AddressType Address, u8 *BufferPtr, u8 ByteCount); /****************i************ Type Definitions *******************************/ typedef u8 AddressType; /************************** Variable Definitions *****************************/ extern XIic IicFmc, IicAdapter ; /* IIC device. */ //HDMI IIC int IicLowLevelDynEeprom() { u8 BytesRead; u32 StatusReg; u8 Index; int Status; u32 i; EepromIicAddr = IIC_SWITCH_ADDRESS; Status = XIic_DynInit(IIC_BASE_ADDRESS); if (Status != XST_SUCCESS) { return XST_FAILURE; } xil_printf("\r\nAfter XIic_DynInit\r\n"); while (((StatusReg = XIic_ReadReg(IIC_BASE_ADDRESS, XIIC_SR_REG_OFFSET)) & (XIIC_SR_RX_FIFO_EMPTY_MASK | XIIC_SR_TX_FIFO_EMPTY_MASK | XIIC_SR_BUS_BUSY_MASK)) != (XIIC_SR_RX_FIFO_EMPTY_MASK | XIIC_SR_TX_FIFO_EMPTY_MASK)) { } EepromIicAddr = IIC_ADV7511_ADDRESS; for ( Index = 0; Index < NUMBER_OF_HDMI_REGS; Index++) { EepromWriteByte(hdmi_iic[Index].addr, &hdmi_iic[Index].init, 1); } for ( Index = 0; Index < NUMBER_OF_HDMI_REGS; Index++) { BytesRead = EepromReadByte(hdmi_iic[Index].addr, &hdmi_iic[Index].data, 1); for(i=0;i<1000;i++) {}; // IIC delay if (BytesRead != 1) { return XST_FAILURE; } } return XST_SUCCESS; } /*****************************************************************************/ /** * This function writes a buffer of bytes to the IIC serial EEPROM. * * @param BufferPtr contains the address of the data to write. * @param ByteCount contains the number of bytes in the buffer to be * written. Note that this should not exceed the page size of the * EEPROM as noted by the constant PAGE_SIZE. * * @return The number of bytes written, a value less than that which was * specified as an input indicates an error. * * @note one. * ******************************************************************************/ u8 EepromWriteByte(AddressType Address, u8 *BufferPtr, u8 ByteCount) { u8 SentByteCount; u8 WriteBuffer[sizeof(Address) + PAGE_SIZE]; u8 Index; /* * A temporary write buffer must be used which contains both the address * and the data to be written, put the address in first based upon the * size of the address for the EEPROM */ if (sizeof(AddressType) == 2) { WriteBuffer[0] = (u8) (Address >> 8); WriteBuffer[1] = (u8) (Address); } else if (sizeof(AddressType) == 1) { WriteBuffer[0] = (u8) (Address); EepromIicAddr |= (EEPROM_TEST_START_ADDRESS >> 8) & 0x7; } /* * Put the data in the write buffer following the address. */ for (Index = 0; Index < ByteCount; Index++) { WriteBuffer[sizeof(Address) + Index] = BufferPtr[Index]; } /* * Write a page of data at the specified address to the EEPROM. */ SentByteCount = XIic_DynSend(IIC_BASE_ADDRESS, EepromIicAddr, WriteBuffer, sizeof(Address) + ByteCount, XIIC_STOP); /* * Return the number of bytes written to the EEPROM. */ return SentByteCount - sizeof(Address); } /****************************************************************************** * * This function reads a number of bytes from the IIC serial EEPROM into a * specified buffer. * * @param BufferPtr contains the address of the data buffer to be filled. * @param ByteCount contains the number of bytes in the buffer to be read. * This value is constrained by the page size of the device such * that up to 64K may be read in one call. * * @return The number of bytes read. A value less than the specified input * value indicates an error. * * @note None. * ******************************************************************************/ u8 EepromReadByte(AddressType Address, u8 *BufferPtr, u8 ByteCount) { u8 ReceivedByteCount; u8 SentByteCount; u16 StatusReg; /* * Position the Read pointer to specific location in the EEPROM. */ do { StatusReg = XIic_ReadReg(IIC_BASE_ADDRESS, XIIC_SR_REG_OFFSET); if (!(StatusReg & XIIC_SR_BUS_BUSY_MASK)) { SentByteCount = XIic_DynSend(IIC_BASE_ADDRESS, EepromIicAddr, (u8 *) &Address, sizeof(Address), XIIC_REPEATED_START); } } while (SentByteCount != sizeof(Address)); /* * Receive the data. */ ReceivedByteCount = XIic_DynRecv(IIC_BASE_ADDRESS, EepromIicAddr, BufferPtr, ByteCount); /* * Return the number of bytes received from the EEPROM. */ return ReceivedByteCount; } /*****************************************************************************/ /** * * Main function to initialize interop system and read data from AR0330 sensor * @param None. * * @return * - XST_SUCCESS if MIPI Interop was successful. * - XST_FAILURE if MIPI Interop failed. * * @note None. * ******************************************************************************/ int main() { int Status; int pcam5c_mode = 1; XV_mix xv_mix; XV_mix_Config *xv_config; XFf_monitor_gen_Config *XV_Ff_monitor_cfg; XFf_monitor_gen xv_ff_monitor; xil_printf("\n\r******************************************************\n\r"); Xil_ICacheDisable(); Xil_DCacheDisable(); xil_printf("\n\r** Environmental HUD **"); PmodHYGRO hygro; PmodAQS aqs; float temp_degc, hum_perrh; Status = IicLowLevelDynEeprom(); if (Status != XST_SUCCESS) { xil_printf("ADV7511 IIC programming FAILED\r\n"); return XST_FAILURE; } xil_printf("ADV7511 IIC programming PASSED\r\n"); //Initialize FMC, Adapter and Sensor IIC Status = InitIIC(); if (Status != XST_SUCCESS) { xil_printf("\n\r IIC initialization Failed \n\r"); return XST_FAILURE; } xil_printf("IIC Initializtion Done \n\r"); //Initialize FMC Interrupt System Status = SetupFmcInterruptSystem(&IicFmc); if (Status != XST_SUCCESS) { xil_printf("\n\rInterrupt System Initialization Failed \n\r"); return XST_FAILURE; } xil_printf("FMC Interrupt System Initialization Done \n\r"); //Set up IIC Interrupt Handlers SetupIICIntrHandlers(); xil_printf("IIC Interrupt Handlers Setup Done \n\r"); Status = SetFmcIICAddress(); if (Status != XST_SUCCESS) { xil_printf("\n\rFMC IIC Address Setup Failed \n\r"); return XST_FAILURE; } xil_printf("Fmc IIC Address Set\n\r"); //Initialize Adapter Interrupt System Status = SetupAdapterInterruptSystem(&IicAdapter); if (Status != XST_SUCCESS) { xil_printf("\n\rInterrupt System Initialization Failed \n\r"); return XST_FAILURE; } xil_printf("Adapter Interrupt System Initialization Done \n\r"); //Set Address of Adapter IIC Status = SetAdapterIICAddress(); if (Status != XST_SUCCESS) { xil_printf("\n\rAdapter IIC Address Setup Failed \n\r"); return XST_FAILURE; } xil_printf("Adapter IIC Address Set\n\r"); Status = InitializeCsiRxSs(); if (Status != XST_SUCCESS) { xil_printf("CSI Rx Ss Init failed status = %x.\r\n", Status); return XST_FAILURE; } 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)1920); XV_mix_Set_HwReg_height(&xv_mix, (u32) 1080); 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)1920); XV_mix_Set_HwReg_layerHeight_0(&xv_mix,(u32)1080); XV_mix_Set_HwReg_layerAlpha_0(&xv_mix, 255); 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)1920); XV_mix_Set_HwReg_layerHeight_1(&xv_mix,(u32)1080); XV_mix_Set_HwReg_layerAlpha_1(&xv_mix, 128); XV_mix_EnableAutoRestart(&xv_mix); XV_mix_Start(&xv_mix); // Ff monitor XV_Ff_monitor_cfg = XFf_monitor_gen_LookupConfig(XPAR_FF_MONITOR_GEN_0_DEVICE_ID); XFf_monitor_gen_CfgInitialize(&xv_ff_monitor,XV_Ff_monitor_cfg); XFf_monitor_gen_Set_row(&xv_ff_monitor, (u32) 1080); XFf_monitor_gen_Set_column(&xv_ff_monitor, (u32) 1920); XFf_monitor_gen_EnableAutoRestart(&xv_ff_monitor); XFf_monitor_gen_Start(&xv_ff_monitor); XFf_monitor_gen_Set_char_1(&xv_ff_monitor, 0x12345678); XFf_monitor_gen_Set_char_2(&xv_ff_monitor, 0x90123456); resetIp(); EnableCSI(); Status = demosaic(); if (Status != XST_SUCCESS) { xil_printf("\n\rDemosaic Failed \n\r"); return XST_FAILURE; } CamReset(); //Preconifgure Sensor Status = SensorPreConfig(pcam5c_mode); if (Status != XST_SUCCESS) { xil_printf("\n\rSensor PreConfiguration Failed \n\r"); return XST_FAILURE; } xil_printf("\n\rSensor is PreConfigured\n\r"); Status = vdma_hdmi(); if (Status != XST_SUCCESS) { xil_printf("\n\rVdma_hdmi Failed \n\r"); return XST_FAILURE; } Status = vtpg_hdmi(); if (Status != XST_SUCCESS) { xil_printf("\n\rVtpg Failed \n\r"); return XST_FAILURE; } WritetoReg(0x30, 0x08, 0x02); Sensor_Delay(); xil_printf("\n\rPipeline Configuration Completed \n\r"); xil_printf("\n\rHYGRO Init Started"); HYGRO_begin( &hygro, XPAR_PMODHYGRO_0_AXI_LITE_IIC_BASEADDR, 0x40, // Chip address of PmodHYGRO IIC XPAR_PMODHYGRO_0_AXI_LITE_TMR_BASEADDR, XPAR_PMODHYGRO_0_DEVICE_ID, TIMER_FREQ_HZ // Clock frequency of AXI bus, used to convert timer data ); xil_printf("\n\rHYGRO Init Done"); xil_printf("\n\rAQS Init Started"); AQS_begin(&aqs, XPAR_PMODAQS_0_AXI_LITE_IIC_BASEADDR, 0x5B); // Chip address of CS811 0x5A module IIC 0x5B PmocAQS xil_printf("\n\rAQS Init Done"); int hum; int temp; u8 buf[5]; u16 eCO2; u16 TVOC; while(1) { temp_degc = HYGRO_getTemperature(&hygro); temp = (int) temp_degc; hum_perrh = HYGRO_getHumidity(&hygro); hum = (int) hum_perrh; AQS_GetData(&aqs, buf); eCO2 = ((u16)buf[0] << 8) | ((u16)buf[1]); TVOC = ((u16)buf[2] << 8) | ((u16)buf[3]); //xil_printf("The CO2 = %d ppm\n\r",eCO2); //xil_printf("The VOC = %d ppb\n\r",TVOC); XFf_monitor_gen_Set_char_1(&xv_ff_monitor, (U16TOBCD(eCO2)<<16) | (U8TOBCD(temp)<<8) | U8TOBCD(hum)); } return XST_SUCCESS; }
Then program the FPGA.
The system in action while debugging IIC communications with the CCS811 Air Quality sensor
I had some problems with the communication with the sensors via IIC but with the help of the logic analyzer of the Digilent Analog Discovery 2 I was able to solve them quickly.
The Analog Discovery 2's Spartan-6 FPGA came to the aid of its brother Spartan-7 FPGA.
IIC communication with the CCS811 Air Quality Sensor
Conclusions and Next Steps
It is the fifth blog in the series. The monitor already displays important information from the air quality sensors and the humidity and temperature sensors superimposed on the video image in real time.
Hardware accelerated module programming with Vitis HLS may seem trivial but it is quite complex and requires a good understanding of digital electronics design.
The next step will be to integrate the Pmod NAV module and use the information provided by the magnetometer to display a compass on the heads up display.
The Complete "Sensor Fusion for Firefighters" Blog Series
- Sensor Fusion for Firefighters. Introductory blog
- Sensor Fusion for Firefighters. Getting Started with the AMD Xilinx SP701
- Sensor Fusion for Firefighters. AMD Xilinx SP701 - MIPI Video Pipe Camera to HDMI Display
- Sensor Fusion for Firefighters. Displaying heads-up video on the live feed
- Sensor Fusion for Firefighters. Environmental monitor heads-up display on Xilinx Spartan-7 SP701 development board
- Sensor Fusion for Firefighters. Compass and Environmental HUD monitor with the Spartan-7
- Sensor Fusion for Firefighters. Thermal Vision, Compass and Environmental HUD monitor with the Spartan-7
- Sensor Fusion for Firefighters. Summary Blog
Top Comments