Table of Contents |
---|
The common ATCA driver is an API that intermediates ATCACommon EPICS module and CPSW. It abstracts common ATCA registers and provides get and set functions to control them using CPSW. It also makes transparent all the peculiarities of CPSW.
The common ATCA package is responsible for the following:
The files in the package are as follows
The common ATCA package uses the common platform software package (establishes connections with hardware based on protocols and addresses described in YAML files). The API assumes that the CPSW YAML files were already read and parsed successfully. The API requires a path the denote where all the registers will reside.
...
YAML file | Stream/Register name | Description | |
---|---|---|---|
1 | AxiVersion.yaml | UpTimeCnt | Number of seconds since last reset |
2 | BuildStamp | Time stamp of the FPGA build | |
3 | FpgaVersion Version | FPGA firmware version | |
4 | GitHash | Git hash of firmware project | |
5 | AxiSysMonUltraScale.yaml | Temperature | ADC temperature values |
6 | AmcCarrierBsi.yaml | EthUpTime | Uptime of ethernet in seconds |
7 | JesdRx.yaml 2 instantiations | StatusValidCnt[0] | Shows stability of JESD lanes. Counts number of JESD re-syncronisationssynchronizations |
8 | StatusValidCnt[1] | ||
9 | StatusValidCnt[2] | ||
10 | StatusValidCnt[3] | ||
11 | StatusValidCnt[4] | ||
12 | StatusValidCnt[5] | ||
13 | DaqMuxV2.yaml 2 instantiations | TriggerCascMask | covered in DaqMux documentation |
14 | TriggerHwAutoRearm | ||
15 | DaqMode | ||
16 | PacketHeaderEn | ||
17 | FreezeHwMask | ||
18 | DecimationRateDiv | ||
19 | DataBufferSize | ||
20 | TrigCount | ||
21 | DbgInputValid | ||
22 | DbgLinkReady | ||
23 | InputMuxSel[0/1/2/3] | ||
24 | StreamPause[0/1/2/3] | ||
25 | StreamReady[0/1/2/3] | ||
26 | StreamOverflow[0/1/2/3] | ||
27 | StreamError[0/1/2/3] | ||
28 | InputDataValid[0/1/2/3] | ||
29 | StreamEnabled[0/1/2/3] | ||
30 | FrameCnt[0/1/2/3] | ||
31 | FormatSignWidth[0/1/2/3] | ||
32 | FormatDataWidth[0/1/2/3] | ||
33 | FormatSign[0/1/2/3] | ||
34 | DecimationAveraging[0/1/2/3] | ||
35 | Timestamp[0/1] | ||
36 | TriggerDaq | ||
37 | ArmHwTrigger | ||
38 | FreezeBuffers | ||
39 | ClearTrigStatus | ||
40 | AxiStreamDmaRingWrite.yaml 2 instantiations | Initialize | covered in waveform engine documentation |
41 | StartAddr[0/1/2/3] | ||
42 | EndAddr[0/1/2/3] | ||
43 | WrAddr[0/1/2/3] | ||
44 | Enabled[0/1/2/3] | ||
45 | Mode[0/1/2/3] | ||
46 | MsgDest[0/1/2/3] | ||
47 | FramesAfterTrigger[0/1/2/3] | ||
48 | Status[0/1/2/3] | ||
49 | AmcCarrierCore.yaml | OutputConfig[0/1/2/3] | Crossbar configuration. Four outputs choosing from four inputs. Output and input enumeration is as follows:
|
50 | 000TopLevel.yaml | Streams (Stream0 - Stream7) | Stream names to be initialized |
This class is responsible for DaqMux 0 and 1 configurations, JESD Top (AMC) 0 and 1, Waveform engine, Build information, and temperature information.
...
Gliffy Diagram | ||||||||
---|---|---|---|---|---|---|---|---|
|
The static function if the parent class ATCACommonFw allows the instantiation of API class. It seems to return an instantiation of the child class as follows:
...
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
atcaCommon = IATCACommonFw::create(p_atcaCommon); |
The stream can be created using the createStream method in the API. Streams can be instantiated separately by calling the CPSW stream creation function directly as follows
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
try { _stream[0] = IStream::create(p_root->findByName(stream0)); } catch (InvalidArgError &e) { // Don't print error if the stream name is empty, as the user didn't // want to create this channel anyway. } catch (CPSWError &e) { fprintf(stderr, "CPSW Error: %s, file: %s, line: %d\n", e.getInfo().c_str(), __FILE__, __LINE__); } |
YAML string mapping
This class is responsible for configuring the timing cross bar. The timing cross bar is nothing more than four multiplexers configuring four outputs. The four outputs and the four inputs are as follows:
...
The functions available are simply to instantiate a crossbar, and to configure and read current configuration.
The package does not throw any exceptions. Nonetheless, CPSW throws CPSWError errors and the package propagates these exceptions. In these contexts the package prints to stderr. Upper layers should catch exceptions of type CPSWError.
The ATCACommon module integrates the common ATCA API with EPICS, and therefore allowing the control of the different components in EPICS.
The ATCACommon module is responsible for the following:
The files in the package are as follows
The database files associated are as follows
Gliffy Diagram | ||||||
---|---|---|---|---|---|---|
|
...
The CrossbarControlDriver instantiates the commonATCA API classCrossbarControlYaml. It also provides 2 methods: report and control . It is not clear why this class was not implemented in the commonATCA API or even if it is necessary at all. The CrossbarControlAsynDriver class on the other hand inherits from AsynDriver, and calls the CrossbarControlDriver with the proper parameters.
Gliffy Diagram | ||||||
---|---|---|---|---|---|---|
|
The ATCAcommonAsynDriver instantiates the lower level commonATCA API class called ATCACommonFw. The Asyn driver is then given access to all the relevant registers in the hardware and exports them as PVs in EPICS.
Gliffy Diagram | ||||||||
---|---|---|---|---|---|---|---|---|
|
...
Gliffy Diagram | ||||||||
---|---|---|---|---|---|---|---|---|
|
The functionality of debugStream could be extended to call one's own callback along with the default. The API function provided for registering the callback is in the debugStreamInterface.h header file and is as follows
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
/** * @brief Register a callback when data arrives on a specific channel of stream * * @param portName : name of the asyn port generating the stream * @param stream_channel : Number of the channel to be parsed (1-4) * @param cb_func : callback function to register * @param cb_usr : private structure that will be passed to the callback * @return int : -1 if channel not found, else 0 */ int registerStreamCallback(const char *portName, const int stream_channel, STREAM_CALLBACK_FUNCTION cb_func, void *cb_usr); |
TBD
TBD
...
The callback function paramters have to be as follows
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
/**
* @brief Callback function format
*
* @param pBuf : buffer pointer
* @param size : size of buffer
* @param time : Time of event
* @param timeslot : timeslot information from the timing pattern modifier
* @param usr : user private object pointer
*/
void callback(void* pBuf, unsigned size, epicsTimeStamp time, int timeslot, void* usr) |
This file contains an IOC shell command that compares the installed firmware version and/or hash to a list of firmwares and hashes. The hash and version are already exported as PVs, but this is an extra diagnostic tool for comparision. Also, it does not seem to function correctly with multiple sets of YAML files. Needs debugging if deemed necessary, otherwise should be removed.
The IOC shell commands are as follows
Command | description | parameters |
---|---|---|
cpswDebugStreamDump | Dump stream contents on screen |
|
cpswDebugStreamAsynDriverConfigure | Initialize Asyn driver for one or more streams and their PVs |
|
cpswATCACommonAsynDriverConfigure | Initialize Asyn driver for connecting ATCA common registers to PVs |
|
cpswRelease | Returns the current CPSW version | No parameters |
crossbarControlAsynDriverConfigure | Initialize Asyn driver to configure crossbar using PVs |
|
crossbarControlDriverConfigure | Configures crossbar in case PCIe is used, otherwise, does nothing PCIe fixed configurations are
|
|
crossbarControlDriverReport | reports how the crossbar inputs are currrently configured | No parameters |
crossbarControl | Configure cross bar straight from IOC Shell |
|
atcaCheckFirmwareVersion | Compared current firmware version to input and exit IOC if requested (buggy) |
|
The DaqMux PVs are shown here.
Waveform engine PVs are shown here.
The remaining PVs are summarized as follows
Register index | PV name | Description |
---|---|---|
7-12 | $(DEVICE):JESD[1:0]_[7:0] | Counts number of JESD re-synchronizations for the corresponding JESD lanes |
1 | $(DEVICE):AMC_UPTIMECNT | Number of seconds since last reset |
2 | $(DEVICE):AMC_BUILDSTAMP | Time stamp of the FPGA build |
4 | $(DEVICE):AMC_GITHASH | Git hash of firmware project |
3 | $(DEVICE):AMC_FPGAVERSION | FPGA firmware version |
5 | $(DEVICE):AMC_FPGATEMP | ADC temperature values |
6 | $(DEVICE):AMC_ETHUPTIMECNT | Uptime of ethernet in seconds |
Software abstraction | $(DEVICE):JESDCNT_RESET | Reset references for JESD count in software |
Software abstraction | $(DEVICE):JESDCNT_MODE | Show count from the last time reset was done or the absolute count since the firmware booted |
Software abstraction | $(DEVICE):CPSW_RELEASE_TAG | CPSW release tag string |
49 | $(DEVICE):TCRB0:OUTPUTCONFIG | configure crossbar input for RTM_IN0. Possible inputs are
|
49 | $(DEVICE):TCRB1:OUTPUTCONFIG | configure crossbar input for FPGA. Possible inputs are
|
49 | $(DEVICE):TCRB2:OUTPUTCONFIG | configure crossbar input for BP. Possible inputs are
|
49 | $(DEVICE):TCRB3:OUTPUTCONFIG | configure crossbar input for RTM_IN1. Possible inputs are
|
In order to read your own (custom stream), following these instructions
This is a streamPoll method example
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
myStreamClass::myStreamClass(const char *portName, const char *named_root, const unsigned size, const bool header, const char *stream0, const char *stream1, const char *stream2, const char *stream3)
: DebugStreamAsynDriver(portName,
named_root,
size,
header,
stream0,
stream1,
stream2,
stream3)
{
createParam(p_myParamString, asynParamFloat64, &p_myParam);
}
void myStreamClass::streamPoll(const int ch) {
// First check if the user created the channel
if(! _stream[ch]) {
return;
}
try {
rdLen[ch] = _stream[ch]->read(buff[ch], size, CTimeout(2000000));
}
catch (IOError &e) {
// A timeout happened
timeoutCnt ++;
timeoutCnt_perStream[ch] ++;
}
catch (CPSWError &e) {
// Don't print, as we are inside a polling. Wait for the next try, as
// rdLen[ch] will be zero.
}
if(rdLen[ch] == 0 ) {
return;
}
epicsTimeStamp time;
rdCnt++; rdCnt_perStream[ch]++;
/* extract data in stream */
stream_with_header_t *p = (stream_with_header_t *) buff[ch];
time.nsec = p->packet.time.secPastEpoch;
time.secPastEpoch = p->packet.time.nsec; /* Set PVs from extracted data */
setTimeStamp(&time);
/* Set your PVs with extracted data and update them */
setDoubleParam(p_myParamString, p->myParam);
callParamCallbacks();
} |