Giter Club home page Giter Club logo

covg_fpga's Introduction

DOI

Verilog and Python for a general purpose data acquisition system using an OpalKelly FPGA as the main controller. The Python is designed to be a general purpose approach to interface with multiple peripheral components that contain register maps.

Quick Start

  1. Clone the covg_fpga repository with github. This provides the required FPGA bitfile and test code.

  2. Install pyripherals with pip

pip install git+https://github.com/lucask07/pyripherals

To use an FPGA and pyripherals:

  1. Download FrontPanel from OpalKelly

  2. Download Registers.xlsx from the GitHub

  3. Create config.yaml with create_yaml and edit fields as needed

>>> from pyripherals.utils import create_yaml
>>> create_yaml()
YAML created at C:/Users/username/.pyripherals

See Installation Guide for more information.

Acknowledgements

If this work contributes to your research please cite:

I. Delgadillo Bonequi, A. Stroschein, and L. J. Koerner, “A field-programmable gate array (FPGA)-based data acquisition system for closed-loop experiments,” Review of Scientific Instruments, vol. 93, no. 11, p. 114712, Nov. 2022, doi: 10.1063/5.0121898.

A. Stroschein, I. D. Bonequi, and L. J. Koerner, “Pyripherals: A Python Package for Communicating with Peripheral Electronic Devices,” Journal of Open Source Software, vol. 7, no. 79, p. 4762, Nov. 2022, doi: 10.21105/joss.04762.

This work is partially supported by National Institutes of Health (NIH) R15 grant R15NS116907 to PI L. J. Koerner.

The FPGA code is dervied from many open-source contributions.

  • The I2C controller is from OpalKelly OpalKelly I2CController (MIT License).

  • The AD7961 controller is from Analog Devices and is free to use / redistribute as long as its used with Analog Devices parts (which must be the case since it does not work if connected to other parts). The Verilog is available within the EVAL-AD7960 evaluation kit software

  • The SPI Controller is from OpenCores.org and is authored by Simon Srot (GPL 2.1 or later license).

  • The wishbone master is written by Dan Gisselquist, Gisselquist Technology LLC. (LGPL, v3)

  • The DDR user interface (ddr_test.v) started with the OpalKelly DDR example provided in the FrontPanel example RAMTester and was significantly modified to support two ports.

The Python code relies on wonderful open source packages such as:

  • Matplotlib
  • numpy
  • pandas

OpalKelly Module Compatibility.

We have targeted and tested with the XEM7310-A75 module (Xilinx Artix-7). We have not tested but anticipate reasonable portability to other USB 3 OpalKelly modules including:

  • XEM7310MT
  • XEM7320
  • XEM7305
  • XEM7360

FPGA Block Diagram (Approximate)

Acknowledgments

Research reported in this repository was supported by the National Institute Of Neurological Disorders And Stroke of the National Institutes of Health under Award Number R15NS116907. The content is solely the responsibility of the authors and does not necessarily represent the official views of the National Institutes of Health.

covg_fpga's People

Contributors

lucask07 avatar ajstros avatar delg5279 avatar ianshogren avatar jhporter8 avatar abe-ust avatar corissau avatar

Stargazers

 avatar  avatar Thomas Wang avatar  avatar  avatar

Watchers

 avatar

covg_fpga's Issues

ADS8686 channel 'A', 'B' not synchronized

The ADS8686 channel 'A', 'B' are stored into the DDR at different 'cycle_cnts'. This was causing slight errors in impedance analyzer measurements until I shifted the channel 'A' results one cycle.

Instead in the FPGA code, we should store 'A', 'B' results at the same cycle count so that there is no need to synchronize in software. (Unfortunately, this will require edits to the function to read .h5 files data_to_names and will make old .h5 files incompatible with newer .h5 files).

Wb_SignalConverter: state register sensitivity list

