hal_evoreg.c
1 /******************************************************************** 2 * Description: hal_evoreg.c 3 * This file, 'hal_evoreg.c', is a HAL component that 4 * provides a driver for the Siemens EVOREG motion 5 * control board. 6 * 7 * Author: Martin Kuhnle, John Kasunich 8 * License: GPL Version 2 9 * 10 * Copyright (c) 2003 All rights reserved. 11 * 12 * Last change: 13 ********************************************************************/ 14 15 /** This file, 'hal_evoreg.c', is a HAL component that provides a 16 driver for the Siemens EVOREG motion control board. 17 This board privides three 16bit DAC's, three encoder inputs, 18 46 digital inputs and 21 digital outputs 19 20 Fixme: error messages are not proper up to now 21 ToDo: better error messages 22 make inverted bits available 23 posibility to read back outputs 24 check dac values for limits 25 scale for every dacs 26 scale for every encoder 27 check if the dacs are updated all at the same time 28 enable Interrupts 29 check for wire break 30 watchdog 31 32 33 34 Copyright (C) 2003 Martin Kuhnle 35 <mkuhnle AT users DOT sourceforge DOT net> 36 John Kasunich 37 <jmkasunich AT users DOT sourceforge DOT net> 38 39 */ 40 41 /** This program is free software; you can redistribute it and/or 42 modify it under the terms of version 2 of the GNU General 43 Public License as published by the Free Software Foundation. 44 This library is distributed in the hope that it will be useful, 45 but WITHOUT ANY WARRANTY; without even the implied warranty of 46 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 47 GNU General Public License for more details. 48 49 You should have received a copy of the GNU General Public 50 License along with this library; if not, write to the Free Software 51 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 52 53 THE AUTHORS OF THIS LIBRARY ACCEPT ABSOLUTELY NO LIABILITY FOR 54 ANY HARM OR LOSS RESULTING FROM ITS USE. IT IS _EXTREMELY_ UNWISE 55 TO RELY ON SOFTWARE ALONE FOR SAFETY. Any machinery capable of 56 harming persons must have provisions for completely removing power 57 from all motors, etc, before persons enter any danger area. All 58 machinery must be designed to comply with local and national safety 59 codes, and the authors of this software can not, and do not, take 60 any responsibility for such compliance. 61 62 This code was written as part of the EMC HAL project. For more 63 information, go to www.linuxcnc.org. 64 */ 65 66 #include "rtapi_ctype.h" /* isspace() */ 67 #include "rtapi.h" /* RTAPI realtime OS API */ 68 #include "rtapi_app.h" /* RTAPI realtime module decls */ 69 #include "hal.h" /* HAL public API decls */ 70 71 /* If FASTIO is defined, uses outb() and inb() from <asm.io>, 72 instead of rtapi_outb() and rtapi_inb() - the <asm.io> ones 73 are inlined, and save a microsecond or two (on my 233MHz box) 74 */ 75 #define FASTIO 76 77 #ifdef FASTIO 78 #define rtapi_inb inb 79 #define rtapi_outb outb 80 #include <asm/io.h> 81 #endif 82 83 /* module information */ 84 MODULE_AUTHOR("Martin Kuhnle"); 85 MODULE_DESCRIPTION("SIEMENS-EVOREG Driver for EMC HAL"); 86 MODULE_LICENSE("GPL"); 87 /* static char *cfg = 0; */ 88 /* config string 89 RTAPI_MP_STRING(cfg, "config string"); */ 90 91 /*********************************************************************** 92 * STRUCTURES AND GLOBAL VARIABLES * 93 ************************************************************************/ 94 95 /* this structure contains the runtime data needed by the 96 driver for a single port/channel 97 */ 98 99 typedef struct { 100 void *io_base; 101 hal_float_t *dac_out[3]; /* ptrs for dac output */ 102 hal_float_t *position[3]; /* ptrs for encoder input */ 103 hal_bit_t *digital_in[47]; /* ptrs for digital input pins 0 - 45 */ 104 hal_bit_t *digital_out[25]; /* ptrs for digital output pins 0 - 20 */ 105 __u16 raw_counts_old[3]; 106 __s32 counts[3]; 107 hal_float_t pos_scale; /*! \todo scale for position command FIXME schould be one per axis */ 108 } evoreg_t; 109 110 /* pointer to array of evoreg_t structs in shared memory, 1 per port */ 111 static evoreg_t *port_data_array; 112 113 /* other globals */ 114 static int comp_id; /* component ID */ 115 static int num_ports; /* number of ports configured */ 116 117 /*********************************************************************** 118 * LOCAL FUNCTION DECLARATIONS * 119 ************************************************************************/ 120 /* These is the functions that actually do the I/O 121 everything else is just init code 122 */ 123 static void update_port(void *arg, long period); 124 125 /*********************************************************************** 126 * INIT AND EXIT CODE * 127 ************************************************************************/ 128 129 #define MAX_PORTS 8 130 #define MAX_DAC 3 /* number of DACs per card */ 131 #define MAX_ENC 3 /* number of Encoders per card */ 132 133 #define MAX_TOK ((MAX_PORTS*2)+3) 134 135 int rtapi_app_main(void) 136 { 137 char name[HAL_NAME_LEN + 1]; 138 int n,i , retval, num_dac, num_enc; 139 140 unsigned int base=0x300; 141 142 /* only one port at the moment */ 143 num_ports = 1; 144 n = 0; 145 146 #define ISA_BASE 0xC9000 147 #define ISA_MAX 0x100000 /* allgemeiner Speicherzugriff */ 148 149 150 /* STEP 1: initialise the driver */ 151 comp_id = hal_init("hal_evoreg"); 152 if (comp_id < 0) { 153 rtapi_print_msg(RTAPI_MSG_ERR, 154 "EVOREG: ERROR: hal_init() failed\n"); 155 return -1; 156 } 157 158 /* STEP 2: allocate shared memory for EVOREG data */ 159 port_data_array = hal_malloc(num_ports * sizeof(evoreg_t)); 160 if (port_data_array == 0) { 161 rtapi_print_msg(RTAPI_MSG_ERR, 162 "EVOREG: ERROR: hal_malloc() failed\n"); 163 hal_exit(comp_id); 164 return -1; 165 } 166 167 /*! \todo FIXME: Test memory area and setup the card */ 168 port_data_array->io_base = ioremap(ISA_BASE, ISA_MAX - ISA_BASE); 169 rtapi_print_msg(RTAPI_MSG_ERR,"EVOREG: io_base: %p \n", port_data_array->io_base); 170 outw(0x82c9,base); /* set indexregister */ 171 172 /* Set all outputs to zero */ 173 writew(0, port_data_array->io_base + 0x20); /* digital out 0-15 */ 174 writew(0, port_data_array->io_base + 0x40); /* digital out 16-23 */ 175 writew(0, port_data_array->io_base + 0x60); /* DAC 1 */ 176 writew(0, port_data_array->io_base + 0x80); /* DAC 2 */ 177 writew(0, port_data_array->io_base + 0xa0); /* DAC 3 */ 178 /* Reset Encoder's */ 179 writew(0, port_data_array->io_base + 0x02); /* ENCODER 1 */ 180 writew(0, port_data_array->io_base + 0x0a); /* ENCODER 2 */ 181 writew(0, port_data_array->io_base + 0x12); /* ENCODER 3 */ 182 183 /* STEP 3: export the pin(s) */ 184 185 /* Export DAC pin's */ 186 for ( num_dac=1; num_dac<=MAX_DAC; num_dac++) { 187 retval = hal_pin_float_newf(HAL_IN, &(port_data_array->dac_out[num_dac-1]), 188 comp_id, "evoreg.%d.dac-%02d-out", 1, num_dac); 189 if (retval < 0) { 190 rtapi_print_msg(RTAPI_MSG_ERR, 191 "EVOREG: ERROR: port %d var export failed with err=%i\n", n + 1, 192 retval); 193 hal_exit(comp_id); 194 return -1; 195 } 196 } 197 198 /* Export Encoder pin's */ 199 for ( num_enc=1; num_enc<=MAX_ENC; num_enc++) { 200 retval = hal_pin_float_newf(HAL_OUT, &(port_data_array->position[num_enc - 1]), 201 comp_id, "evoreg.%d.position-%02d-in", 1, num_enc); 202 if (retval < 0) { 203 rtapi_print_msg(RTAPI_MSG_ERR, 204 "EVOREG: ERROR: port %d var export failed with err=%i\n", n + 1, 205 retval); 206 hal_exit(comp_id); 207 return -1; 208 } 209 } 210 211 /* Export IO pin's */ 212 213 /* export write only HAL pin's for the input bit */ 214 for ( i=0; i<=45;i++) { 215 retval += hal_pin_bit_newf(HAL_OUT, &(port_data_array->digital_in[i]), 216 comp_id, "evoreg.%d.pin-%02d-in", 1, i); 217 218 /* export another write only HAL pin for the same bit inverted */ 219 /* 220 retval += hal_pin_bit_newf(HAL_OUT, &(port_data_array->digital_in[(2*i)+1]), 221 comp_id, "evoreg.%d.pin-%02d-in-not", 1, i); */ 222 if (retval < 0) { 223 rtapi_print_msg(RTAPI_MSG_ERR, 224 "EVOREG: ERROR: port %d var export failed with err=%i\n", n + 1, 225 retval); 226 hal_exit(comp_id); 227 return -1; 228 } 229 } 230 231 /* export read only HAL pin's for the output bit */ 232 for ( i=0; i<=23;i++) { 233 retval += hal_pin_bit_newf(HAL_IN, &(port_data_array->digital_out[i]), 234 comp_id, "evoreg.%d.pin-%02d-out", 1, i); 235 236 /* export another read only HAL pin for the same bit inverted */ 237 /* 238 retval += hal_pin_bit_newf(HAL_IN, &(port_data_array->digital_out[(2*i)+1]), 239 comp_id, "evoreg.%d.pin-%02d-out-not", 1, i)); */ 240 if (retval < 0) { 241 rtapi_print_msg(RTAPI_MSG_ERR, 242 "EVOREG: ERROR: port %d var export failed with err=%i\n", n + 1, 243 retval); 244 hal_exit(comp_id); 245 return -1; 246 } 247 } 248 249 /* export parameter for scaling */ 250 retval = hal_param_float_newf(HAL_RW, &(port_data_array->pos_scale), 251 comp_id, "evoreg.%d.position-scale", 1); 252 if (retval != 0) { 253 return retval; 254 } 255 256 257 /* STEP 4: export function */ 258 rtapi_snprintf(name, sizeof(name), "evoreg.%d.update", n + 1); 259 retval = hal_export_funct(name, update_port, &(port_data_array[n]), 1, 0, 260 comp_id); 261 if (retval < 0) { 262 rtapi_print_msg(RTAPI_MSG_ERR, 263 "EVOREG: ERROR: port %d write funct export failed\n", n + 1); 264 hal_exit(comp_id); 265 return -1; 266 } 267 268 rtapi_print_msg(RTAPI_MSG_INFO, 269 "EVOREG: installed driver for %d card(s)\n", num_ports); 270 hal_ready(comp_id); 271 return 0; 272 } 273 274 void rtapi_app_exit(void) 275 { 276 outw(0x0,0x300); 277 hal_exit(comp_id); 278 } 279 280 /************************************************************** 281 * REALTIME PORT WRITE FUNCTION * 282 **************************************************************/ 283 284 static void update_port(void *arg, long period) 285 { 286 evoreg_t *port; 287 int pin; 288 unsigned char tmp, mask; 289 __u16 raw_counts[3]; 290 291 port = arg; 292 293 /* write DAC's */ 294 writew((*(port->dac_out[0])/10 * 0x7fff), port->io_base + 0x60); 295 writew((*(port->dac_out[1])/10 * 0x7fff), port->io_base + 0x80); 296 writew((*(port->dac_out[2])/10 * 0x7fff), port->io_base + 0xa0); 297 298 /* Read Encoders, improve the 16bit hardware counters to 32bit and scale the values */ 299 raw_counts[0] = (__u16) readw(port->io_base); 300 raw_counts[1] = (__u16) readw(port->io_base + 0x08 ); 301 raw_counts[2] = (__u16) readw(port->io_base + 0x10 ); 302 303 port->counts[0] += (__s16) (raw_counts[0] - port->raw_counts_old[0]); 304 port->raw_counts_old[0] = raw_counts[0]; 305 306 port->counts[1] += (__s16) (raw_counts[1] - port->raw_counts_old[1]); 307 port->raw_counts_old[1] = raw_counts[1]; 308 309 port->counts[2] += (__s16) (raw_counts[2] - port->raw_counts_old[2]); 310 port->raw_counts_old[2] = raw_counts[2]; 311 312 *port->position[0] = port->counts[0] * port->pos_scale; 313 *port->position[1] = port->counts[1] * port->pos_scale; 314 *port->position[2] = port->counts[2] * port->pos_scale; 315 316 317 /* read digital inputs */ 318 tmp = readw(port->io_base + 0x20); /* digital input 0-15 */ 319 mask = 0x01; 320 for (pin=0 ; pin < 16 ; pin++) { 321 *port->digital_in[pin] = (tmp & mask) ? 1:0 ; 322 mask <<= 1; 323 } 324 tmp = readw(port->io_base + 0x40); /* digital input 16-31 */ 325 mask = 0x01; 326 for (pin=16 ; pin < 32 ; pin++) { 327 *port->digital_in[pin] = (tmp & mask) ? 1:0 ; 328 mask <<= 1; 329 } 330 331 tmp = readw(port->io_base + 0x60); /* digital input 32-45 */ 332 mask = 0x01; 333 for (pin=32 ; pin < 46 ; pin++) { 334 *port->digital_in[pin] = (tmp & mask) ? 1:0 ; 335 mask <<= 1; 336 } 337 338 339 /* write digital outputs */ 340 tmp = 0x0; 341 mask = 0x01; 342 for (pin=0; pin < 16; pin++) { 343 if (port->digital_out[pin]) { 344 tmp |= mask; 345 mask <<= 1; 346 } 347 } 348 writew( tmp, port->io_base + 0x20); /* digital output 0-15 */ 349 350 351 tmp = 0x0; 352 mask = 0x01; 353 for (pin=16; pin < 24; pin++) { 354 if (port->digital_out[pin]) { 355 tmp |= mask; 356 mask <<= 1; 357 } 358 } 359 writew( tmp, port->io_base + 0x40); /* digital output 16-23 */ 360 361 }