Blog from April, 2011

Today, Zen presented a talk on asynportdriver. During the discussion, we talked about aai, aao and waveform and Steph suggested a codeathon task to

combine them all into waveform and have a flag to define your own bptr. I mentioned that this can be done in waveform as is, by freeing bptr.

Here is the init routine that does that (in orange)

/* $Id: devWaveformLlrf.c,v 1.20 2009/06/05 00:43:09 dayle Exp $ */

/*=============================================================================
 
  Name: devWaveformLlrf.c

  Abs:  Device support for saving raw digitizer data into a waveform
        (4 channels into a single, row-major array).

  Auth: 10-nov-2006, Till Straumann (TSS)
  Rev:  2008 Dayle Kotturi: adapt read_waveform contents to LLRF app

-----------------------------------------------------------------------------*/

#if 0
#include "copyright_SLAC.h"    /* SLAC copyright comments */
#endif
 
/*-----------------------------------------------------------------------------
 
  Mod:  (see CVS log)

 
=============================================================================*/

...

static long
init_record(void *record_p)
{
waveformRecord      *waveform_ps = record_p;
DevWfRawSigDpvt_tps    dpvt_ps;

    /* Check DB configuration */

    if ( waveform_ps->ftvl != menuFtypeSHORT )

Unknown macro: {        epicsPrintf                (DEVSUPNAM"}

    epicsPrintf(DEVSUPNAM": FTVL is SHORT\n");

    /* Set NELM to what the driver is configured for */
    free(waveform_ps->bptr);

        waveform_ps->nelm = 4*drvPadUdpCommGetNsamples(/dpvt_ps->station_type/);
    epicsPrintf(DEVSUPNAM": NELM is %d\n", (int) waveform_ps->nelm);

    if ( !(waveform_ps->bptr = calloc(waveform_ps->nelm, sizeof(short))) )

Unknown macro: {        /* If there's no memory we are unlikely to be able to print something */        goto egress;    }

    if ( VME_IO != waveform_ps->inp.type )

Unknown macro: {        epicsPrintf(DEVSUPNAM"}

    epicsPrintf(DEVSUPNAM": INP is VME_IO\n");

    if ( !(dpvt_ps = calloc(1, sizeof(*dpvt_ps))) )

Unknown macro: {        epicsPrintf(DEVSUPNAM"}

    waveform_ps->dpvt = dpvt_ps;

    if ( drvPadUdpCommDpvtInit(&dpvt_ps->drvPadUdpCommPart, waveform_ps->inp.value.vmeio.card) )
        goto egress;
    epicsPrintf(DEVSUPNAM": DPVT initialized\n");

        dpvt_ps->station_type = waveform_ps->inp.value.vmeio.card;
        #ifdef DEBUG_PRINT
        DEBUGPRINT(DP_INFO, devWaveformLlrfFlag,
          ("init_waveform: Record %s setting station to card #%d\n",
          waveform_ps->name, dpvt_ps->station_type));
        #endif

    return 0;

egress:
    waveform_ps->pact = 1;
    return -1;
}

Desirable HW-FW Features

SW-Developer's Dream

Has happened to all of us. Our best bud Fritz has just finished a fancy board and drops it off on our desk. "Can you make it work? You know, write a driver and some software?". And, yes: "Can you get it done by tomorrow?". If he was nice then there is a manual, otherwise the meeting minutes from 8 months ago will have to do. Then, while designing this driver we come across some odd features of that board. We wonder what was going on in Fritzes head - why would he make certain things work in a way that makes our life more difficult? There has probably never been proper communication and some basic things we just assume to work in a particular way so we never requested specific semantics explicitly.

Thus the idea - thanks to John D. - to create this blog where we can assemble a "wish-list" of basic features we believe are important to us. Hopefully it starts a dialogue/interface between HW and SW designers...

So let's kick-off with a few things that come to my mind

  • A detailed manual certainly helps.
  • Firmware version number should be available to be read from a register so that SW can figure out the FW-version at run-time. The documentation should refer to these same version numbers and document changes between versions.
  • It is desirable to use modern, dynamic configuration methods (for base-adresses, interrupt vectors etc.) as defined by PCI, VME64x etc. rather than "jumpers". If jumpers cannot be avoided them make their current setting available to SW via a register.
  • When there are moderate to large amounts of data to be transferred (especially over VME) then try to implement efficient transfer modes (BLT, wide datapaths, new technologies like 2eVME etc).
  • Commonly, there are multiple status bits in registers that are set by HW and cleared by SW. Occasionally, I have seen "clear-on-read" semantics, i.e., the bits clear automatically when SW reads the status register. This can be a real pain since it may be that different SW modules deal with different bits, hence it is very desirable that individual bits can be cleared under SW control so that a particular SW module may selectively clear the bits it is "responsible" for. Commercial HW commonly provides "clear-on-write-one" or "clear-on-write-zero" semantics. This means that a bit (which can only be set by HW, not SW) is cleared when SW writes a one (or zero) but left alone when a zero (or one, respectively) is written.
  • If a particular state of the HW is spread over multiple registers then provide a way for SW to obtain a coherent reading. E.g., by latching multiple registers when the "lowest" one is read.
  • Prefer level-sensitive interrupts to edge-sensitive ones. It is much easier to ensure that no interrupts are lost with level-sensitive interrupts.
  • Provide interrupt status and mask registers. Status should be asserted even while interrupts are masked (and the status bits should use e.g., "clear-on-write-one", see above). This facilitates testing and debugging.
  • Most OSes and thus driver software assumes that a VME interrupt vector is assigned by the OS and can be programmed on the board. Hence, HW should provide a register where the vector can be programmed and it should provide this vector during an VME IACK cycle.
  • Provide a method for SW to completely reset a board to initial, power-up state.
  • Reset should put the board in a useful, default state.
  • Manual should specify that currently unused or "reserved" bits must always be written e.g., with zeroes by SW. This helps backwards-compatibility.