Tests on SCU
Address of Wishbone Devices
NEVER USE HARD CODED ADDRESSES OF WISHBONE DEVICES
Many examples on this wiki page make use of hard coded address for Wishbone devices. This is extremely bad style and almost like hard coding of pointer values in C source code. A typical situation is shown below
[user@scul017f /]# eb-ls dev/wbm0
BusPath VendorID Product BaseAddress(Hex) Description
1 0000000000000651:eef0b198 0 WB4-Bridge-GSI
1.1 000000000000ce42:66cfeb52 0 WB4-BlockRAM
1.2 0000000000000651:eef0b198 20000 WB4-Bridge-GSI
1.2.1 000000000000ce42:ab28633a 20000 WR-Mini-NIC
1.2.2 000000000000ce42:650c2d4f 20100 WR-Endpoint
1.2.3 000000000000ce42:65158dc0 20200 WR-Soft-PLL
1.2.4 000000000000ce42:de0d8ced 20300 WR-PPS-Generator
...
Another SCU
[user@scul022 /]# eb-ls dev/wbm0
BusPath VendorID Product BaseAddress(Hex) Description
1 0000000000000651:eef0b198 0 WB4-Bridge-GSI
1.1 000000000000ce42:66cfeb52 0 WB4-BlockRAM
1.2 0000000000000651:eef0b198 40000 WB4-Bridge-GSI
1.2.1 000000000000ce42:ab28633a 40000 WR-Mini-NIC
1.2.2 000000000000ce42:650c2d4f 40100 WR-Endpoint
1.2.3 000000000000ce42:65158dc0 40200 WR-Soft-PLL
1.2.4 000000000000ce42:de0d8ced 40300 WR-PPS-Generator
...
Half a year later
[user@scul022 /]# eb-ls dev/wbm0
BusPath VendorID Product BaseAddress(Hex) Description
1 000000000000ce42:66cfeb52 0 WB4-BlockRAM
2 0000000000000651:eef0b198 80000 WB4-Bridge-GSI
2.1 000000000000ce42:66cfeb52 80000 WB4-BlockRAM
2.2 0000000000000651:eef0b198 a0000 WB4-Bridge-GSI
2.2.1 000000000000ce42:ab28633a a0000 WR-Mini-NIC
2.2.2 000000000000ce42:650c2d4f a0100 WR-Endpoint
2.2.3 000000000000ce42:65158dc0 a0200 WR-Soft-PLL
2.2.4 000000000000ce42:de0d8ced a0300 WR-PPS-Generator
...
As can be seen, the base addresses of Wishbone devices are not fixed, but depend of the layout of the wishbone bus.
However, what is not subject to change are the VendorID and ProductID. Hence, base addresses should be obtained programmatically. This can be done by using the routine eb_sdb_find_by_identity(..) of the Etherbone library. See
https://www-acc.gsi.de/svn/bel/timing/trunk/development/eb_demo/eb_native_demo.c for an example. VendorID and ProductID as well as register layouts of some Wishbone devices can be found here
https://www-acc.gsi.de/svn/bel/timing/trunk/development/wb_devices/.
For making Etherbone available on a SCU, please have a look
here (look for "Etherbone on the SCU").
Version of a Wishbone Devices
CHECK VERSION OF WISHBONE DEVICES
Next to it's base address, the application software must also check if the version of a Wishbone device (and thus the register layout) is correct.
- Major Version: Whenever the interface is changed, the major version is changed. As an example, if the register layout of a Wishbone device is changed, the major version is changed too. An application must check, if that actual major version of the Wishbone device equals the one against which the application has been developed.
- Minor Version: Whenever features are just added, the minor version is changed. An application must query the minor version of a Wishbone device and check if it's minor version is equal or older than the one used during the development of the application.
- On a SCU, versions of Wishbone devices can be checked by using
eb-ls
in verbose mode, example [user@scul022 /]# eb-ls -v dev/wbm0
Example for the Wishbone Device WR-Endpoint
#include <wr_endpoint.h>
...
eb_status_t status;
eb_device_t device;
struct sdb_device sdbDevice;
eb_address_t wrEndpoint;
int nDevices;
...
nDevices = 1;
if ((status = eb_sdb_find_by_identity(device, WR_ENDPOINT_VENDOR, WR_ENDPOINT_PRODUCT, &sdbDevice, &nDevices)) != EB_OK)
die("EP eb_sdb_find_by_identity", EB_FAIL);
/* check if a unique Wishbone device exists */
if (nDevices != 1)
die("expect exactly one endpoint", EB_FAIL);
/* check version of Wishbone device */
if (WR_ENDPOINT_VMAJOR != sdbDevice.abi_ver_major)
die("Endpoint major version conflicting - interface changed:", EB_FAIL);
if (WR_ENDPOINT_VMINOR > sdbDevice.abi_ver_minor)
die("Endpoint minor version too old - required features might be missing:", EB_FAIL);
/* record the address of the device */
wrEndpoint = sdbDevice.sdb_component.addr_first;
Things to Test
- TODO
- Test of all available Timing-Receiver-Methods (etherbone) (Will be provided as soon as we havea WR-Switch connected to the SCU)
- get current time
- configure interrupt
- receive interrupt
- Test of the Function-Generator-FPGA-Device (Not yet available for etherbone)
- Test automatic check/load of FPGA-Software (TOBE implemented?)
- ACU: Ludwig Hechler will do ACU tests as soon as an ACU is available
- Write set value, read actual value, read status. (LH, ok)
- More than one device per ACU. Needs defined ACU register model!
- Generate ramps with ACU function generator. Needs oscilloscope or logic analyzer to check output.
- Connect RT-actions with external events (triggers).
- Program FTRN and get timing event interrupts. Needs an FTRN and (some sort of) a timing.
- A device is triggered by an external trigger. An RT-action must check if there was a triggeran if it was in time.
- Detect an overrun.
- Write a program (that somehow acts like a FESA server action and) that loads a binary to theLM32 soft CPU and starts it.
- Investigate potentially necessary mutexed slave (ACU) accesses between the SCU CPU and theLM32 soft CPU.
- Investigate if and how interrupt service routines can be connected with external eventsfrom trigger inputs and from an FTRN.
- A lm32-gcc is necessary on the asl7xx cluster - more a C than a C++ compiler, right?.
- DONE
- Read/Write on FPGA devices via C++ (etherbone)
- Read/Write on InterfaceCard (etherbone)
Login for SCUs (in the tee-chamber)
- Just ask Alex, Stefan Rauch or Wesley for login info
- scul002: with 2 LED slave boards (top)
- scul007: removed due to HW problems (middle)
- scul020: with ACU (bottom)
Useful Console Commands
- lsmod - to get all modules of this linux-kernel
- check if "wishbone"-modul is loaded
- eb-ls - to list all etherbone-devices on a port (use -h for help)
- eb-read - to read out data from an etherbone-device
- E.g. #eb-read dev/wbm0 0x100400/4
- reboot
Launch lm32 Software
-
Only 1 program can run on the FPGA !
- load a new program
- eb-write dev/wbm0/4 0x8 -- puts lm32 into RESET
- eb-put dev/wbm0 [MyProgram.bin] - loads program
- eb-write dev/wbm0/4 0x0 -- starts lm32 (removes RESET)
Etherbone Source code
- Can be found here:
- Use "git clone git://ohwr.org/hdl-core-lib/etherbone-core.git" to checkout
- On blade-system, just go to the api-folder and compile by using make
- Dont forget to add -m32 for compiler & linker if you want to compile for the SCU (An already modified Makefile is attached)
- Ask Wesley for more details
Simple C++ etherbone client
- What I did until now, using the C++ API can be found here:
- https://www-acc.gsi.de/viewvc/view/fesa/framework/branches/SCU-Test/
- To compile the client on the blades & run the client on the SCU, do the following steps:
- compile the etherbone-core sources for 32bit
- compile & link the client for 32bit (check etherbone-core pathes in makefile)
- copy binary to SCU and run it
SCU-Lemos (Digital In-/Output)
The SCU offers 2 Digital In-/Output Lemo-Connectors, which can be accessed from the FESA Class using the Etherbone bus. In order to access them you need to consider following Points:
- The address of the Lemos is listed as GSI_GPIO_32 and is currently mapped to 0x800000
- In order to read or write data, Lemos must be switched to In- or Output mode accordingly
- To set the mode a required value must be written to the register 0x2. The value is interpreted bitwise (1 - IN, 0 - OUT), e.g. 0x3 - sets both connectors to input, 0x1 only first connector is set to input. Default value is 0x0 (both are set to output).
- Steps to read the value:
- Open etherbone socket
- Write to the address 0x800004 the value 0x3
- Read the value from the address 0x800000
- Close etherbone socket
SCU-Display
Simple-Display
Consider using the
simple display tool, provided by the timing group. The tool not only supports the OLED display of the SCU but also the LCD display on other timing receivers in a transparent way. Example
#include "disp.h"
...
eb_device_t device;
...
init_disp(device);
disp_put_s(device, "hello world");
...
Another possibility, see also here
Some SCUs are supplied with display, which for example can be used to write logging messages. The display may be accessed via etherbone bus.
- Current display base address is 0x900000 and it is descripted as OLED_Display
- Display has 3 (4) operating modes:
- 00 : idle
- 01 : UART - written ASCII code is put directly on the screen
- 02 : Char - written ASCII code is put on supplied location
- 03 : Raw - read/write to display memory
- The mode can be set using the base address, i.e. 0x900000 (write the appropriate value to it)
- To write something on the display following addresses can be used:
- 0x00004 : Write resets FSMs and display controller
- 0x10000 : UART Mode - Written ASCII code is put directly to the screen
- 0x20000 : Char Mode - Written ASCII code is put on supplied location
- Address bits(8-6) Char location row
- Address bits(5-2) Char location column
- 0x30000 : Raw Mode - Read/Write to display memory
- Organization is column based, 8px per column
- Address Bits (12-2) Disp RAM address
- ASCII code 0x0c (Form Feed) clears the display in mode 1 and 2
ADDAC - Card
The ADDAC - Card (with it IO extension) is providing 3 types of functionality:
- Reading and converting the analog voltage values (ADC)
- Output of a supplied voltage level (DAC)
- Reading (or writing) digital input values of the extention cards (0 - no power, 1 - 5+Volt)
The Communication with the Card is done via the SCU-Bus, which is accessed via etherbone. The card provides following addresses for data exchage:
- DAC1 : 0x200 (+1 for setting the value)
- DAC2 : 0x210 (+1 for setting the value)
- IO : 0x220
- ADCn : 0x230 + n
The base address of the ADC (ADC0) can be used to configure the ADC. The configuration is done via single byte value, where bits have following meanings:
- 0 : reset
- 1 : active
- 2..1 : 00-> paralell, 01->seriell
- 3 : range, 1 - (-10/+10 V, default), 0 - (-5/+5 V)
- 4 : n.e.
- 7..5 : oversampling mode, 000 - no OS, 110 ratio 64
- 8 : diff input 3..8
Etherbone Adapter
TODO: The internal API for the Etherbone Adapter has been changed a bit, so the examples below will not work and need an update
Etherbone Adapter is a small API to ease the access to etherbone bus from the FESA classes. The API is basicly an Object-Oriented wrapper over the "standard" etherbone framework. It also contains classes with some basic utility functions and an
DisplayAdapter to write messages to the display.
The API can be found here (SVN):
https://www-acc.gsi.de/svn/fesa/device/driver/EtherboneAdapter. Additionaly a tar.gz is attached to this section
Some examples how to use it whithin a fesa class:
Read example (read from ADDAC card):
std::string etherboneDevicePort = "dev/wbm0"; // device port
uint32_t baseAddress = 0x400000; // etherbone address to access
uint32_t registerAddress = 0x231; // address of particular device register (e.g. 0x230 for ADDAC cards ADC1)
int slaveNumber = 5; // Slave number of the card (needed only for SCU-Bus cards)
// Calculates the actual address of the device (baseAddress + 2^15 * slaveNR + 2 * registerAddress)
uint32_t readAddress = etherbone::EtherboneHelper::calculateAddress(baseAddress, slaveNumber, registerAddress);
// Get the adapter
etherbone::EtherboneAdapter myAdapter(etherboneDevicePort, readAddress);
myAdapter.open(); // open connection
uintptr_t someRawValue1 = myAdapter.readInt(); // read value from readAddress
uintptr_t someRawValue2 = myAdapter.readInt(0x2); // read value with an offset of 0x2: readAddress + offset (corresponds to ADC2 in this case)
myAdapter.close(); // close connection
Write example:
//Some address initializaion like in the example above
...
// get the adapter
etherbone::EtherboneAdapter myAdapter(etherboneDevicePort, writeAddress)
myAdapter.open(); // open connection
myAdapter.writeInt(data); // write data to the base writeAddress
myAdapter.writeInt(data, offset); // write data with an offset writeAddress+offset
myAdapter.close(); // close connection
Display usage example:
// Some message
std::stringstream;
message << "Read value equals: ";
message << someValue;
etherbone::DisplayAdapter display(etherboneDevicePort); // get the display adapter
display.init(); // init the adapter
display.reset(); // clear the content of the display
display.print(message.str()); // print a message on the display
display.close(); // close connection
To use the API with an FESA class the Makefile.specific files of Class and
DeployUnit Projects need to be modified:
EB_HOME = /home/bel/rapp/lnx/git/etherbone-core/api
EB_INCL = -I$(EB_HOME)
EB_LIBS = -L$(EB_HOME) -letherbone
EB_ACC_HOME = /common/home/bel/rapp/lnx/workspace/EtherboneAdapter
EB_ACC_INCL = -I$(EB_ACC_HOME)
EB_ACC_LIBS = -L$(EB_ACC_HOME) -libetherbone-adapter
# for DeployUnit
#EB_ACC_STATIC_LIB = $(EB_ACC_HOME)/etherbone-adapter.a
COMPILER_FLAGS += $(EB_ACC_INCL) $(EB_INCL)
LINKER_FLAGS += $(EB_ACC_LIBS) $(EB_LIBS)
# for DeployUnit
# LINKER_FLAGS += $(EB_ACC_STATIC_LIB) $(EB_LIBS)
Misc
- GSI_GPIO_32 is one of the devices, which makes the SCU blinking
- Dont touch GSI_CFI_FLASH_32
- The LED-slaves use a big-endian, so you have to use EB_BIG_ENDIAN when sending data