Hello...

As I have near finished driver for EPP boards I have one problem. As computer is common staretd with CNC machine off the EPP board respond to al IO with timeout. EPP timeout is aprox 10uSec. So if I wan't to write 5 bytes that can least over 50uSec. And in that case the computer freeze. The solution seems to be to check EPP timeout after every IO. That's works but make big overhead. On my EPP board (sem's to be slowest one) the fastest cycle is 2uS long. The timeout is on aprox 11uS. But the read from status port (to check timeout) least 1.5uS. So if I get that approach then I have (for 3/3 byte IO)
6 x 2.0uS   12uS        for real IO
6 x 1.5uS    9uS        overhead to check Timeout
total       21uS        and system got little slower already

Then I realize that checking how long in/out can be faster.
So if write_board routine take more than predetermined time to execute then execution shall be aborted and checked what's realy wrong.

maybe the best way is to check if out/inp routine take more than 5uS. If is more then probably is something wrong.

in write_board there is argument PERIOD. I can't find what is this. Time ?!?

I have only RDTSC instruction in mind but afraid to use as can be dissabled (privileged)

Can someone help??



And here is working (but unfinished) driver hal_eppport.c


/********************************************************************
 Description:  hal_eppport.c
               This file, 'hal_eppport.c', is a HAL component that
               provides a driver for generic EPP port.
               The drive scheme is simple to use and simple to extend.
               Hardvare attached to EPP port should assume all
               addres access as acces to byte [0] of board and all
               folowed data acces as access to [next] byte.
               Example board with 24 outputs and 24 inputs are in
               http:// (fixme)

 Author: Slavko Kocjancic
 License: GPL

 Copyright (c) 2010 All rights reserved.

    The configuration is determined by a config string passed to
    insmod when loading the module.  The format consists of a base
    address, followed by a parameter I and parameter O telling how many
    bytes are in IO space. The parameter is single digit number ranging
    from 1 to 9. Whitespace betwen I/O and number are not alowed.

    example:    insmod eppport cfg="0x278 I2 O3"

    The example above is for one card, with its base address
    set to hex 278, with 3 byte output (24 bits) and with 2 byte
    input (16) bits. 

    The driver creates HAL pins and parameters for each port pin
    as follows:
    Each physical output has a correspinding HAL pin, named
    'eppport.<boardnum>.out-<pinnum>', and a HAL parameter
    'eppport.<boardnum>.out-<pinnum>-invert'.
    Each physical input has two corresponding HAL pins, named
    'eppport.<boardnum>.in-<pinnum>' and
    'eppport.<boardnum>.in-<pinnum>-not'.

    <boardnum> is the board number, starting from zero.
    <pinnum> is the pin number, formated as two digit number. 1'st
    number is byte number 0 to maxbyte-1 and 2'nd number is bit number
    from that byte. (ranging from 0 to 7). 

    The driver exports two HAL functions for each board,
    'eppport.<boardnum>.read' and 'eppport.<boardnum>.write'.

*/

/** This program is free software; you can redistribute it and/or
    modify it under the terms of version 2 of the GNU General
    Public License as published by the Free Software Foundation.
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111 USA

    THE AUTHORS OF THIS LIBRARY ACCEPT ABSOLUTELY NO LIABILITY FOR
    ANY HARM OR LOSS RESULTING FROM ITS USE.  IT IS _EXTREMELY_ UNWISE
    TO RELY ON SOFTWARE ALONE FOR SAFETY.  Any machinery capable of
    harming persons must have provisions for completely removing power
    from all motors, etc, before persons enter any danger area.  All
    machinery must be designed to comply with local and national safety
    codes, and the authors of this software can not, and do not, take
    any responsibility for such compliance.

    This code was written as part of the EMC HAL project.  For more
    information, go to www.linuxcnc.org.
*/

#include "rtapi_ctype.h"        /* isspace() */
#include "rtapi.h"              /* RTAPI realtime OS API */
#include "rtapi_app.h"          /* RTAPI realtime module decls */
#include "hal.h"                /* HAL public API decls */

/* If FASTIO is defined, uses outb() and inb() from <asm.io>,
   instead of rtapi_outb() and rtapi_inb() - the <asm.io> ones
   are inlined, and save a microsecond or two (on my 233MHz box)
*/
#define FASTIO

#ifdef FASTIO
#define rtapi_inb inb
#define rtapi_outb outb
#include <asm/io.h>
#endif


/* module information */
MODULE_AUTHOR("Slavko Kocjancic");
MODULE_DESCRIPTION("EPP port Driver for HAL");
MODULE_LICENSE("GPL");
static char *cfg = "";  /* config string, default no boards */
RTAPI_MP_STRING(cfg, "config string");
/***********************************************************************
*                STRUCTURES AND GLOBAL VARIABLES                       *
************************************************************************/

/* this structure contains the runtime data needed by the
   driver for a single board
*/

typedef struct {
    hal_bit_t *data;            /* basic pin for input or output */
    union {
        hal_bit_t *not;         /* pin for inverted data (input only) */
        hal_bit_t invert;       /* param for inversion (output only) */
        } io;
} io_pin_t;


typedef struct {
    unsigned short base_addr;   /* base I/O address (0x220, etc.) */
    unsigned char port_outputs;     /* number of output bytes */
    unsigned char port_inputs;      /* number of input bytes */
    unsigned char port_timeout;         /* latch for timeout flag for port */
    io_pin_t port_Out[72];
    io_pin_t port_Inp[72];
} epp_board_t;

/* pointer to array of epp_board_t structs in shared memory, 1 per board */
static epp_board_t *board_array;

/* other globals */
static int comp_id;             /* component ID */
static int num_boards;          /* number of ports configured */

/***********************************************************************
*                  LOCAL FUNCTION DECLARATIONS                         *
************************************************************************/

/* These are the functions that actually do the I/O
   everything else is just init code
*/

static void read_board(void *arg, long period);
static void write_board(void *arg, long period);

/* 'pins_and_params()' does most of the work involved in setting up
   the driver.  It parses the command line (argv[]), then if the
   command line is OK, it calls hal_init(), allocates shared memory
   for the parport_t data structure(s), and exports pins and parameters
   It does not set up functions, since that is handled differently in
   realtime and user space.
*/
static int pins_and_params(char *argv[]);
static unsigned short parse_board_addr(char *cp);
static int export_board(int boardnum, epp_board_t * board);
static int export_byte(int boardnum, int pin_num, io_pin_t *pin, int num_pins, 
int dir);
static int export_input_pin(int boardnum, int pinnum, io_pin_t *pin);
static int export_output_pin(int boardnum, int pinnum, io_pin_t *pin);


/***********************************************************************
*                       INIT AND EXIT CODE                             *
************************************************************************/

#define MAX_BOARDS 8
#define MAX_TOK ((MAX_BOARDS*2)+3)

int rtapi_app_main(void)
{
    char *cp;
    char *argv[MAX_TOK];
    char name[HAL_NAME_LEN + 2];
    int n, retval;
    /* test for config string */
    if ((cfg == 0) || (cfg[0] == '\0')) {
        rtapi_print_msg(RTAPI_MSG_ERR, "EPPPORT: ERROR: no config string\n");
        return -1;
    }
    /* as a RT module, we don't get a nice argc/argv command line, we only
       get a single string... so we need to tokenize it ourselves */
    /* and to make things worse, it seems that insmod under kernel 2.6
       ends the config string at the first space, so I added the ability
       to use '_' as a token separator.  What an ugly hack...  HAL needs
       a better way to handle insmod time config data */
    cp = cfg;
    for (n = 0; n < MAX_TOK; n++) {
        /* strip leading whitespace or token separators */
        while ((*cp != '\0') && ( isspace(*cp) || ( *cp == '_') ))
            cp++;
        /* mark beginning of token */
        argv[n] = cp;
        /* find end of token */
        while ((*cp != '\0') && !( isspace(*cp) || ( *cp == '_') ))
            cp++;
        /* mark end of this token, prepare to search for next one */
        if (*cp != '\0') {
            *cp = '\0';
            cp++;
        }
    }
    for (n = 0; n < MAX_TOK; n++) {
        /* is token empty? */
        if (argv[n][0] == '\0') {
            /* yes - make pointer NULL */
            argv[n] = NULL;
        }
    }
    /* parse "command line", set up pins and parameters */
    retval = pins_and_params(argv);
    if (retval != 0) {
        return retval;
    }
    /* export functions for each board */
    for (n = 0; n < num_boards; n++) {
        /* make read function name */
        rtapi_snprintf(name, HAL_NAME_LEN, "eppport.%d.read", n);
        /* export read function */
        retval = hal_export_funct(name, read_board, &(board_array[n]),
            0, 0, comp_id);
        if (retval != 0) {
            rtapi_print_msg(RTAPI_MSG_ERR,
                "EPPPORT: ERROR: port %d read funct export failed\n", n);
            hal_exit(comp_id);
            return -1;
        }
        /* make write function name */
        rtapi_snprintf(name, HAL_NAME_LEN, "eppport.%d.write", n);
        /* export write function */
        retval = hal_export_funct(name, write_board, &(board_array[n]),
            0, 0, comp_id);
        if (retval != 0) {
            rtapi_print_msg(RTAPI_MSG_ERR,
                "EPPPORT: ERROR: port %d write funct export failed\n", n);
            hal_exit(comp_id);
            return -1;
        }
    }
    rtapi_print_msg(RTAPI_MSG_INFO,
        "EPPPORT: installed driver for %d boards\n", num_boards);
    hal_ready(comp_id);
    return 0;
}

void rtapi_app_exit(void)
{
    int n;
    epp_board_t *board;

    for ( n = 0 ; n < num_boards ; n++ ) {
        board = &(board_array[n]);
        }
    hal_exit(comp_id);
}


/***********************************************************************
*                  REALTIME PORT READ AND WRITE FUNCTIONS              *
************************************************************************/

static inline void epp_check_for_timeout(epp_board_t * board) {
    if (board->port_timeout){
        (void) rtapi_inb(board->base_addr+3);  //dummy read
        }
    
    if (rtapi_inb(board->base_addr+1) & 0x01){
        (void) rtapi_inb(board->base_addr+1);  //some has reset by double read
        rtapi_outb(0x01,board->base_addr+1);   //some has reset by 1
        rtapi_outb(0xFE,board->base_addr+1);   //some has reset by 0
        
        if (!board->port_timeout){
            board->port_timeout=1;
                rtapi_print_msg(RTAPI_MSG_ERR,
                "EPPPORT: board (%04X) EPP timeout\n", board->base_addr);
        }
        } 
        else{
        if (board->port_timeout){
            board->port_timeout=0;
                rtapi_print_msg(RTAPI_MSG_ERR,
                "EPPPORT: board (%04X) EPP timeout cleared\n", 
board->base_addr);
        }
    }
}


static void split_input(unsigned char data, io_pin_t *dest)
{
    int b;
    unsigned char mask;
    /* splits a byte into HAL pins (and their NOTs) */
    mask = 0x01;
    for (b = 0 ; b < 8 ; b++ ) {
        if ( data & mask ) {
            *(dest->data) = 1;    // input high
            *(dest->io.not) = 0;
        } else {
            *(dest->data) = 0;    // input low
            *(dest->io.not) = 1;
        }
        mask <<= 1;
        dest++;
    }
}

static void read_board(void *arg, long period)
{
    unsigned char indata, n;
    epp_board_t *board;
    board = arg;

    if (!board->port_timeout){
        for (n = 0 ;n < (board->port_inputs) ; n++) {
            if (n == 0) {indata = rtapi_inb(board->base_addr+3);}
                else {indata = rtapi_inb(board->base_addr+4);}
            split_input(indata, &(board->port_Inp[n * 8]));
        }
        }
}

unsigned char build_output(io_pin_t *src)
{
    int b;
    unsigned char data, mask;
    data = 0x00;
    mask = 0x01;
    for (b = 0; b < 8; b++) {
        /* get the data, add to output byte */
            if ( *(src->data) ) {
                if ( !(src->io.invert) ) {
                    data |= mask;
                }
            } else {
                if ( (src->io.invert) ) {
                    data |= mask;
                }
            }
            mask <<= 1;
            src++;
    }
    return data;
}

static void write_board(void *arg, long period)
{
    unsigned char outdata, n;
    epp_board_t *board;
    board = arg;

    if (!board->port_timeout){
        for (n = 0 ;n < (board->port_outputs) ; n++) {
            outdata = build_output(&(board->port_Out[n*8]));
            if (n == 0) {rtapi_outb(~outdata, board->base_addr+3);}
            else {rtapi_outb(~outdata, board->base_addr+4);}
        }
        }
        epp_check_for_timeout(board);
}

/***********************************************************************
*                   LOCAL FUNCTION DEFINITIONS                         *
************************************************************************/

static int pins_and_params(char *argv[])
{
    unsigned short board_addr[MAX_BOARDS];
    unsigned char inputs[MAX_BOARDS],outputs[MAX_BOARDS];
    int n, retval;

    /* clear port_addr and dir_bits arrays */
    for (n = 0; n < MAX_BOARDS; n++) {
        board_addr[n] = 0;
        inputs[n] = 0;
        outputs[n] = 0;
    }

    /* parse config string, results in port_addr[] and data_dir[] arrays */
    num_boards = 0;
    n = 0;
    while ((num_boards < MAX_BOARDS) && (argv[n] != 0)) {
        board_addr[num_boards] = parse_board_addr(argv[n]);
        if (board_addr[num_boards] == 0) {
            rtapi_print_msg(RTAPI_MSG_ERR,
                "EPPPORT: ERROR: bad port address '%s'\n", argv[n]);
            return -1;
        }
        n++;
        if (argv[n] == 0) {
            rtapi_print_msg(RTAPI_MSG_ERR,
                "EPPPORT: ERROR: no config info for port %s\n", argv[n-1]);
            return -1;
        }

    if ((argv[n][0] == 'i') || (argv[n][0] == 'I')) {
        if ((argv[n][1] >= '0') && (argv[n][1] <= '9')) {
            inputs[num_boards] = argv[n][1]-'0';
            }
    }
    n++;

    if ((argv[n][0] == 'o') || (argv[n][0] == 'O')) {
        if ((argv[n][1] >= '0') && (argv[n][1] <= '9')) {
            outputs[num_boards] = argv[n][1]-'0';
            }
    }
    n++;

    // to do some error checking if bad parameter is listed?!?

        num_boards++;
    }

    /* OK, now we've parsed everything */
    if (num_boards == 0) {
        rtapi_print_msg(RTAPI_MSG_ERR,
            "EPPPORT: ERROR: no ports configured\n");
        return -1;
    }
    /* have good config info, connect to the HAL */
    comp_id = hal_init("hal_eppport");
    if (comp_id < 0) {
        rtapi_print_msg(RTAPI_MSG_ERR, "EPPPORT: ERROR: hal_init() failed\n");
        return -1;
    }
    /* allocate shared memory for board data */
    board_array = hal_malloc(num_boards * sizeof(epp_board_t));
    if (board_array == 0) {
        rtapi_print_msg(RTAPI_MSG_ERR,
            "EPPPORT: ERROR: hal_malloc() failed\n");
        hal_exit(comp_id);
        return -1;
    }
    /* export all the pins and params for each board */
    for (n = 0; n < num_boards; n++) {

        /* config addr and direction */
        board_array[n].base_addr = board_addr[n];
        board_array[n].port_inputs = inputs[n];
        board_array[n].port_outputs = outputs[n];
        board_array[n].port_timeout = 3;
        /* export all vars */
        retval = export_board(n, &(board_array[n]));
        if (retval != 0) {
            rtapi_print_msg(RTAPI_MSG_ERR,
                "EPPPORT: ERROR: board %d (%04X) var export failed\n", n, 
board_addr[n]);
            hal_exit(comp_id);
            return -1;
        }
    }
    return 0;
}

static unsigned short parse_board_addr(char *cp)
{
    unsigned short result;
    /* initial value */
    result = 0;
    /* test for leading '0x' */
    if (cp[0] == '0') {
        if ((cp[1] == 'X') || (cp[1] == 'x')) {
            /* leading '0x', skip it */
            cp += 2;
        }
    }
    /* ok, now parse digits */
    while (*cp != '\0') {
        /* if char is a hex digit, add it to result */
        if ((*cp >= '0') && (*cp <= '9')) {
            result <<= 4;
            result += *cp - '0';
        } else if ((*cp >= 'A') && (*cp <= 'F')) {
            result <<= 4;
            result += (*cp - 'A') + 10;
        } else if ((*cp >= 'a') && (*cp <= 'f')) {
            result <<= 4;
            result += (*cp - 'a') + 10;
        } else {
            /* not a valid hex digit */
            return 0;
        }
        /* next char */
        cp++;
    }
    return result;
}


static int export_board(int boardnum, epp_board_t * board)
{
    int retval, msg, n;
    unsigned char ch;
    /* This function exports a lot of stuff, which results in a lot of
       logging if msg_level is at INFO or ALL. So we save the current value
       of msg_level and restore it later.  If you actually need to log this
       function's actions, change the second line below */
    msg = rtapi_get_msg_level();
    rtapi_set_msg_level(RTAPI_MSG_WARN);
    retval = 0;

//export outputs as connector/pin
    for (n = 0 ;n < (board->port_outputs) ; n++) {
        retval += export_byte ( boardnum, n * 10 , &(board->port_Out[n*8]), 8, 
1 );
    }

//export inputs as connector/pin
   for (n = 0 ;n < (board->port_inputs) ; n++) {
        retval += export_byte ( boardnum, n * 10 , &(board->port_Inp[n*8]), 8, 
0 );
    }

    /* initialize hardware  */
    outb(0x04, board->base_addr+2);
    outb(0x00, board->base_addr+3); //Reset counter and byte 0 - can give wrong 
cycle
    if (inb(board->base_addr+1)&0x01){   //clear timeout
        ch = inb(board->base_addr+1);    //some boards need double read
        outb(0x01, board->base_addr+1); //some board needs to write 1
        outb(0xfe, board->base_addr+1); //and some boards needs to write 0
    }
    /* restore saved message level */
    rtapi_set_msg_level(msg);
    return retval;
}

static int export_byte(int boardnum, int pin_num, io_pin_t *pin, int num_pins, 
int dir)
{
    int n, retval;
    retval = 0;
    for ( n = 0 ; n < num_pins ; n++ ) {
        if ( dir == 0 ) {
            retval += export_input_pin(boardnum, pin_num, pin );
        } else {
            retval += export_output_pin(boardnum, pin_num, pin );
        }
        pin_num++;
        pin++;
    }
    return retval;
}

static int export_input_pin(int boardnum, int pinnum, io_pin_t *pin)
{
    char buf[HAL_NAME_LEN + 2];
    int retval;
    /* export read only HAL pin for input data */
    rtapi_snprintf(buf, HAL_NAME_LEN, "eppport.%d.in-%02d", boardnum, pinnum);
    retval = hal_pin_bit_new(buf, HAL_OUT, &(pin->data), comp_id);
    if (retval != 0) {
        return retval;
    }
    /* export additional pin for inverted input data */
    rtapi_snprintf(buf, HAL_NAME_LEN, "eppport.%d.in-%02d-not", boardnum, 
pinnum);
    retval = hal_pin_bit_new(buf, HAL_OUT, &(pin->io.not), comp_id);
    /* initialize HAL pins */
    *(pin->data) = 0;
    *(pin->io.not) = 1;
    return retval;
}

static int export_output_pin(int boardnum, int pinnum, io_pin_t *pin)
{
    char buf[HAL_NAME_LEN + 2];
    int retval;
    /* export read only HAL pin for output data */
    rtapi_snprintf(buf, HAL_NAME_LEN, "eppport.%d.out-%02d", boardnum, pinnum);
    retval = hal_pin_bit_new(buf, HAL_IN, &(pin->data), comp_id);
    if (retval != 0) {
        return retval;
    }
    /* export parameter for polarity */
    rtapi_snprintf(buf, HAL_NAME_LEN, "eppport.%d.out-%02d-invert", boardnum, 
pinnum);
    retval = hal_param_bit_new(buf, HAL_RW, &(pin->io.invert), comp_id);
    /* initialize HAL pin and param */
    *(pin->data) = 0;
    pin->io.invert = 0;
    return retval;
}
------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
Emc-developers mailing list
Emc-developers@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/emc-developers

Reply via email to