📄 hal_motenc.c
字号:
/****************************************************************************** * * Copyright (C) 2005 Peter G. Vavaroutsos <pete AT vavaroutsos DOT com> * License: GPL Version 2 * * $RCSfile: hal_motenc.c,v $ * $Author: jmkasunich $ * $Locker: $ * $Revision: 1.23 $ * $State: Exp $ * $Date: 2007/06/13 02:05:25 $ * * This is the driver for the Vital Systems MOTENC-100 board. * The board includes 8 quadrature decoders, 8 analog inputs, * 8 analog outputs, 68 digital inputs, 32 digital outputs, * programable timer interrupts, a watch dog timer, and a hardware * E-STOP circuit. * * Installation of the driver (realtime only): * * insmod hal_motenc * * * The following items are exported to the HAL. <boardId> is read * from the jumper settings on the MOTENC-100 board and is formated * as "%d". <channel> is formated as "%02d". * * Encoders: * Parameters: * float motenc.<boardId>.enc-<channel>-scale * * Pins: * s32 motenc.<boardId>.enc-<channel>-count * float motenc.<boardId>.enc-<channel>-position * bit motenc.<boardId>.enc-<channel>-index * bit motenc.<boardId>.enc-<channel>-index-enable * bit motenc.<boardId>.enc-<channel>-reset * * Functions: * void motenc.<boardId>.encoder-read * * * DACs: * Parameters: * float motenc.<boardId>.dac-<channel>-offset * float motenc.<boardId>.dac-<channel>-gain * * Pins: * float motenc.<boardId>.dac-<channel>-value * * Functions: * void motenc.<boardId>.dac-write * * * ADC: * Parameters: * float motenc.<boardId>.adc-<channel>-offset * float motenc.<boardId>.adc-<channel>-gain * * Pins: * float motenc.<boardId>.adc-<channel>-value * * Functions: * void motenc.<boardId>.adc-read * * * Digital In: * Pins: * bit motenc.<boardId>.pin-<channel>-in * bit motenc.<boardId>.pin-<channel>-in-not * * Functions: * void motenc.<boardId>.digital-in-read * * * Digital Out: * Parameters: * bit motenc.<boardId>.pin-<channel>-out-invert * * Pins: * bit motenc.<boardId>.pin-<channel>-out * * Functions: * void motenc.<boardId>.digital-out-write * * * Miscellaneous: * Parameters: * u32 motenc.<boardId>.watchdog-control * MOTENC_WATCHDOG_CTL_8MS 0x00000000 * MOTENC_WATCHDOG_CTL_16MS 0x00000001 * MOTENC_WATCHDOG_CTL_ENABLE 0x00000004 * MOTENC_WATCHDOG_CTL_AUTO_RESET 0x00000010 // Reset by DAC writes. * * Pins: * bit motenc.<boardId>.estop-in * bit motenc.<boardId>.estop-in-not * bit motenc.<boardId>.watchdog-reset * * Functions: * void motenc.<boardId>.misc-update * ****************************************************************************** * * 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. * ******************************************************************************/#ifndef RTAPI#error This is a realtime component only!#endif#include <linux/pci.h>#include "rtapi.h" // RTAPI realtime OS API.#include "rtapi_app.h" // RTAPI realtime module decls.#include "hal.h" // HAL public API decls.#include "motenc.h" // Hardware dependent defines.#ifndef MODULE#define MODULE#endif#ifdef MODULE// Module information.MODULE_AUTHOR("Pete Vavaroutsos");MODULE_DESCRIPTION("Driver for Vital Systems MOTENC-100 for EMC HAL");MODULE_LICENSE("GPL");#endif // MODULE/****************************************************************************** * DEVICE OBJECT * * This object contains all the data for one card. A device object is * dynamically allocated in shmem for each card during initialization. * ******************************************************************************/typedef struct { // Pins. hal_s32_t *pCount; // Captured binary count value. hal_float_t *pPosition; // Scaled position (floating point). hal_bit_t *pIndex; // Current state of index. hal_bit_t *pIndexEnable; // Setting this pin causes the count // to be cleared on the next index pulse. // Use this feature at your own risk as the PID loop // may get upset. This pin is self clearing. hal_bit_t *pReset; // Setting this pin causes Count to be reset. // Parameters. hal_float_t scale; // Scaling factor for position. // Private data. float oldScale; // Stored scale value. double scaleRecip; // Reciprocal value used for scaling.} EncoderPinsParams;typedef struct { // Pins. hal_float_t *pValue; // Desired value. // Parameters. hal_float_t offset; hal_float_t gain;} DacPinsParams;typedef struct { // Pins. hal_float_t *pValue; // Converted value. // Parameters. hal_float_t offset; hal_float_t gain;} AdcPinsParams;typedef struct { // Pins. hal_bit_t *pValue; hal_bit_t *pValueNot;} DigitalInPinsParams;typedef struct { // Pins. hal_bit_t *pValue; // Parameters. hal_bit_t invert;} DigitalOutPinsParams;typedef struct { // Pins. hal_bit_t *pEstopIn; hal_bit_t *pEstopInNot; hal_bit_t *pWatchdogReset;// This pin is self clearing. // Parameters. hal_u32_t watchdogControl;} MiscPinsParams;typedef struct { // Private data. MotencRegMap *pCard; int boardType; char *pTypeName; int boardID; int numFpga; int adcState; hal_u32_t watchdogControl;// Shadow HW register. // Exported to HAL. EncoderPinsParams encoder[MOTENC_NUM_ENCODER_CHANNELS]; DacPinsParams dac[MOTENC_NUM_DAC_CHANNELS]; AdcPinsParams adc[MOTENC_NUM_ADC_CHANNELS]; DigitalInPinsParams in[MOTENC_NUM_DIGITAL_INPUTS]; DigitalOutPinsParams out[MOTENC_NUM_DIGITAL_OUTPUTS]; MiscPinsParams misc;} Device;// These methods are used for initialization.static int Device_Init(Device *this, MotencRegMap *pCard);static int Device_ExportPinsParametersFunctions(Device *this, int componentId);static int Device_ExportEncoderPinsParametersFunctions(Device *this, int componentId, int boardId);static int Device_ExportDacPinsParametersFunctions(Device *this, int componentId, int boardId);static int Device_ExportAdcPinsParametersFunctions(Device *this, int componentId, int boardId);static int Device_ExportDigitalInPinsParametersFunctions(Device *this, int componentId, int boardId);static int Device_ExportDigitalOutPinsParametersFunctions(Device *this, int componentId, int boardId);static int Device_ExportMiscPinsParametersFunctions(Device *this, int componentId, int boardId);// These methods are exported to the HAL.static void Device_EncoderRead(void *this, long period);static void Device_DacWrite(void *this, long period);static void Device_AdcRead(void *this, long period);static void Device_DigitalInRead(void *this, long period);static void Device_DigitalOutWrite(void *this, long period);static void Device_MiscUpdate(void *this, long period);// Private helper methods.static int Device_AdcRead4(Device *this, int startChannel);/****************************************************************************** * DRIVER OBJECT * * This object contains all the data for this HAL component. * ******************************************************************************/#define MAX_DEVICES 4 // Since there are 2 board id bits.typedef struct { int componentId; // HAL component ID. Device *deviceTable[MAX_DEVICES]; unsigned char idPresent[MAX_DEVICES];} Driver;static Driver driver;/****************************************************************************** * INIT AND EXIT CODE ******************************************************************************/intrtapi_app_main(void){ int i, j; struct pci_dev *pDev = NULL; MotencRegMap *pCard = NULL; Device *pDevice; // Connect to the HAL. driver.componentId = hal_init("hal_motenc"); if (driver.componentId < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "MOTENC: ERROR: hal_init() failed\n"); return(-EINVAL); } for(i = 0; i < MAX_DEVICES; i++){ driver.deviceTable[i] = NULL; driver.idPresent[i] = 0; } i = 0; // Find a MOTENC card. while((i < MAX_DEVICES) && ((pDev = pci_find_device(MOTENC_VENDOR_ID, MOTENC_DEVICE_ID, pDev)) != NULL)){ // Allocate memory for device object. pDevice = hal_malloc(sizeof(Device)); if (pDevice == 0) { rtapi_print_msg(RTAPI_MSG_ERR, "MOTENC: ERROR: hal_malloc() failed\n"); hal_exit(driver.componentId); return(-ENOMEM); } // Save pointer to device object. driver.deviceTable[i++] = pDevice; // Map card into memory. pCard = (MotencRegMap *)ioremap_nocache(pci_resource_start(pDev, 2), pci_resource_len(pDev, 2)); rtapi_print_msg(RTAPI_MSG_INFO, "MOTENC: Card detected in slot %2x\n", PCI_SLOT(pDev->devfn)); rtapi_print_msg(RTAPI_MSG_INFO, "MOTENC: Card address @ %p, Len = %d\n", pCard, (int)pci_resource_len(pDev, 2)); // Initialize device. Device_Init(pDevice, pCard); rtapi_print_msg(RTAPI_MSG_INFO, "MOTENC: Card is %s, ID: %d\n", pDevice->pTypeName, pDevice->boardID); if ( pDevice->boardType == 0 ) { rtapi_print_msg(RTAPI_MSG_ERR, "MOTENC: ERROR, unknown card detected\n"); hal_exit(driver.componentId); return(-ENODEV); } if ( driver.idPresent[pDevice->boardID] != 0 ) { // duplicate ID... a strict driver would bail out, but // we are nice, we try to find an unused ID j = 0; while ( driver.idPresent[j] != 0 ) { j++; if ( j >= MAX_DEVICES ) { rtapi_print_msg(RTAPI_MSG_ERR, "MOTENC: ERROR, duplicate ID, can't remap\n"); hal_exit(driver.componentId); return(-EINVAL); } } pDevice->boardID = j; rtapi_print_msg(RTAPI_MSG_WARN, "MOTENC: WARNING, duplicate ID, remapped to %d\n", j); } driver.idPresent[pDevice->boardID] = 1; // Export pins, parameters, and functions. if(Device_ExportPinsParametersFunctions(pDevice, driver.componentId)){ hal_exit(driver.componentId); return(-EINVAL); } } if(pCard == NULL){ // No card present. rtapi_print_msg(RTAPI_MSG_WARN, "MOTENC: **** No MOTENC card detected ****\n"); hal_exit(driver.componentId); return -ENODEV; } hal_ready(driver.componentId); return(0);}voidrtapi_app_exit(void){ int i, j; Device *pDevice; hal_exit(driver.componentId); for(i = 0; i < MAX_DEVICES; i++){ if((pDevice = driver.deviceTable[i]) != NULL){ // turn off digital outputs for(j = 0; j < pDevice->numFpga; j++){ pDevice->pCard->fpga[i].digitalIo = MOTENC_DIGITAL_OUT; } // set DAC outputs to zero volts for(i = 0; i < MOTENC_NUM_DAC_CHANNELS; i++){ pDevice->pCard->dac[i] = MOTENC_DAC_COUNT_ZERO; } // Unmap card. iounmap((void *)(pDevice->pCard)); // TODO: Free device object when HAL supports free.// hal_free(pDevice); } }}/****************************************************************************** * DEVICE OBJECT FUNCTION DEFINITIONS ******************************************************************************//* * LOCAL FUNCTIONS */static intDevice_Init(Device *this, MotencRegMap *pCard){ int i, status; this->pCard = pCard; this->adcState = 0; this->watchdogControl = 0; // Identify type of board. status = pCard->fpga[0].boardVersion; if ( status == 0 ) { // MOTENC-100. this->boardType = 1; this->pTypeName = "MOTENC-100"; this->numFpga = 2; } else if ( status == 1 ) { // MOTENC-Lite. this->boardType = 2; this->pTypeName = "MOTENC-Lite"; this->numFpga = 1; } else { // No idea what it is. this->boardType = 0; this->pTypeName = "unknown"; this->numFpga = 0; return -1; } // Extract board id from first FPGA. The user sets this via jumpers on the card. status = pCard->fpga[0].statusControl; this->boardID = (status & MOTENC_STATUS_BOARD_ID) >> MOTENC_STATUS_BOARD_ID_SHFT; // Initialize hardware. for(i = 0; i < this->numFpga; i++){ pCard->fpga[i].digitalIo = MOTENC_DIGITAL_OUT; pCard->fpga[i].statusControl = MOTENC_CONTROL_ENCODER_RESET; } for(i = 0; i < MOTENC_NUM_DAC_CHANNELS; i++){ pCard->dac[i] = MOTENC_DAC_COUNT_ZERO; } pCard->timerIrqDisable = 1; pCard->watchdogControl = this->watchdogControl; return(0);}static intDevice_ExportPinsParametersFunctions(Device *this, int componentId){ int msgLevel, boardId, error; // 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. msgLevel = rtapi_get_msg_level(); rtapi_set_msg_level(RTAPI_MSG_WARN); boardId = this->boardID; // Export encoders. error = Device_ExportEncoderPinsParametersFunctions(this, componentId, boardId); // Export DACs. if(!error) error = Device_ExportDacPinsParametersFunctions(this, componentId, boardId); // Export ADCs. if(!error) error = Device_ExportAdcPinsParametersFunctions(this, componentId, boardId); // Export digital I/O. if(!error) error = Device_ExportDigitalInPinsParametersFunctions(this, componentId, boardId); if(!error) error = Device_ExportDigitalOutPinsParametersFunctions(this, componentId, boardId); // Export miscellaneous. if(!error) error = Device_ExportMiscPinsParametersFunctions(this, componentId, boardId); // Restore saved message level. rtapi_set_msg_level(msgLevel); return(error);}static intDevice_ExportEncoderPinsParametersFunctions(Device *this, int componentId, int boardId){ int halError, channel; char name[HAL_NAME_LEN + 2]; // Export pins and parameters. halError = 0; for(channel = 0; channel < this->numFpga * MOTENC_FPGA_NUM_ENCODER_CHANNELS; channel++){ // Pins. rtapi_snprintf(name, HAL_NAME_LEN, "motenc.%d.enc-%02d-count", boardId, channel); if((halError = hal_pin_s32_new(name, HAL_OUT, &(this->encoder[channel].pCount), componentId)) != 0) break; rtapi_snprintf(name, HAL_NAME_LEN, "motenc.%d.enc-%02d-position", boardId, channel); if((halError = hal_pin_float_new(name, HAL_OUT, &(this->encoder[channel].pPosition), componentId)) != 0) break; rtapi_snprintf(name, HAL_NAME_LEN, "motenc.%d.enc-%02d-index", boardId, channel); if((halError = hal_pin_bit_new(name, HAL_OUT, &(this->encoder[channel].pIndex), componentId)) != 0) break; rtapi_snprintf(name, HAL_NAME_LEN, "motenc.%d.enc-%02d-index-enable", boardId, channel); if((halError = hal_pin_bit_new(name, HAL_IO, &(this->encoder[channel].pIndexEnable), componentId)) != 0) break; rtapi_snprintf(name, HAL_NAME_LEN, "motenc.%d.enc-%02d-reset", boardId, channel); if((halError = hal_pin_bit_new(name, HAL_IN, &(this->encoder[channel].pReset), componentId)) != 0) break; // Parameters. rtapi_snprintf(name, HAL_NAME_LEN, "motenc.%d.enc-%02d-scale", boardId, channel); if((halError = hal_param_float_new(name, HAL_RW, &(this->encoder[channel].scale), componentId)) != 0) break; // Init encoder.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -