FlxCard
Loading...
Searching...
No Matches
Introduction


This note defines an application program interface (API) for the use of the FLX PCIe I/O card in the ATLAS read-out system. The intention of the API is to satisfy the needs of simple test programs as well as the requirements of the FelixApplication.

Copyright


This is the header file for the FlxCard object

Author
Markus Joos, CERN Marku.nosp@m.s.Jo.nosp@m.os@ce.nosp@m.rn.c.nosp@m.h
Maintainance: Henk Boterenbrood, Nikhef boter.nosp@m.enbr.nosp@m.ood@n.nosp@m.ikhe.nosp@m.f.nl

Description of the API

This note defines an application program interface (API) for use with FLX PCIe cards.

The API can also be used for the Wupper release. Wupper is the OpenCore version of the PCIe DMA engine of the FLX firmware. See:

https://opencores.org/project/virtex7_pcie_dma

The main requirements that drove the design of this API as well as the underlying software were:

  • Simplicity
    • The functions shall be easy to understand
    • The functions shall only provide basic operations. Complex functions can be built on the basis of this API in higher level code.
  • Safety
    • The functions shall perform plausibility checks on user input and provide a detailed error reporting mechanism
  • Speed
    • The implementation shall keep an eye on performance
  • Portability
    • The implementation shall not use constructs that complicate the porting of the software to other platforms
  • Flexibility
    • The API shall allow for the addition of features as required by the evolution of the FELIX project

Implementation Issues

The following issues are related to the implementation of the API:

  1. Layered implementation
    • The source code that implements this API will be kept in one .cpp and one .h file. The layer below this API are the "flx" and "cmem_rcc" device drivers as well as the Linux OS. The functions of the API may also use selected low level packages from the ATLAS TDAQ project.
  2. Multi-processing and multi-threading
    • The implementation of the API shall allow for several application programs and multiple threads within the same application program to use all functions of the API concurrently. It is up to the application programmers to add synchronisation as and where required.
  3. Language binding
    • C++ was chosen for the language binding of the API.
  4. Binary
    • The source code will be compiled into a single, shared library object named "libFlxCard.so". The library will exist in the form of a dynamically loadable object (shared library): libFlxCard.so. Applications should not use static linking
  5. Buffer allocation
    • The API (i.e. libFlxCard.so) will not provide methods for buffer allocation. Application programmers are requested to use the cmem_rcc library directly in their code. If needed a wrapper for libcmem_rcc.so as a separate object (e.g. FelixContiguousBuffer) and library (e.g. lib FelixContiguousBuffer.so) can be added at a later time.
  6. cmake will be used in order to build the library from the source code

Building the Software

Links to documentation on how to install additional software and build FlxCard can be found in:

https://gitlab.cern.ch/atlas-tdaq-felix/flxcard/blob/master/README.md

Support for debugging

The source code of the library (FlxCard.cpp) uses the DEBUG_TEXT macro

Example:

DEBUG_TEXT(DFDB_FELIX, 15, "card number = " << cardno);

If the code gets compiled without –DDEBUG_LEVEL=1 the macros will disappear (i.e. will not impact performance) If the macros are enabled the generation of the debug text can be controlled via two variables:

#include "DFDebug/DFDebug.h"
  DF::GlobalDebugSettings::setup(dblevel, dbpackage);

dbpackage defines the package for which text is output. In order to activate line in the example above one has to set dbpackage=DFDB_FELIX dblevel defines the level of verbosity. Only messages that have a level equal or smaller than dblevel will be printed.

Error reporting

All errors will be reported through exceptions. For that purpose an exception class, FlxException.cpp, has been added. The FlxException object inherits from std::runtime_error and provides some additional data members such as an error code.

At the level of the FlxCard source code a macro is used for throwing exceptions:

#define THROW_FLX_EXCEPTION(errorCode, message) throw FlxException(FlxException::errorCode, message);

Organization of this Document

Section 'Application Program Interface' contains the definition of the API. For each function the section gives a detailed description of all input and output parameters, a description of the functionality and the return codes. The section contains sub-section for the type definitions used by the API as well as functions concerning the return codes.

Application Program Interface

The methods of the API are grouped by function into several categories.

For the implementation of the API it will be necessary to develop service functions for internal use. They are not described in this API document.

The remarks below apply to all functions defined in the API:

  • If not stated otherwise, all functions of this API are non-blocking, i.e. they return immediately indicating an error code if necessary. Wherever functions are blocking, i.e. waiting on external events, e.g. end of block transfer, this is stated explicitly.
  • The implementation of the API is in the following called the “FLX library”.