A synchronous always block sensitivity list can have a clock or a clock and a reset. A third signal in the sensitivity list is not good practice.

    //state register
    always@(posedge rst or posedge clk or posedge startread/*int_o*/)begin

This issue is to remove posedge startread from the sensitivity list

Either, move startread out of the sensitivity list and into the logic of the state register always block
Or, move startread into the next state logic.

LVDS needs to be on clock pin?

A clock IOB / BUFGMUX clock component pair have been found
that are not placed at an optimal clock IOB / BUFGMUX site pair. The clock
IOB component <A1_DCO_P> is placed at site

Add MAC frontpanel setup to interfaces.py

To allow Python to import the ok module on MAC change the interfaces.py file to:

# TODO: make sure this path works for Windows, Mac, and Linux: https://docs.opalkelly.com/fpsdk/frontpanel-api/programming-languages/
if sys.platform == 'win32':
    sys.path.append(os.path.join(configs['frontpanel_path'], 'API/Python/3.7/x64')) # Add path to ok.py to PATH for import
    os.add_dll_directory(os.path.join(configs['frontpanel_path'], 'API/lib/x64'))   # Make DLL (okFrontPanel.dll) available
elif sys.platform == 'darwin':
    sys.path.append(os.path.join(configs['frontpanel_path'], 'API/Python3/')) # Add _ok.so to PATH for import

DAC80508_ADS8686_test.py executes open_rigol_supply fails during pytest collection

At line 43 of DAC80508_ADS8686_test.py an instrument is opened:

dc_pwr, dc_pwr2 = open_rigol_supply(setup=pwr_setup) # 7V and +/-16.5V, None

This fails during pytest collection on a Mac when not connected to the instrument. python3 -m pytest -m no_fpga

I explored the pytest flag of --continue-on-collection-errors yet this did not remove the error since a Fatal Python error occurs.

Would it be possible to move open_rigol_supply to a fixture/function so that it only happens if the test is run (rather than just collected?)

The terminal error message:

A00080338:python koer2434$ python3 -m pytest --continue-on-collection-errors -m no_fpga
============================================================= test session starts ==============================================================
platform darwin -- Python 3.9.7, pytest-7.1.2, pluggy-1.0.0
rootdir: /Users/koer2434/Documents/covg_fpga, configfile: pyproject.toml
plugins: anyio-3.5.0
collecting ... Fatal Python error: Aborted
Current thread 0x000000011602a600 (most recent call first):
File "/Users/koer2434/opt/anaconda3/lib/python3.9/site-packages/pyvisa/ctwrapper/functions.py", line 1871 in open_default_resource_manager
File "/Users/koer2434/opt/anaconda3/lib/python3.9/site-packages/pyvisa/highlevel.py", line 3024 in new
File "/Users/koer2434/opt/anaconda3/lib/python3.9/site-packages/instrbuilder/scpi.py", line 674 in open_visa
File "/Users/koer2434/opt/anaconda3/lib/python3.9/site-packages/instrbuilder/scpi.py", line 651 in init
File "/Users/koer2434/opt/anaconda3/lib/python3.9/site-packages/instrbuilder/scpi.py", line 975 in init_instrument
File "/Users/koer2434/opt/anaconda3/lib/python3.9/site-packages/instrbuilder/instrument_opening.py", line 273 in open_by_name
File "/Users/koer2434/Documents/covg_fpga/python/instruments/power_supply.py", line 10 in open_rigol_supply
File "/Users/koer2434/Documents/covg_fpga/python/tests/integration_tests/DAC80508_ADS8686_test.py", line 43 in
File "/Users/koer2434/opt/anaconda3/lib/python3.9/site-packages/_pytest/assertion/rewrite.py", line 168 in exec_module
File "", line 680 in _load_unlocked
File "", line 986 in _find_and_load_unlocked
File "", line 1007 in _find_and_load
File "", line 1030 in _gcd_import
File "/Users/koer2434/opt/anaconda3/lib/python3.9/importlib/init.py", line 127 in import_module
File "/Users/koer2434/opt/anaconda3/lib/python3.9/site-packages/_pytest/pathlib.py", line 533 in import_path

