Embedded Measurement System for FPGA

Similar projects worth following
Simulation tools can't help you and you cannot guess what is happening inside anymore. You need to see it now. You need an Embedded Measurement System in the FPGA that lets you see as much data as you need using as few resources as possible.

I found myself in a situation in which I had to debug a high-performance open source portable DDR Core. I needed to capture a lot of data to see as many events as possible. There weren’t just a few signals, but more than sixteen to understand what was happening. That is how ScopeIO was born.

Check the video description to download the files.

Its goals were:

  • Small footprint to embed it.
  • Portability.
  • VGA to display data.
  • Block RAM requirement only.
  • UDP to communicate with the computer.

Small footprint to embed it

ADSL, DVB-T,  ISDB-T, LTE, WiFi and others are OFDM signals. In those cases, a self-correlation function should be calculated to know when packets start or end. That is not difficult to do. However, if the measurement instrument lacks a self-correlation function it is not possible to trigger the signal at its boundaries. One can see that it is important that ScopeIO be as small as possible to embed it in the design to be debugged.

The table below shows the resources used by both implementations that are on the youtube channel.



Samples per Channel

Video Resolution

FPGA Slices

Block Rams

Artix-7 35T Arty






Spartan 3E Starter






VGA to display data

VGA is a well known video standard that is easy to implement, and it is pretty much available on every monitor. Many monitors that have a DVI port are easy to connect to a VGA port too through a mechanical adapter. A VGA port needs a minimum of GND, VSYNC, HSYNC and RGB pins. Four wires are more than enough if you don’t mind a monochrome image, or six to have eight colors. But if you have video dacs in the development kit, ScopeIO can display as many colors as there are available.

Block RAM requirement only

FPGAs have embedded memory blocks that are fast and easy to use but they are small compared to dynamic ram. As much as possible, the memory is used to capture the signal data to display. The memory is not used for video.

UDP to send data to the computer.

Commands to control ScopeIO are sent by UDP/IP. The commands are detected every time a packet with the corresponding MAC address : “00:00:00:01:02:03” - not much imagination there -  is received. A configuration in the PC is required as described in the video. A simple JavaScript Application controls everything else. Node,js and Nw.js are required to run it.