Driver calls

In order to optimize user code for performance and to spot potential race conditions between processes and threads it is important to know details about the interface between this library and the device driver underneath. The methods listed in the table below make a call to the driver (typically via an ioctl() function or to mmap()).

Method Type of driver access
card_open() open() and ioctl(SETCARD)
card_close() close()
dma_max_tlp_bytes() ioctl(GET_TLP)
irq_enable() ioctl(UNMASK_IRQ)
irq_disable() ioctl(MASK_IRQ)
irq_wait() ioctl(WAIT_IRQ)
irq_cancel() ioctl(CANCEL_IRQ_WAIT)
irq_clear() ioctl(CLEAR_IRQ)
irq_reset_conters() ioctl(RESET_IRQ_COUNTERS)
map_memory_bar() mmap()
number_of_cards() ioctl(GETCARDS)

Background information about I2C transfers

This section provides some information about how I2C transfers work in the FELIX system. At the level of the software tools several of the applications in the flxcard package perform I2C transfers. The program flx-i2c allows for the execution of single transfers. Program flx-init provides functions that execute lists of I2C transactions in order to e.g. set the clock frequency of the TTC interface.

Description of flx-i2c:

Command “flx-i2c list” produces a list of I2C devices. Below is the output for an FLX-712. FLX-709, FLX-710, FLX-711 and FLX-128 cards are of course also supported.

> flx-i2c list
Card model: FLX-712
Switch I2C address: 0x70
=> List of I2C devices:
Device Model Switch port(s) Address
======================================================================
ADN2814 ADN2814 1:-:- 0x40
SIS53154 SI53154 1:-:- 0x6b
LTC2991_1 LTC2991 1:-:- 0x48
LTC2991_2 LTC2991 1:-:- 0x49
SI5345 SI5345 2:-:- 0x68
TCA6408A TCA6408A 2:-:- 0x20
MINIPOD-TX1 AFBR-814PxyZ 3:-:- 0x2c
MINIPOD-TX2 AFBR-814PxyZ 3:-:- 0x2d
MINIPOD-TX3 AFBR-814PxyZ 3:-:- 0x2e
MINIPOD-TX4 AFBR-814PxyZ 3:-:- 0x2f
MINIPOD-RX1 AFBR-824PxyZ 3:-:- 0x30
MINIPOD-RX2 AFBR-824PxyZ 3:-:- 0x31
MINIPOD-RX3 AFBR-824PxyZ 3:-:- 0x32
MINIPOD-RX4 AFBR-824PxyZ 3:-:- 0x33

The function of the FELIX can be implemented on several types of PCI cards. They are known as FLX-709, FLX-710, FLX-711, FLX-712 and FLX-128. Each type of PCI card has its own I2C tree. This tree connects to the FPGA. Therefore all I2C commands originate in the firmware and the used programs I2C transactions by reading from and writing to registers of the firmware (via PCIe).

The switch I2C addresses are the address of the single I2C switches on the FELIX cards. All I2C devices (see below) connect to these switches. Hence every I2C access from the firmware is first routed to a switch and from there reaches the endpoint.

On a FLX with more than one switch, the first one is connected to the firmware (primary switch) and the second connects to one of the ports of the first; therefore, it is a secondary switch that cannot be reached directly from the firmware.

The output of “flx-i2c list” is what we call the “I2C model”. At the level of the software it is defined as an array of structures of type “i2c_device_t” in FlxCard.cpp.

Below is a description of the columns of the table above:

Column Description
Device This is the name of a discrete chip with a I2C interface
Model This is the actual part number of the device
Switch port An I2C switch has 8 ports. Each port has its own range of 128 device addresses. Therefore up to 128 I2C devices could be connected to each port in principle. The first number is the switch port (0..7). The number after the “:” characters is the secondary and tertiary switch number in case of cascaded switches (present on certain hardware platforms), or '-' if that number does not apply. Therefore e.g. “7:-:-” refers to a port that connects directly to I2C endpoint devices while “4:3:-” means that two switches are cascaded. The first number (“4”) is the port of the first switch and the second number (“3”) refers to the port of the second switch.
Address This is a 7-bit address value that selects the I2C endpoint device. The addresses of the endpoints are hardwired in the hardware design.

The applications internally use functions of the flxcard API: i2c_devices_read(), i2c_devices_write(), i2c_read_byte() and i2c_write_byte(). See the appropriate section in another chapter for the details of these methods.