Wb_SignalConverter: avoid reg initializations

Lines 33 and 34 state:

reg startread = 1'b0;
reg readmarker = 1'b0;

This may work in simulation but is not necessarily synthesizable. In hardware (i.e. on the FPGA), if you desire a register to be initialized to a certain value a flip-flop with a reset is needed. However, in certain scenarios, a reset may not be needed if all the inputs that create this signal initialize to known values.

Action items for this issue:

  1. See if this synthesizes onto the FPGA
  2. Think through if it is necessary to initialize these regs
  3. If it is not, necessary remove the initialize
  4. If it is, consider how to add into a flip-flop with a reset

Determine FPGA bit-file version

There can be confusion when we don't know what version of Verilog code a bit file originated from.
I'd propose that we use the MD5 checksum, after skipping the header information that contains the date/time of the build, to create a unique ID for bit files.
See this Xilinx Answer

$ tail -c 4045674 fpga1.bit | md5sum

DAQ board set_dac_gain

daq.set_dac_gain(channel, 5) # 5V to see easier on oscilloscope
has an incorrect channel mapping. Channel 0 actually changes channel 1, and channel 1 changes channel 0. Need to correct the I/O expander nibble to channel mapping within the boards.py file.
Suspect this caused similar issues with the ISEL programming for the Howland current pump.

WbSignal_converter: create 1 clock cycle pulse

These two code blocks seem to be generating a pulse that is one clock cycle wide (startread) on the rising edge of int_o:

  always@(posedge clk /*or posedge int_o*/) begin
      if(int_o && !readmarker)begin
         startread <= 1'b1;
         readmarker <= 1'b1;
      end
      else if(!int_o)begin
          readmarker <= 1'b0;
      end
      /*else begin
         startread <= 1'b0; 
      end*/
  end
always@(negedge clk)begin
	if(startread)begin
		startread <= 1'b0;
	end
	else begin
		startread <= startread;
	end
end

A best practice "rule" relevant here is to not mix positive edge and negative edge clock triggers, particularly for flip-flops driving the same signal.

A better approach follows the answer from Dave Tweed in this StackExchange answer

So this issue is to change the creation of startread to use a 2-stage synchronizer.

MAC installation instructions

The _ok.so shared library needs to be able to find libokFrontPanel.dylib

The user should navigate to the FrontPanel API directory: e.g. frontpanel_5p26/API/Python3/ and check where _ok.so is searching for libokFrontPanel.dylib

In a terminal:

A00080338:Python3 koer2434$ otool -L _ok.so
_ok.so:
libokFrontPanel.dylib (compatibility version 0.0.0, current version 0.0.0)

This output indicates that the Python import of ok will fail since libok is one directory up.

Change using install_name_tool
In terminal:
install_name_tool -change libokFrontPanel.dylib /fullpath/to/libokFrontPanel/libokFrontPanel.dylib _ok.so

Alternatively, the path to libokFrontPanel.dylib could be included in the environmental variable DYLD_FALLBACK_LIBRARY_PATH as discussed at Is it OK to use DYLD_LIBRARY_PATH on Mac OS X? And, what's the dynamic library search algorithm with it?

ADS8686 sequencer position is unknown in DDR readings

The ADS8686 sequencer free runs at 1 MSPS. We need to implement a small module count of conversion starts in the FPGA that allows us to map each DDR reading to a specific ADS MUX channel within the sequencer sequence.
The counter should only be reset when the ADS8686 is also reset.

Plotting of DDR data streams is too memory intensive

DDR data streams are very long and normally have a repeated value for many many points. We should create a method to find the unique points in a DDR sequence and plot lines between these rather than all points.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.