Portability is also one of the main goals. While videos on the channels are for Xilinx’s FPGA kits: Artix-7 35T Arty FPGA Evaluation Kit and Spartan 3E Starter kit board, ScopeIO is easy to port to other manufactures' devices and kit boards. You can find a porting to Latticesemi ECP3Versa, kit to which I have access.

  • USB real-time configuration handshake capture

    Miguel Angel08/23/2023 at 22:47 0 comments

    USB device communication link for #hdl4fpga is operational

  • USB core for SIO

    Miguel Angel07/08/2023 at 00:01 0 comments

    Some progress has been made on the USB core. The request set_address and get_descriptor are now recognized. The device_descriptor is successfully read by the PC. The Wireshark capture complies with the captured frame 

    data-capture screenshot data is little endian

    Wireshark screenshot

    The captured frames screenshot is a raw bitstream with bit stuffing extraction. CRC is included. Octets are MSB first. The screenshot data capture is done on the ULX3S board using HDL4FPGA's ser_debug app. You can find the LatticeDiamond project file at The active implementation is ser_debug

    USB core is now detected by Linux

  • Orangecrab was added to the project

    Miguel Angel05/26/2023 at 22:51 0 comments

     Graphics was ported to the orangecrab 

  • When leds are not enough

    Miguel Angel05/11/2023 at 17:09 0 comments

    Display testpoint values on screen. It helped me to find deadlock bug on the UDP comm system.

    Project files  can be found on


    Example of usage 

    library ieee;
    use ieee.std_logic_1164.all;
    entity ulx3s is
        generic (
            debug : boolean := false);
        port (
            clk_25mhz      : in    std_logic;
            ftdi_rxd       : out   std_logic;
            ftdi_txd       : in    std_logic := 'U';
            ftdi_nrts      : inout std_logic := 'U';
            ftdi_ndtr      : inout std_logic := 'U';
            ftdi_txden     : inout std_logic := 'U';
            btn_pwr_n      : in  std_logic := 'U';
            fire1          : in  std_logic := 'U';
            fire2          : in  std_logic := 'U';
            up             : in  std_logic := 'U';
            down           : in  std_logic := 'U';
            left           : in  std_logic := 'U';
            right          : in  std_logic := 'U';
            led            : out std_logic_vector(8-1 downto 0);
            sw             : in    std_logic_vector(4-1 downto 0) := (others => 'U');
            oled_clk       : out   std_logic;
            oled_mosi      : out   std_logic;
            oled_dc        : out   std_logic;
            oled_resn      : out   std_logic;
            oled_csn       : out   std_logic;
            --flash_csn      : out   std_logic;
            --flash_clk      : out   std_logic;
            --flash_mosi     : out   std_logic;
            --flash_miso     : in    std_logic;
            --flash_holdn    : out   std_logic;
            --flash_wpn      : out   std_logic;
            sd_clk         : in    std_logic := '-';
            sd_cmd         : out   std_logic; -- sd_cmd=MOSI (out)
            sd_d           : inout std_logic_vector(4-1 downto 0) := (others => 'U'); -- sd_d(0)=MISO (in), sd_d(3)=CSn (out)
            sd_wp          : in    std_logic := '-';
            sd_cdn         : in    std_logic := '-'; -- card detect not connected
            adc_csn        : out   std_logic;
            adc_mosi       : out   std_logic;
            adc_miso       : in    std_logic := '-';
            adc_sclk       : out   std_logic;
            audio_l        : out   std_logic_vector(4-1 downto 0);
            audio_r        : out   std_logic_vector(4-1 downto 0);
            audio_v        : out   std_logic_vector(4-1 downto 0);
            wifi_en        : out   std_logic := '1'; -- '0' disables ESP32
            wifi_rxd       : out   std_logic;
            wifi_txd       : in    std_logic := '-';
            wifi_gpio0     : out   std_logic := '1'; -- '0' requests ESP32 to upload "passthru" bitstream
            wifi_gpio5     : inout std_logic := '-';
            wifi_gpio16    : inout std_logic := '-';
            wifi_gpio17    : inout std_logic := '-';
            ant_433mhz     : out   std_logic;
            usb_fpga_dp    : inout std_logic := 'U';  
            usb_fpga_dn    : inout std_logic := 'U';
            usb_fpga_bd_dp : inout std_logic := 'U';
            usb_fpga_bd_dn : inout std_logic := 'U';
            usb_fpga_pu_dp : inout std_logic := 'U';
            usb_fpga_pu_dn : inout std_logic := 'U';
            sdram_clk      : inout std_logic;  
            sdram_cke      : out   std_logic;
            sdram_csn      : out   std_logic;
            sdram_wen      : out   std_logic;
            sdram_rasn     : out   std_logic;
            sdram_casn     : out   std_logic;
            sdram_a        : out   std_logic_vector(13-1 downto 0);
            sdram_ba       : out   std_logic_vector(2-1 downto 0);
            sdram_dqm      : inout std_logic_vector(2-1 downto 0) := (others => 'U');
            sdram_d        : inout std_logic_vector(16-1 downto 0) := (others => 'U');
            gpdi_d         : out   std_logic_vector(4-1 downto 0);
            gpdi_dn        : out   std_logic_vector(4-1 downto 0);
            gpdi_cec       : inout std_logic := '-';
            gpdi_sda       : inout std_logic := '-';
            gpdi_scl       : inout std_logic := '-';
            gp             : inout std_logic_vector(28-1 downto 0) := (others => 'Z');
            gn             : inout std_logic_vector(28-1 downto 0) := (others => 'Z');
            gp_i           : in    std_logic_vector(12 downto 9);
     user_programn : out std_logic := '1'; -- '0' loads next bitstream...
    Read more »

  • new tmds_encoder and dvi module

    Miguel Angel04/29/2023 at 03:17 0 comments

    tmds_encoder and dvi modules working on any DDR gear. 

  • Changing repository layout and editing some documentation

    Miguel Angel04/23/2023 at 06:54 0 comments

    app_graphics documentation improved.

  • DDR core

    Miguel Angel04/23/2023 at 06:52 0 comments

    DDR core exceeds or equals that of the manufacturers in Xilinx spartan 3, virtex 5, artix, Latticesemi ecp3, ecp5.

View all 7 project logs

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates