From 64dafb749804d157eb6883f6523d8458d95f544b Mon Sep 17 00:00:00 2001 From: kpetersn Date: Thu, 4 Apr 2019 16:52:17 -0500 Subject: [PATCH] Removed HytecSrc; Added motorHytec submodule --- .gitmodules | 3 + modules/Makefile | 3 + modules/motorHytec | 1 + motorApp/HytecSrc/Copyright.doc | Bin 30720 -> 0 bytes motorApp/HytecSrc/HytecMotorControl.db | 72 -- motorApp/HytecSrc/HytecMotorDriver.cpp | 1116 ------------------------ motorApp/HytecSrc/HytecMotorDriver.dbd | 4 - motorApp/HytecSrc/HytecMotorDriver.h | 222 ----- motorApp/HytecSrc/Makefile | 25 - motorApp/HytecSrc/README_Hy8601Asyn | 510 ----------- motorApp/Makefile | 6 - 11 files changed, 7 insertions(+), 1955 deletions(-) create mode 160000 modules/motorHytec delete mode 100755 motorApp/HytecSrc/Copyright.doc delete mode 100644 motorApp/HytecSrc/HytecMotorControl.db delete mode 100644 motorApp/HytecSrc/HytecMotorDriver.cpp delete mode 100644 motorApp/HytecSrc/HytecMotorDriver.dbd delete mode 100644 motorApp/HytecSrc/HytecMotorDriver.h delete mode 100644 motorApp/HytecSrc/Makefile delete mode 100644 motorApp/HytecSrc/README_Hy8601Asyn diff --git a/.gitmodules b/.gitmodules index f1c9286b..72db1047 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "modules/motorFaulhaber"] path = modules/motorFaulhaber url = https://github.com/epics-motor/motorFaulhaber.git +[submodule "modules/motorHytec"] + path = modules/motorHytec + url = https://github.com/epics-motor/motorHytec.git diff --git a/modules/Makefile b/modules/Makefile index 1b1ba24d..0e2d2454 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -9,6 +9,9 @@ SUBMODULES += motorAcsTech80 SUBMODULES += motorAttocube SUBMODULES += motorDeltaTau SUBMODULES += motorFaulhaber +ifdef IPAC +SUBMODULES += motorHytec +endif # Allow sites to add extra submodules -include Makefile.local diff --git a/modules/motorHytec b/modules/motorHytec new file mode 160000 index 00000000..17b57f75 --- /dev/null +++ b/modules/motorHytec @@ -0,0 +1 @@ +Subproject commit 17b57f757a9174c014583889587b937d751990c7 diff --git a/motorApp/HytecSrc/Copyright.doc b/motorApp/HytecSrc/Copyright.doc deleted file mode 100755 index bd00c2d824d56f54ddd9ffaaa364a737b625b1f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30720 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 0. */ -/* */ -/********************************************************************************/ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "HytecMotorDriver.h" -#include - -static void ISR_8601(int pDrv); -static void intQueuedTask( void *pDrv ); - -#define MAX_MESSAGES 100 /* maximum number of messages */ -#define ENCODER_HARD_RATIO 0.25 /* encoder hardware ratio, it is 1/4 since the quadrature encoder */ - - -// Constructor -HytecMotorController::HytecMotorController(const char *portName, int numAxes, - double movingPollPeriod, double idlePollPeriod, int cardnum, - int ip_carrier, int ipslot, int vector, int useencoder, - double encoderRatio0, double encoderRatio1, double encoderRatio2, - double encoderRatio3) - : asynMotorController(portName, numAxes, NUM_HYTEC_PARAMS, - asynInt32Mask | asynFloat64Mask | asynUInt32DigitalMask, - asynInt32Mask | asynFloat64Mask | asynUInt32DigitalMask, - ASYN_CANBLOCK | ASYN_MULTIDEVICE, - 1, // autoconnect - 0, 0) // Default priority and stack size -{ - int axis; - double encoderRatio[4]; - asynStatus status; - HytecMotorAxis *pAxis; - static const char *functionName = "HytecMotorController"; - - encoderRatio[0] = encoderRatio0; - encoderRatio[1] = encoderRatio1; - encoderRatio[2] = encoderRatio2; - encoderRatio[3] = encoderRatio3; - - // Check the validity of the arguments - // Is Interrupt Vector Valid... - if (vector <= 0 || vector > 255) - { - asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, - "%s:%s: illegal interrupt vector number. must be in range [1..255]\n", - driverName, functionName); -// printf("ERROR! illegal interrupt vector number %d !\n", vector); - } - - if (numAxes < 1 ) numAxes = 1; - this->numAxes = numAxes; - this->card = cardnum; - this->ip_carrier = ip_carrier; - this->ipslot = ipslot; - this->vector = vector & 0xFF; - this->ip_carrier = ip_carrier; - this->useencoder = useencoder; - - // Create controller-specific parameters - createParam(HytecPowerControlString, asynParamInt32, &this->HytecPowerControl_); - createParam(HytecBrakeControlString, asynParamInt32, &this->HytecBrakeControl_); - createParam(HytecFirmwareString, asynParamInt32, &this->HytecFWVersion_); - createParam(HytecMoveAllString, asynParamInt32, &this->HytecMoveAll_); - - if ((status = SetupCard()) != asynSuccess) - { - asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, - "%s:%s: setup motor IP card failed.\n", - driverName, functionName); - } - - for (axis=0; axisintMsgQId = epicsMessageQueueCreate(MAX_MESSAGES, (this->numAxes + 2)*sizeof(int)); - if (epicsThreadCreate("drvHy8601intQueuedTask", - epicsThreadPriorityLow, - epicsThreadGetStackSize(epicsThreadStackMedium), - (EPICSTHREADFUNC)intQueuedTask, - (void *) this) == NULL) - { - asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, - "%s:%s: drvHy8601intQueuedTask epicsThreadCreate failure.\n", - driverName, functionName); - } - - startPoller(movingPollPeriod, idlePollPeriod, 2); -} - -// set up IP card -asynStatus HytecMotorController::SetupCard() -{ - char *regbase; - int st; - static const char *functionName = "SetupCard"; - - /* Register the card in A16 address space */ - regbase=(char*)ipmBaseAddr( this->ip_carrier, - this->ipslot, - ipac_addrIO); - - /* If failed to register card... */ - if (regbase == NULL) - { - asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, - "%s:%s: Cannot register Hy8601 A16 device.\n", - driverName, functionName); - return asynError; - } - - /* Memory Check OK, so check PROM */ - /* JSC. checkprom returns 1 = ok, 0 = failed. */ - if (checkprom((char*)regbase+PROM_OFFS, PROM_MODEL)!=1) - { - return asynError; - } - - /* Setup Interrupts. */ - st=ipmIntConnect(this->ip_carrier, - this->ipslot, - this->vector, - &ISR_8601, - (long)this); - - /* If Interrupts NOT Setup OK */ - if (st!=OK) - { - asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, - "%s:%s: intConnect ERROR.\n", - driverName, functionName); - return asynError; - } - - /* Setup Carrier Card */ - ipmIrqCmd(this->ip_carrier, - this->ipslot, - 0, - ipac_irqEnable); - - this->regbase = regbase; - return asynSuccess; -} - -/********************************************************** - - NAME: checkprom() - - Description: - - Function - - 1. Check for "VITA4 " string. - 2. Check for Hytec ID. - 3. Check for IP Model (0x8601). - 4. Display Debug Information. - 5. Return whether Check PROM Successful. - - Parameters: - - Inputs: - - pr - The PROM base address (1st address of PROM). - expmodel - Expected IP Model as a Hex Value (i.e. 0x8601) - verbose - TRUE = Display Debug Information as you go. - - Outputs: None. - Return: (ishytec && ismodel) - - TRUE - Everything OK. - FALSE - Either the Hytec ID or IP Model number is wrong. - - - Notes: - - Programmer(s): Darrell Nineham - Walter Scott - Steve Hunt - -********************************************************** - -Revision History ----------------- - -Date By Version Descripition ----- -- ------- ------------ -29-MAR-2011 JSC 1.1.1.0 Intial Version. - -**********************************************************/ -int HytecMotorController::checkprom(char *pr,int expmodel) -{ - #define PR_ID 0x06 - #define PR_MODN 0x0a - #define PR_REVN 0x0c - #define PR_DRID1 0x10 - #define PR_DRID2 0x12 - #define PR_FLAGS 0x14 - #define PR_BYTES 0x16 - #define PR_SERN 0x1a - #define HYTECID 0x8003 - - char* hytecstr=" (HyTec Electronics Ltd., Reading, UK)"; - char lstr[7]; - int manid; - epicsUInt16 modelnum, word; - int ishytec,ismodel,strok, ver; - - /* Begin */ - - /* Debug - Display the passed Address */ - printf("PROM CONTENTS AT: %p\n",pr); - /* Read the first 6 Characters from the passed Address */ - word = *((epicsUInt16*)(pr+0)); - lstr[0] = (char) (word >> 8); - lstr[1] = (char) (word & 0xFF); - word = *((epicsUInt16*)(pr+2)); - lstr[2] = (char) (word >> 8); - lstr[3] = (char) (word & 0xFF); - word = *((epicsUInt16*)(pr+4)); - lstr[4] = (char) (word >> 8); - lstr[5] = 0x20; - lstr[6] = 0; - - /* Compare to Expected String (i.e. "VITA4 ") */ - strok = (strcmp(lstr, IP_DETECT_STR) == 0); - - printf("PROM header: '%6s'\n",lstr); - /* Set manid to PROM Address of the Hytec ID */ - manid = (*((epicsUInt16*)(pr+PR_ID)) << 8) + (*((epicsUInt16*)(pr+PR_ID+2)) >> 8); - /* Set ishytec to TRUE if Hytec ID is as expected */ - ishytec = (manid ==HYTECID); - /* Set modelnum to PROM Address of the IP Model */ - modelnum = *((epicsUInt16*)(pr+PR_MODN)); - /* Set ismodel to TRUE if IP Model is as expected */ - ismodel = (modelnum==expmodel); - - /* Display Assorted Information from Reading the PROM */ - printf("PROM manufacturer ID: 0x%04X",manid); - if (ishytec) printf(hytecstr); - - printf("\nPROM model #: 0x%04hx, rev. 0x%04hx, serial # %hu\n", - modelnum, - *((short int*)(pr+PR_REVN)), - *((short int*)(pr+PR_SERN))); - - printf("PROM driver ids: 0x%04hx, 0x%04hx\n", - *((short int*)(pr+PR_DRID1)), - *((short int*)(pr+PR_DRID2))); - - ver = *((short int*)(pr+PR_REVN)); - ver = ver/4096*1000 + (ver % 4096)/256*100 + ((ver % 4096) % 256)/16*10 + ((ver % 4096) % 256) % 16; - setIntegerParam( HytecFWVersion_, ver); - - printf("PROM flags: 0x%04hx\nPROM number of bytes used: 0x%04hx (%hd)\n\n", - *((short int*)(pr+PR_FLAGS)), - *((short int*)(pr+PR_BYTES)), - *((short int*)(pr+PR_BYTES))); - - - /* Debug - Print error message if string is NOT as expected */ - if (!strok) - { - printf("PROM INVALID PROM HEADER; EXPECTED '%s'\n", - IP_DETECT_STR); - } - - /* Debug - Print error message if Hytec ID is NOT as expected */ - if (!ishytec) - { - printf("PROM UNSUPPORTED MANUFACTURER ID;\nPROM EXPECTED 0x%08X, %s\n", - HYTECID,hytecstr); - } - - /* Debug - Print error message if IP Model is NOT as expected */ - if(!ismodel) - { - printf("PROM UNSUPPORTED BOARD MODEL NUMBER: EXPECTED 0x%04hx\n", - expmodel); - } - - return (/* SCO strok && */ ismodel); -} - -// report -void HytecMotorController::report(FILE *fp, int level) -{ - int axis; - HytecMotorAxis *pAxis; - double p, encoderp; - int dir, hasencoder, done, hlimit, home, fault, llimit; - - fprintf(fp, "Hytec motor driver %s, numAxes=%d, carrierNo=%d, ipslot=%d\n", - this->portName, this->numAxes, this->ip_carrier, this->ipslot); - - if (level > 0) { - for (axis=0; axisnumAxes; axis++) { - pAxis = getAxis(axis); - getDoubleParam(pAxis->axisNo_, motorPosition_, &p); - getDoubleParam(pAxis->axisNo_, motorEncoderPosition_, &encoderp); - getIntegerParam(pAxis->axisNo_, motorStatusDirection_, &dir); - getIntegerParam(pAxis->axisNo_, motorStatusHasEncoder_, &hasencoder); - getIntegerParam(pAxis->axisNo_, motorStatusDone_, &done); - getIntegerParam(pAxis->axisNo_, motorStatusHighLimit_, &hlimit); - getIntegerParam(pAxis->axisNo_, motorStatusHome_, &home); - getIntegerParam(pAxis->axisNo_, motorStatusProblem_, &fault); - getIntegerParam(pAxis->axisNo_, motorStatusLowLimit_, &llimit); - fprintf(fp, " axis %d: encoder ratio = %f\n", pAxis->axisNo_, pAxis->encoderRatio); - fprintf(fp, " abs position = %f\n", p); - fprintf(fp, " encoder position = %f\n", encoderp); - fprintf(fp, " direction = %d\n", dir); - fprintf(fp, " encoder detected = %s\n", hasencoder == 0 ? "No" : "Yes"); - fprintf(fp, " Done bit set = %s\n", done == 0 ? "No" : "Yes"); - fprintf(fp, " High limit hit = %s\n", hlimit == 0 ? "No" : "Yes"); - fprintf(fp, " Low limit hit = %s\n", llimit == 0 ? "No" : "Yes"); - fprintf(fp, " Home limit hit = %s\n", home == 0 ? "No" : "Yes"); - fprintf(fp, " Faulty = %s\n", fault == 0 ? "No" : "Yes"); - } - } - - // Call the base class method - asynMotorController::report(fp, level); -} - -// get axis -HytecMotorAxis * HytecMotorController::getAxis(asynUser *pasynUser) -{ - return dynamic_cast(asynMotorController::getAxis(pasynUser)); -} - -HytecMotorAxis * HytecMotorController::getAxis(int axisNo) -{ - return dynamic_cast(asynMotorController::getAxis(axisNo)); -} - -// Int32 read interface -asynStatus HytecMotorController::readInt32(asynUser *pasynUser, epicsInt32 *value) -{ - int function = pasynUser->reason; - asynStatus status = asynSuccess; - HytecMotorAxis *pAxis = getAxis(pasynUser); - double dvalue; - bool moving; -// static const char *functionName = "readInt32"; - - if ((function == motorPosition_) || (function == motorEncoderPosition_)) - { - //update all values and status - pAxis->poll(&moving); - getDoubleParam(pAxis->axisNo_, function, &dvalue); - *value = (int)dvalue; - }else if(function == HytecFWVersion_) - { - getIntegerParam( HytecFWVersion_, value); - }else - // Call base class call its method (if we have our parameters check this here) - status = asynPortDriver::readInt32(pasynUser, value); - return status; -} - -// Int32 write interface -asynStatus HytecMotorController::writeInt32(asynUser *pasynUser, epicsInt32 value) -{ - int function = pasynUser->reason; - asynStatus status = asynSuccess; - HytecMotorAxis *pAxis = getAxis(pasynUser); -// static const char *functionName = "writeInt32"; - - - /* Set the parameter and readback in the parameter library. This may be overwritten when we read back the - * status at the end, but that's OK */ - status = setIntegerParam(pAxis->axisNo_, function, value); - - if(function == HytecPowerControl_) - { - if(value) - CSR_SET(pAxis->chanbase, CSR_AUX1); - else - CSR_CLR(pAxis->chanbase, CSR_AUX1); - } else if(function == HytecBrakeControl_) - { - if(value) - CSR_CLR(pAxis->chanbase, CSR_AUX2); - else - CSR_SET(pAxis->chanbase, CSR_AUX2); - } else if(function == HytecMoveAll_) - { - - } else - /* Call base class call its method (if we have our parameters check this here) */ - status = asynMotorController::writeInt32(pasynUser, value); - - /* Do callbacks so higher layers see any changes */ - callParamCallbacks(pAxis->axisNo_); - return status; -} - -// Float64 write interface. This is currently useless. -asynStatus HytecMotorController::writeFloat64(asynUser *pasynUser, epicsFloat64 value) -{ - int function = pasynUser->reason; - asynStatus status = asynSuccess; - HytecMotorAxis *pAxis = getAxis(pasynUser); -// static const char *functionName = "writeFloat64"; - - /* Set the parameter and readback in the parameter library. This may be overwritten when we read back the - * status at the end, but that's OK */ - status = setDoubleParam(pAxis->axisNo_, function, value); - - /* - * The following part are not implemented in this driver but is retained here - * in case of future requirements. - */ -// if(function == motorResolution_) -// { - /* Calculate the resolution. it is initialised as 1.0. - previous_resolution = pAxis->resolution; - pAxis->resolution = value; - pAxis->softLowLimit = pAxis->resolution * pAxis->softLowLimit / previous_resolution; - pAxis->softHighLimit = pAxis->resolution * pAxis->softHighLimit / previous_resolution; */ -// } -// else if(function == motorEncRatio_) -// { - /* Calculate the encoder ratio and store. Note, encoder ratio is initialised as 1/4 since - * the hardware design counts 4 of each encoder pulse. encoderRatio is not used for 8601 - * after consulting to Ron Sluiter on 21/01/2001 - pAxis->encoderRatio = ENCODER_HARD_RATIO * value; */ -// } -// else if(function == motorLowLimit_) -// { - // Calculate the soft low limit to engineering unit. softLowLimit is not used for 8601 - //pAxis->softLowLimit = pAxis->resolution * value; -// } -// else if(function == motorHighLimit_) -// { - // Calculate the soft high limit to engineering unit. softHighLimit is not used for 8601 - //pAxis->softHighLimit = pAxis->resolution * value; -// } -// else - /* Call base class call its method (if we have our parameters check this here) */ - status = asynMotorController::writeFloat64(pasynUser, value); - - /* Do callbacks so higher layers see any changes */ - pAxis->callParamCallbacks(); - return status; -} - -// ISR8601 Routines to handle interrupts -static void ISR_8601(int pDrv) -{ - HytecMotorController *pController = (HytecMotorController*) pDrv; - HytecMotorAxis * pAxis; - volatile char * chanbase; - epicsMessageQueueId qID; - int data[4]; - int axis; - int numOfAxes; - - numOfAxes = pController->getNumAxes(); - for (axis = 0; axis < numOfAxes; axis++) - { - pAxis = pController->getAxis(axis); - chanbase = pAxis->getChanbase(); - data[axis] = GET_REG(chanbase, REG_CSR); - SET_REG(chanbase, REG_INTMASK, 0); /* disable interrupt */ - } - - /* wake up INT queue */ - qID = pController->getINTMsgQID(); - if (epicsMessageQueueTrySend(qID, data, sizeof(data)) == 0) - pController->increaseMsgSent(); - else - pController->increaseMsgFail(); -} - -// Interrupt queue task -static void intQueuedTask( void *pDrv ) -{ - HytecMotorController *pController = (HytecMotorController*) pDrv; - HytecMotorAxis * pAxis; - epicsMessageQueueId qID; - int data[4]; - int axis; - int numOfAxes, ipslot, ipcarrier; - - qID = pController->getINTMsgQID(); - numOfAxes = pController->getNumAxes(); - ipslot = pController->getIPSlot(); - ipcarrier = pController->getIPCarrier(); - - while(1) - { - /* Wait for event from interrupt routine */ - epicsMessageQueueReceive(qID, data, sizeof(data)); - - for (axis = 0; axis < numOfAxes; axis++) - { - pAxis = pController->getAxis(axis); - pController->drvHy8601GetAxisStatus( pAxis, data[axis] ); - } - - /* re-enable interrupt. for Linux IOCs */ - ipmIrqCmd(ipcarrier, ipslot, 0, ipac_irqEnable); - } -} - -// Interrupt queue task updates -void HytecMotorController::drvHy8601GetAxisStatus( HytecMotorAxis *pAxis, int csr_data ) -{ - this->lock(); - - setIntegerParam( pAxis->axisNo_, motorStatusDone_, ((csr_data & CSR_DONE) != 0 ) ); - setIntegerParam( pAxis->axisNo_, motorStatusHighLimit_, ((csr_data & CSR_MAXLMT) != 0 ) ); - setIntegerParam( pAxis->axisNo_, motorStatusHome_, ((csr_data & CSR_HOMELMT) != 0 ) ); - - if (csr_data & CSR_HOMELMT) CSR_CLR(pAxis->chanbase, CSR_HOMESTOP); /* after home limit is reported, clear Stop at home */ - - setIntegerParam( pAxis->axisNo_, motorStatusProblem_, ((csr_data & CSR_DRVSTAT) != 0) ); - setIntegerParam( pAxis->axisNo_, motorStatusLowLimit_, ((csr_data & CSR_MINLMT) != 0) ); - callParamCallbacks(pAxis->axisNo_); - - this->unlock(); -} - -int HytecMotorController::getNumAxes() -{ - return numAxes; -} - -int HytecMotorController::getIPCarrier() -{ - return ip_carrier; -} - -int HytecMotorController::getIPSlot() -{ - return ipslot; -} - -epicsMessageQueueId HytecMotorController::getINTMsgQID() -{ - return intMsgQId; -} - -void HytecMotorController::increaseMsgSent() -{ - messagesSent++; -} - -void HytecMotorController::increaseMsgFail() -{ - messagesFailed++; -} - - -/************************************************************************************** - * - * Motor Axis Methods - * - *************************************************************************************/ -// Motor Axis methods -HytecMotorAxis::HytecMotorAxis(HytecMotorController *pC, int axisNo, double ratio, int vector) - : asynMotorAxis(pC, axisNo), - pC_(pC), vector(vector), encoderRatio(ratio) -{ - InitialiseAxis(); -} - -int HytecMotorAxis::getVector() -{ - return vector; -} - -volatile char *HytecMotorAxis::getChanbase() -{ - return chanbase; -} - - -// initialise axis -asynStatus HytecMotorAxis::InitialiseAxis() -{ - volatile char *chanbase; - - // Required for the motor axis infrastructure - this->absPosition = 0; // initialise the software counter to 0 to be in line with the reset which clears the absolute position - this->desiredMove = 0; // clear desired position - this->resolution = 1.0; // initial resolution is 1 - this->softLowLimit = 0.0; // initialise soft low limit to 0 - this->softHighLimit = 0.0; // initialise soft high limit to 0 - this->times = 0; - - // Initialisation specific to this model of controller - chanbase = this->chanbase = pC_->regbase + REG_BANK_OFFS + this->axisNo_ * REG_BANK_SZ; - - // Reset Card - CSR_SET(chanbase, CSR_RESET); - CSR_CLR(chanbase, CSR_RESET); - - /* Note: the useencoder in configure overrides the encoder detection. So if the user decides not - * to use encoder by setting the useencoder param to 0 in the configure call, even there is - * an encoder present, the software will not use the encoder. If the useencoder is 1, then - * driver will use encoder but if the encoder is not present, no value will be written to the position register */ - - this->useencoder = ((pC_->useencoder & (1<axisNo_)) == 0) ? 0 : 1; - - /* check use encoder set by the configure */ - if(this->useencoder) - CSR_SET(chanbase, CSR_ENCODUSE); - - /* enable interrupt, set vector */ - /* Note, all 4 axis of 8601 have been set the same vector. - * It is the ISR's responsibility to check which axis generates the interrupt at runtime. - * If the mask of individual axis needs to be set differently, extra interface should - * be created, but they should still share the same ISR routine. */ - CSR_SET(chanbase, CSR_INTEN); - SET_REG(chanbase,REG_INTVECTOR,this->vector); - - CSR_SET(chanbase, CSR_CRASHSTOP); - epicsThreadSleep( 0.1 ); - CSR_CLR(chanbase, CSR_CRASHSTOP); - - return asynSuccess; -} - -// Move axis -asynStatus HytecMotorAxis::move(double position, int relative, double min_velocity, double max_velocity, double acceleration) -{ -// static const char *functionName = "moveAxis"; - asynStatus status = asynSuccess; - double result; - int currpos; - - if (min_velocity != 0) - { - /* Set start speed register, min_velocity is steps/s */ - SET_REG(this->chanbase, REG_STARTSTOPSPD, (int)floor(min_velocity)); - } - if (max_velocity != 0) - { - /* Set high speed register, max_velocity is steps/s */ - SET_REG(this->chanbase, REG_HIGHSPD, (int)floor(max_velocity)); - } - if (acceleration >= 64) - { - /* Set ramp register, acceleration is steps/s/s */ - SET_REG(this->chanbase, REG_RAMPRATE, (int)floor(acceleration)); - } - - if (relative) - { - /* Write to step counter register abs(position)*/ - SET_REG(this->chanbase, REG_STEPCNTLO, (abs((int)floor(position))) & 0xFFFF); - SET_REG(this->chanbase, REG_STEPCNTHI, (abs((int)floor(position))) >> 16); - /* Write dir flag based on relative position */ - if (position >= 0) - { - CSR_SET(this->chanbase, CSR_DIRECTION); - }else - { - CSR_CLR(this->chanbase, CSR_DIRECTION); - } - this->desiredMove = position; /* store desired position */ - }else - { - if(!this->useencoder) /* if encoder is not used, read the absolute position from register */ - { - currpos = GET_REG(this->chanbase, REG_CURRPOSHI) << 16; - currpos += GET_REG(this->chanbase, REG_CURRPOSLO); - } - else /* otherwise, current position is from the software variable */ - currpos = (int)this->absPosition; - - /* calculate steps to move */ - result = position - currpos; - this->desiredMove = result; /* store desired position */ - - /* Write to step counter abs(result) */ - SET_REG(this->chanbase, REG_STEPCNTLO, (abs((int)floor(result))) & 0xFFFF); - SET_REG(this->chanbase, REG_STEPCNTHI, (abs((int)floor(result))) >> 16); - /* Write dir flag based on result */ - if (result >= 0) - { - CSR_SET(this->chanbase, CSR_DIRECTION); - }else - { - CSR_CLR(this->chanbase, CSR_DIRECTION); - } - } - -/* int csr = GET_REG(this->chanbase, REG_CSR); - printf("rel=%d askp=%d currp=%d, absp=%d res=%d, csr=%x acce=%d minsp=%d maxsp=%d\n", relative, (int)position, (int)currpos, (int)this->absPosition, (int)result, csr, (int)floor(acceleration), (int)floor(min_velocity), (int)floor(max_velocity));*/ /* for debug */ - - /* Write GO bit */ - this->times = 0; /* clear done bit flag at the beginning of every move */ - CSR_SET(this->chanbase, CSR_GO); - SET_REG(this->chanbase,REG_INTMASK,DONE_INT); /* to enable interrupt */ - - pC_->lock(); - setIntegerParam(pC_->motorStatusDone_, 0); - callParamCallbacks(); - pC_->unlock(); - - return status; -} - -// Move home -asynStatus HytecMotorAxis::home(double min_velocity, double max_velocity, double acceleration, int forwards) -{ - asynStatus status = asynSuccess; -// static const char *functionName = "homeAxis"; - - if (min_velocity != 0) - { - /* Set start speed register, min_velocity is steps/s */ - SET_REG(this->chanbase, REG_STARTSTOPSPD, (int)floor(min_velocity)); - } - if (max_velocity != 0) - { - /* Set high speed register, max_velocity is steps/s */ - SET_REG(this->chanbase, REG_HIGHSPD, (int)floor(max_velocity)); - } - if (acceleration != 0) - { - /* Set ramp register, acceleration is steps/s/s */ - SET_REG(this->chanbase, REG_RAMPRATE, (int)floor(acceleration)); - } - /* Write direction bit */ - if (forwards) - { - CSR_SET(this->chanbase, CSR_DIRECTION); - }else - { - CSR_CLR(this->chanbase, CSR_DIRECTION); - } - /* Write SH bit and start moving towards home */ - CSR_SET(this->chanbase, CSR_HOMESTOP | CSR_JOG); - SET_REG(this->chanbase,REG_INTMASK,DONE_INT); /* to enable interrupt */ - - pC_->lock(); - setIntegerParam(pC_->motorStatusDone_, 0); - callParamCallbacks(); - pC_->unlock(); - - return status; -} - -// move velocity -asynStatus HytecMotorAxis::moveVelocity(double min_velocity, double max_velocity, double acceleration) -{ - asynStatus status = asynSuccess; -// static const char *functionName = "moveVelocityAxis"; - - if (min_velocity != 0) - { - /* Set start speed register, min_velocity is steps/s */ - SET_REG(this->chanbase, REG_STARTSTOPSPD, (int)floor(min_velocity)); - } - if (max_velocity != 0) - { - /* Set high speed register, velocity is steps/s */ - SET_REG(this->chanbase, REG_HIGHSPD, (int)floor(max_velocity)); - } - if (acceleration != 0) - { - /* XXXX: set ramp register, acceleration is steps/s/s */ - SET_REG(this->chanbase, REG_RAMPRATE, (int)floor(acceleration)); - } - /* Write direction bit */ - if (max_velocity >= 0) - { - CSR_SET(this->chanbase, CSR_DIRECTION); - } else - { - CSR_CLR(this->chanbase, CSR_DIRECTION); - } - /* Set Jog flag */ - CSR_SET(this->chanbase, CSR_JOG); - SET_REG(this->chanbase,REG_INTMASK,DONE_INT); /* to enable interrupt */ - - pC_->lock(); - setIntegerParam(pC_->motorStatusDone_, 0); - callParamCallbacks(); - pC_->unlock(); - - return status; -} - -// stop axis -asynStatus HytecMotorAxis::stop(double acceleration ) -{ - asynStatus status = asynSuccess; -// static const char *functionName = "stopAxis"; - int value; - unsigned int acce; - - acce = ((unsigned int)floor(acceleration)); - if (acce != 0) - { - value = GET_REG(this->chanbase, REG_RAMPRATE); - if((acce > 64) || (acce <= 0xFFFF)) - value = acce; - - /* Set ramp register, acceleration is steps/s/s */ - SET_REG(this->chanbase, REG_RAMPRATE, value); - /* Clear JOG and GO bits */ - CSR_CLR(this->chanbase, CSR_JOG | CSR_GO); - }else - { - /* Write abort bit to 1 */ - CSR_SET(this->chanbase, CSR_CRASHSTOP); - CSR_CLR(this->chanbase, CSR_CRASHSTOP); - } - - return status; -} - -// timer task updates -asynStatus HytecMotorAxis::poll(bool *moving) -{ - double position, error=0.0, stepMoved; - epicsUInt16 csr; - asynStatus status = asynSuccess; - - pC_->lock(); - - /* Get position register reading */ - position = GET_REG(this->chanbase, REG_CURRPOSHI) << 16; - position += GET_REG(this->chanbase, REG_CURRPOSLO); - - /* For calculating absolute position if encoder is used */ - csr = GET_REG(this->chanbase, REG_CSR); - error = GET_REG(this->chanbase, REG_STEPCNTHI) << 16; - error += GET_REG(this->chanbase, REG_STEPCNTLO); - - if(this->desiredMove < 0) /* move reversely */ - { - if(error >= 0) - { - stepMoved = (this->desiredMove + error) > 0 ? this->desiredMove + error : -(this->desiredMove + error); - this->desiredMove = -error; - } - else - { - stepMoved = (this->desiredMove) > 0 ? this->desiredMove : -(this->desiredMove); - this->desiredMove = 0; - } - } - else /* move forward */ - { - if(error >= 0) - { - stepMoved = this->desiredMove - error; - this->desiredMove = error; - } - else - { - stepMoved = this->desiredMove; - this->desiredMove = 0; - } - } - - if((csr & CSR_ENCODDET) && this->useencoder) /* use encoder */ - { - setDoubleParam( pC_->motorEncoderPosition_, floor(position*this->encoderRatio+0.5) ); - if(csr & CSR_DIRECTION) /* forward */ - { - if(!(csr & CSR_DONE)) - this->absPosition += stepMoved; - else - { - if(this->times == 0) - { - this->absPosition += stepMoved; - this->times = 1; /* set done bit hit the first time */ - } - SET_REG(this->chanbase, REG_STEPCNTHI, 0); - SET_REG(this->chanbase, REG_STEPCNTLO, 0); - } - setDoubleParam( pC_->motorPosition_, floor(this->absPosition+0.5) ); - }else /* reversed */ - { - if(!(csr & CSR_DONE)) - this->absPosition -= stepMoved; - else - { - if(this->times == 0) - { - this->absPosition -= stepMoved; - this->times = 1; /* set done bit hit the first time */ - } - SET_REG(this->chanbase, REG_STEPCNTHI, 0); - SET_REG(this->chanbase, REG_STEPCNTLO, 0); - } - setDoubleParam( pC_->motorPosition_, floor(this->absPosition-0.5) ); - } - }else /* do not use encoder */ - { - setDoubleParam( pC_->motorEncoderPosition_, floor(position+0.5) ); - setDoubleParam( pC_->motorPosition_, floor(position+0.5) ); - } - -/* //debug -int acc= GET_REG(this->chanbase, REG_RAMPRATE); -int lsp= GET_REG(this->chanbase, REG_STARTSTOPSPD); -int hsp=GET_REG(this->chanbase, REG_HIGHSPD); -if(this->axisNo_ == 0) -printf("%d: moved=%d, error=%d, desired=%d absp=%d csr=%x\n",this->axisNo_, (int)stepMoved, (int)error , (int)this->desiredMove, (int)this->absPosition, (int)csr); -*/ - setIntegerParam( pC_->motorStatusDirection_, ((csr & CSR_DIRECTION) != 0 ) ); - setIntegerParam( pC_->motorStatusHasEncoder_, ((csr & CSR_ENCODDET) != 0) ); - - *moving = (csr & CSR_DONE) != 0 ? true : false; - setIntegerParam( pC_->motorStatusDone_, ((csr & CSR_DONE) != 0 ) ); - setIntegerParam( pC_->motorStatusHighLimit_, ((csr & CSR_MAXLMT) != 0 ) ); - setIntegerParam( pC_->motorStatusHome_, ((csr & CSR_HOMELMT) != 0 ) ); - setIntegerParam( pC_->motorStatusProblem_, ((csr & CSR_DRVSTAT) != 0) ); - setIntegerParam( pC_->motorStatusLowLimit_, ((csr & CSR_MINLMT) != 0) ); - - callParamCallbacks(); - pC_->unlock(); - return status; -} - -asynStatus HytecMotorAxis::setPosition(double position) -{ - asynStatus status = asynSuccess; - - if(this->useencoder) /* use encoder */ - this->absPosition = position; /* update the software absolute position, note if encoder is not present, this is not used */ - else - { - SET_REG(this->chanbase, REG_CURRPOSLO, ((int)floor(position)) & 0xFFFF); - SET_REG(this->chanbase, REG_CURRPOSHI, ((int)floor(position)) >> 16); - } - - return status; -} - - - -/** - * Configure the Hy8601 card - * - * This simply creates a HytecMotorController object and - * the constructor does everything for initialisation. - * - * @param portName asyn port name - * @param numAxes number of axis on the IP card - * @param movingPollPeriod The time in ms between polls when any axis is moving - * @param idlePollPeriod The time in ms between polls when no axis is moving - * @param cardnum Arbitrary card number to assign to this controller - * @param ip_carrier which previously configured IP carrier in the IOC - * @param ipslot which IP Slot on carrier card (0=A etc.) - * @param vector which Interrupt Vector (0 - Find One ?) - * 8601 interrupt mask is always set to 0x2000. Even though the logical AND of bits in this - * register and those in the CSR will cause the channel and then the IP module - * to generate an interrupt on IRQ0 as the graph below - * - * bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - * * | * | DN | * | * | * | * | * | * | * | * | FLT | HLIM | +LIM | -LIM | * | - * - * we only set Done bit to generate interrupt since no matter which bit of FLT, HLIM, +LIM - * or -LIM is set, the Done bit is set. As such, the interrupt source is identified by the - * ISR. Note, there is no interrupt clear concept. To stop the interrupt, we need to clear - * the mask bit. This means we need to enable the mask bit to enable the interrupt every time - * after a GO command which will also knock down the Done bit. - * - * @param useencoder - the least 4 bits determine to the 4 axes to use encoder when set (=1) - * @param encoderRatio0 ~ encoderRatio3 - hardware encoder ratio. For example, a quardrature encoder would - * have its ratio of 0.25 since every line generates 4 counts. - * - */ -extern "C" int Hytec8601Configure(const char *portName, - int numAxes, - int movingPollPeriod, - int idlePollPeriod, - int cardnum, - int ip_carrier, - int ipslot, - int vector, - int useencoder, - double encoderRatio0, - double encoderRatio1, - double encoderRatio2, - double encoderRatio3) -{ - HytecMotorController *pHytecMotorController - = new HytecMotorController(portName, numAxes, movingPollPeriod/1000., idlePollPeriod/1000., - cardnum, ip_carrier, ipslot, vector, useencoder, encoderRatio0, - encoderRatio1, encoderRatio2, encoderRatio3); - pHytecMotorController = NULL; - return(asynSuccess); -} - -extern "C" -{ - -static const iocshArg Hy8601ConfigArg0 = {"portName", iocshArgString}; -static const iocshArg Hy8601ConfigArg1 = {"numAxes", iocshArgInt}; -static const iocshArg Hy8601ConfigArg2 = {"movingPollPeriod", iocshArgInt}; -static const iocshArg Hy8601ConfigArg3 = {"idlePollPeriod", iocshArgInt}; -static const iocshArg Hy8601ConfigArg4 = {"cardnum", iocshArgInt}; -static const iocshArg Hy8601ConfigArg5 = {"carrier", iocshArgInt}; -static const iocshArg Hy8601ConfigArg6 = {"ipslot", iocshArgInt}; -static const iocshArg Hy8601ConfigArg7 = {"vector", iocshArgInt}; -static const iocshArg Hy8601ConfigArg8 = {"useencoder", iocshArgInt}; -static const iocshArg Hy8601ConfigArg9 = {"encoderRatio0", iocshArgDouble}; -static const iocshArg Hy8601ConfigArg10 = {"encoderRatio1", iocshArgDouble}; -static const iocshArg Hy8601ConfigArg11 = {"encoderRatio2", iocshArgDouble}; -static const iocshArg Hy8601ConfigArg12 = {"encoderRatio3", iocshArgDouble}; - -static const iocshArg * const Hy8601ConfigArgs[] = {&Hy8601ConfigArg0, - &Hy8601ConfigArg1, - &Hy8601ConfigArg2, - &Hy8601ConfigArg3, - &Hy8601ConfigArg4, - &Hy8601ConfigArg5, - &Hy8601ConfigArg6, - &Hy8601ConfigArg7, - &Hy8601ConfigArg8, - &Hy8601ConfigArg9, - &Hy8601ConfigArg10, - &Hy8601ConfigArg11, - &Hy8601ConfigArg12}; - -static const iocshFuncDef configHy8601 = {"Hytec8601Configure", 13, Hy8601ConfigArgs}; -static void configHy8601CallFunc(const iocshArgBuf *args) -{ - Hytec8601Configure(args[0].sval, args[1].ival, args[2].ival, args[3].ival, args[4].ival, - args[5].ival, args[6].ival, args[7].ival, args[8].ival, args[9].dval, - args[10].dval, args[11].dval, args[12].dval); -} - -static void Hytec8601Register(void) -{ - iocshRegister(&configHy8601, configHy8601CallFunc); -} - -epicsExportRegistrar(Hytec8601Register); - -} diff --git a/motorApp/HytecSrc/HytecMotorDriver.dbd b/motorApp/HytecSrc/HytecMotorDriver.dbd deleted file mode 100644 index a35acebf..00000000 --- a/motorApp/HytecSrc/HytecMotorDriver.dbd +++ /dev/null @@ -1,4 +0,0 @@ -# Database Definition -registrar(Hytec8601Register) - - diff --git a/motorApp/HytecSrc/HytecMotorDriver.h b/motorApp/HytecSrc/HytecMotorDriver.h deleted file mode 100644 index 95c6b8c2..00000000 --- a/motorApp/HytecSrc/HytecMotorDriver.h +++ /dev/null @@ -1,222 +0,0 @@ -/********************************************************************************/ -/* H H Y Y TTTTT EEEEE CCC HYTEC ELECTRONICS LTD */ -/* H H Y Y T E C 5 Cradock Road, */ -/* HHHHH Y T EEE C Reading, Berks. Tel: 0118 9757770 */ -/* H H Y T E C RG2 0JT Fax: 0118 9757566 */ -/* H H Y T EEEEE CCC Web: www.hytec-electronics.co.uk */ -/********************************************************************************/ -/********************************************************************************/ -/* _____________________________________________________________________ */ -/* | H Y T E C 8 6 0 1 S T E P M O T E R A s y n D r i v e r | */ -/* --------------------------------------------------------------------- */ -/* */ -/* Source file name :- HytecMotorDriver.c */ -/* */ -/* Initial creation date :- 29-Mar-2011 */ -/* */ -/* Original Developers :- Jim Chen. Hytec Electronics Ltd */ -/* */ -/********************************************************************************/ -/* */ -/* Description :- This is the "model 3" asyn motor driver for Hytec 8601 */ -/* Stepper Motor IP module. The code is based on original */ -/* Hytec drvHy8601asyn.c driver and also Mark Rivers' */ -/* ACRMotorDriver. */ -/* */ -/* */ -/* (C)2011 Hytec Electronics Ltd. */ -/* */ -/********************************************************************************/ -/* */ -/* Revision history: (comment and initial revisions) */ -/* */ -/* vers. revised modified by date */ -/* ----- ----------- ---------------- --------------- */ -/* 2.0 Continued version Jim Chen 29/03/2011 */ -/* The main contents of this driver are the same as the original */ -/* Hytec drvHy8601asyn.c driver but in "model 3" form as defined */ -/* by Mark Rivers. Hence it starts from version 2.0. */ -/* 2.1 New interfaces Jim Chen 04/04/2011 */ -/* This version follows the asyn motor model 3 latest interface */ -/* changes that include: */ -/* a).New asynMotorAxis base class */ -/* b).Moves the axis specific functions from the motor controller */ -/* class to individual axis class */ -/* c).Changes asynMotorDriver.cpp to asynMotorController.cpp. */ -/* 2.2 Bugs fix Jim Chen 14/04/2011 */ -/* Fixed setPosition bug */ -/* Added firmware version parameter */ -/* */ -/********************************************************************************/ - -#include "asynMotorController.h" -#include "asynMotorAxis.h" - -static const char *driverName = "HytecMotorDriver"; - -/* CSR Register bit definitions */ -#define CSR_HOMESTOP 0x8000 -#define CSR_INTEN 0x4000 -#define CSR_DONE 0x2000 -#define CSR_CRASHSTOP 0x1000 -#define CSR_DIRECTION 0x0800 -#define CSR_AUX2 0x0400 -#define CSR_AUX1 0x0200 -#define CSR_ENCODUSE 0x0100 -#define CSR_ENCODDET 0x0080 -#define CSR_JOG 0x0040 -#define CSR_GO 0x0020 -#define CSR_DRVSTAT 0x0010 -#define CSR_HOMELMT 0x0008 -#define CSR_MAXLMT 0x0004 -#define CSR_MINLMT 0x0002 -#define CSR_RESET 0x0001 - -/* New Hardware Register Map */ -#define REG_STEPCNTLO 0x00 -#define REG_STEPCNTHI 0x02 -#define REG_CURRPOSLO 0x04 -#define REG_CURRPOSHI 0x06 -#define REG_STARTSTOPSPD 0x08 -#define REG_HIGHSPD 0x0A -#define REG_RAMPRATE 0x0C -#define REG_CSR 0x0E -#define REG_INTMASK 0x10 -#define REG_INTVECTOR 0x12 -#define REG_INTREQUEST 0x14 -#define REG_CURRENTSPD 0x16 -#define REG_SPARE1 0x18 -#define REG_SPARE2 0x1A -#define REG_SPARE3 0x1C -#define REG_SPARE4 0x1E - -#define PROM_MODEL 0x8601 -#define PROM_OFFS 0x80 - -#define REG_BANK_OFFS 0x00 -#define REG_BANK_SZ 0x20 - -#define INT_LMT (CSR_MINLMT | CSR_MAXLMT | CSR_HOMELMT) -#define INT_SRCS (CSR_RESET | INT_LMT | CSR_DRVSTAT | CSR_DONE) - -/* define a mask to enable all sources of interrupts */ -#define ALL_INTS (INT_SRCS | CSR_INTEN) -#define DONE_INT (CSR_DONE) /* the only interrupt suggested to use. JC 12-Nov-2009 */ - -#define HY8601_NUM_AXES 4 - -#define IP_DETECT_STR "VITA4 " - -#define GET_REG(base,reg) (*(volatile epicsUInt16 *)((base)+(reg))) -#define SET_REG(base,reg,val) do { *(volatile epicsUInt16 *)((base)+(reg)) = (val);} while(0) -#define CSR_SET(base,bit) do { *(volatile epicsUInt16 *)((base)+REG_CSR) |= (bit);} while(0) -/* Please NOTE, The DONE bit is cleared by either ORing an "1" or ANDing an "1" (if it is already "1") to it. - * Yet neither ORing nor ANDing it with "0" would affect it. As such, clearing any other bit in the CSR with - * the AND operation need to be very careful so that it doesn't knock down the DONE bit. This is why in the - * following macro after inverting the bit in the CSR, we clear the DONE bit to the inversion result in order - * not to affect the DONE bit. */ -#define CSR_CLR(base,bit) do { *(volatile epicsUInt16 *)((base)+REG_CSR) &= ((~(bit)) & 0xDFFF);} while(0) - - -#define HytecPowerControlString "HYTEC_POWER" -#define HytecBrakeControlString "HYTEC_BRAKE" -#define HytecFirmwareString "HYTEC_FWVERSION" -#define HytecMoveAllString "HYTEC_MOVEALL" - - -class HytecMotorAxis : public asynMotorAxis -{ -public: - HytecMotorAxis(class HytecMotorController *pC, int axis, double ratio, int vector); - asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration); - asynStatus moveVelocity(double min_velocity, double max_velocity, double acceleration); - asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards); - asynStatus stop(double acceleration); - asynStatus poll(bool *moving); - asynStatus setPosition(double position); - int getVector(); - volatile char * getChanbase(); - //the following are called from non-member function so they are here - -private: - asynStatus InitialiseAxis(); - HytecMotorController *pC_; - - volatile char *chanbase; - int vector; - - int useencoder; - double encoderRatio; /**< (double) Number of encoder counts in one motor count (encoder counts/motor counts) */ - double resolution; /**< (double) Number of motor units per engineering unit */ - double softLowLimit; /**< (double) Low soft limit in motor units ???? Shouldn't these two in engineering unit? */ - double softHighLimit; /**< (double) High soft limit in motor units ???? */ - double absPosition; - double desiredMove; - int times; /* to remember the the done bit set the first time */ - int absAskingPosition; - - -friend class HytecMotorController; -}; - - -class HytecMotorController : asynMotorController -{ -public: - HytecMotorController(const char *portName, int numAxes, double movingPollPeriod, - double idlePollPeriod, int cardnum, int ip_carrier, int ipslot, - int vector, int useencoder, double encoderRatio0, double encoderRatio1, - double encoderRatio2, double encoderRatio3); - - // These are the methods that we override from asynMotorDriver - asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value); - asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); - asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value); - void report(FILE *fp, int level); - - HytecMotorAxis* getAxis(asynUser *pasynUser); - HytecMotorAxis* getAxis(int axisNo); - - //the following are called from non-member function so they are here - void drvHy8601GetAxisStatus( HytecMotorAxis *pAxis, int csr_data ); - int getNumAxes(); - int getIPCarrier(); - int getIPSlot(); - epicsMessageQueueId getINTMsgQID(); - void increaseMsgSent(); - void increaseMsgFail(); - - -protected: - // New function codes - int HytecPowerControl_; -#define FIRST_HYTEC_PARAM HytecPowerControl_ - int HytecBrakeControl_; - int HytecFWVersion_; - int HytecMoveAll_; -#define LAST_HYTEC_PARAM HytecMoveAll_ - -#define NUM_HYTEC_PARAMS (&LAST_HYTEC_PARAM - &FIRST_HYTEC_PARAM + 1) - -private: - asynStatus SetupCard(); - int checkprom(char *pr,int expmodel); - - int numAxes; - epicsMessageQueueId intMsgQId; - int messagesSent; // for report - int messagesFailed; // for report - int ip_carrier; - int ipslot; - - asynUser *pasynUser; - - int card; - int vector; - int useencoder; - volatile char *regbase; - - epicsThreadId motorThread; - -friend class HytecMotorAxis; -}; diff --git a/motorApp/HytecSrc/Makefile b/motorApp/HytecSrc/Makefile deleted file mode 100644 index f4e1618c..00000000 --- a/motorApp/HytecSrc/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -TOP=../.. - -include $(TOP)/configure/CONFIG - -# ------------------------------- -# Build HytecMotor Module Library -# ------------------------------- - -LIBRARY_IOC += HytecMotor - -DBD += HytecMotorDriver.dbd - -# The following are compiled and added to the support library -HytecMotor_SRCS += HytecMotorDriver.cpp - -INC += HytecMotorDriver.h - -# We need to link this IOC Application against the EPICS Base libraries -HytecMotor_LIBS += motor -HytecMotor_LIBS += asyn Ipac -HytecMotor_LIBS += $(EPICS_BASE_IOC_LIBS) - -# --------------------------------------------------- - -include $(TOP)/configure/RULES diff --git a/motorApp/HytecSrc/README_Hy8601Asyn b/motorApp/HytecSrc/README_Hy8601Asyn deleted file mode 100644 index 47445d62..00000000 --- a/motorApp/HytecSrc/README_Hy8601Asyn +++ /dev/null @@ -1,510 +0,0 @@ -*********************************************************************************** -Hytec 8601 Step Motor Controller Asyn Driver Notes - -Author: Jim Chen, Hytec Electronics Ltd - jim.chen@hytec-electronics.co.uk - -First Initial: 12/NOV/2010 -Last updated: 29/FEB/2012 - -Modification note: -22/FEB/2012 - corrected memory offset calculation errors reported by Ernest Williams SLAC. -29/FEB/2012 - added coverage for all cases when setting up the MEMOFFS for 8002 carrier. - -This driver is based on "model 3" motor asyn driver defined by Mark Rivers. -*********************************************************************************** - -Support modules -=============== - -1). asyn driver version asyn4-13-1 or later. - -2). ipac module version ipac-2.11 plus one of the Hytec carrier card drivers such as - drvHy8002.c for VxWorks or RTEMS under VME64x with 8002/8003/8004 carriers, - drvHyLinuxCarrier.c for Linux with IOC9010/PCIe6335/uTCA7002 carriers, - drvHyRTEMSCarrier.c for RTEMS with IOC9010 blade. - -3). devLib2 version 2.1 or later if using RTEMS on IOC9010 blade. - -4). motor module version later than motorR6-5-1. Currently the 'model 3' version can be - downloaded from subversion https://subversion.xor.aps.anl.gov/synApps/motor/trunk. - This will be formally released some stage on the official EPICS website. - -5). EPICS core R3.14.8.2 or later. - -6). RTEMS R4.9.4 or later. - - -Hytec 8002/8003/8004 carrier card configuration -=============================================== - -This board is a 6U VME64x carrier card. It provides four single size IP slots and -is configurable for many parameters. It supports interrupt level from 0 to 7. Any -IP cards can be enabled/disabled interrupt. The clock can be set to either 8MHz or -32MHz. For IPAC Memory space if required, the base address can be defined automatically -by geographical addressing when VME64x crate is used. For other type of crates, -the base address can be set by configuring a series of jumpers on the board or by -passing parameter to the memory offset register in the ipacAddCarrier call. - -The IPAC Carrier Driver for this board is found in the file drvHy8002.c which -implements two commands ipacAddHy8002 and Hy8002CarrierInfo. The ipacAddHy8002 -command is used to add a Hytec 8002/8003 board to the system. The Hy8002CarrierInfo -reports hardware information for a specified board or all boards in the system if -the parameter passed down is 0xFFFF. These commands are registered by the registrar -routine Hy8002Registrar to add them to the iocsh and link the driver into a final -IOC executable, for which it must be listed in the IOC's .dbd file thus: - - registrar(Hy8002Registrar) - - -1). Configuration Command and Parameter --------------------------------------- - -- int ipacAddHYy8002(const char *cardParams); - -The parameter string should comprise two (2) to six (6) parameters which are comma -separated. The first two are mandate and have to be separated only by one comma. -The others are key/value pairs and are optional as per the conditions of the operating -system used. The format is defined as - -s,i,IPMEM=d,IPCLCK=d,ROAK=d,MEMOFFS=d - -where d is a decimal integer number. -s defines the VME slot number of the carrier card. Valid number is 2 ~ 21. - this number MUST be the same as the VME slot number where the carrier - card is plugged in. -i defines the interrupt level. Valid number is 0 ~ 7. -IPMEM=d defines the maximum memory size of the IP module. The valid values are 1, 2, - 4 or 8 that represent 1MB, 2MB, 4MB or 8MB respectively. Default is 1. For - majority Hytec ADCs, DACs such as 8401, 8414, 8417, 8402 and 8415 etc, they - all have 2MB on board. The user can choose to use either 1MB or 2MB. None of - the Hytec IPs has more than 2MB on board memory. Other vendors might have. -IPCLCK=d defines the clock that its value has to be either 8 for 8MHz or 32 for - 32Mhz. Default is 8. -ROAK=d if d =1, it defines carrier card to release the interrupt upon the - acknowledgment. If d=0, the interrupt is released by user interrupt - service routine. Default is 0. -MEMOFFS=d this parameter defines the A32 memory access base address. "d" is a decimal - number that represents the offset (the upper WORD) of the A32 base address. - It is needed when any of the two statements below is true: - - A. The operating system either VxWorks or RTEMS has defined a non-zero - VME_A32_MSTR_LOCAL macro in the system config.h file. - - B. The VME crate is not geographical addressing facilitated. In such a system, - user must use this to set up base address for A32. - - For a VME crate that is geographical addressing facilitated, and the system - defines a non-zero VME_A32_MSTR_LOCAL macro, then it is needed. But if - VME_A32_MSTR_LOCAL macro is defined as 0, then this is optional. Setting this - the driver will turn off the carrier card geographical addressing by setting - a bit in the CSR. - -Note: MEMOFFS has nothing to do with A16 base address formation. A16 base address - is determined either by geographical addressing or by carrier board on board - jumpers settings. For VME crate that is not geographical addressing facilitated, - both 8002 and 8004 carriers need to use on board jumpers (J6~J10) to set up - (On 8004 carrier, moving the jumpers to "manual" positions). When the VME - crate is geographical addressing facilitated, for 8002 carrier, A16 base - address is determined by the crate geographical addressing facility, i.e. - determined automatically by the slot number where the carrier is plugged in - (the actually A16 base address is determined as vmeslotnumber << 11). But for - 8004 carrier, user can have a choice to either use the on board jumpers to - manually set up (moving jumpers J6~J10 away from "auto" to "manual" positions) - or let the the geographical addressing to determine it (keep all J6 ~ J10 to - "auto" position). - -Calcualtion of MEMOFFS: - -As mentioned above, MEMOFFS setting represents the upper WORD of A32 VME address. Two -things need to be considered when doing the calculation: IPMEM setting and the the -VME_A32_MSTR_LOCAL macro definition in the config.h file of the BSP. - -IPMEM defines the memory size per IP card. Either 8002 or 8004 has up to 4 IPs so -the carrier memory size is 4 times of the IP memory. The minimum size of an IP, which -is also the default setting (if IPMEM is not defined), is 1MB. Hence the MEMOFFS -should start from address line A22 as shown below - -MEMOFFS BIT 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 - A31 A30 A29 A28 A27 A26 A25 A24 A23 A22 0 0 0 0 0 0 - -The MEMOFFS must be defined such that any two carriers in the same crate shuoldn't -have overlapped memory area. So when IPMEM changes, the starting address line for -calculating MEMOFFS changes as well as illustrated below: - - IPMEM memory per IP carrier memory size starting address line - 1 1MB 4MB A22 - 2 2MB 8MB A23 - 4 4MB 16MB A24 - 8 8MB 32MB A25 - -all address lines below this starting address must be 0. - -VME_A32_MSTR_LOCAL macro is the system base and it just needs to be added on to the -calculation. - -In principle, calculating MEMOFFS doesn't have to correspond it to VME slot number -that the carrier is plugged in. The only thing matters is as said that any two MEMOFFS -settings for any two carriers in the same crate should not overlap. Yet associating -the VME slot number in the calculation just makes better logical sense and fits the -natual of human being's thinking. Some examples are shown below. - -Let's assume IPMEM=1 (the default setting), this gives 4MB memory space for a 8002 -carrier so starting address line is A22. The remaining must be 0. - -MEMOFFS BIT 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 - A31 A30 A29 A28 A27 A26 A25 A24 A23 A22 0 0 0 0 0 0 - -For a carrier in VME slot 2, we can define its A32 base address as 0x00400000, -plus VME_A32_MSTR_LOCAL. For VME slot 3, it could be 0x00800000 plus VME_A32_MSTR_LOCAL -and for VME slot 4, it could be 0x00C00000 plus VME_A32_MSTR_LOCAL and so forth. - -Assuming VME_A32_MSTR_LOCAL is 0x20000000, then for VME slot 4, the calculated base -address should be 0x00C00000 + 0x20000000 = 0x20C000000. Hence the MEMOFFS = 8384 -(decimal, i.e. 0x20C0). For slot 5, the derived base address could be 0x01000000 + -0x20000000 = 0x21000000. Hence the MEMOFFS = 8448 (decimal, i.e. 0x2100) and so forth. - -Now if IPMEM=2, this gives 8MB memory space for each 8002 carrier so the starting address -line is A23. The remaining must be 0. - -MEMOFFS BIT 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 - A31 A30 A29 A28 A27 A26 A25 A24 A23 0 0 0 0 0 0 0 - -For a carrier in VME slot 2, we could define its A32 base address as 0x00800000 -plus VME_A32_MSTR_LOCAL. For VME slot 3, the base address could be 0x01000000 plus -VME_A32_MSTR_LOCAL and for VME slot 4, the base address could be 0x01800000 plus -VME_A32_MSTR_LOCALand so forth. - -Assuming VME_A32_MSTR_LOCAL is still 0x20000000, then for VME slot 4, the calculated -base address should be 0x01800000 + 0x20000000 = 0x218000000. Hence the MEMOFFS = 8576 -(decimal, i.e. 0x2180). For slot 5, the derived base address could be 0x02000000 + -0x20000000 = 0x22000000. Hence the MEMOFFS = 8704 (decimal, i.e. 0x2200) and so forth. - - - -- int Hy8002CarrierInfo(int carrier); - -where 'carrier' is the registered carrier number in the system. If it is specified, -this function prints out the specified carrier hardware information. If carrier = 0xFFFF, -then all carriers' hardware information will be printed out. - - -2). Configuration Examples -------------------------- - -ipacAddHy8002("3,2") - -This indicates that the carrier is in slot 3 and the interrupt level is set to 2. -IP memory uses default 1MB. Clock uses default 8MHz. RORA as default. use geographical -addressing etc. - -ipacAddHy8002("5,4,IPMEM=1,IPCLCK=8,ROAK=1,MEMOFFS=256 ") - -Here the slot is 5, interrupt level is 4. IP memory size is 1MB, clock uses 8MHz. -Use ROAK but not using geographic addressing. The memory offset is 256 which means its -base address is 0x01000000 assuming the VME_A32_MSTR_LOCAL is set to 0x00000000. - -3). Interrupt Commands Supported -------------------------------- - -The interrupt level can be set by the second parameter of the ipacAddHy8002 routine. -Individual IP module can be set to generate interrupt or not. The commands supported -for ipmIrqCmd are illustrated below. - -cmd Value Returned -ipac_irqGetLevel Carrier interrupt level (0 ~ 7) -ipac_irqEnable 0 = OK -ipac_irqDisable 0 = OK -ipac_irqPoll >0 if the interrupt line is active, else 0 -(other commands) S_IPAC_notImplemented - - -Hy8601 IP Asyn Driver Usage -============================ - -1). Configuration shell command -------------------------------- - -The configuration ioc shell command takes the form below. - -int Hytec8601Configure(char *portName, - epicsUInt16 numAxes, - epicsUInt16 movingPollPeriod, - epicsUInt16 idlePollPeriod, - epicsUInt16 cardnum, - epicsUInt16 ip_carrier, - epicsUInt16 ipslot, - epicsUInt16 vector, - epicsUInt16 useencoder, - epicsDouble encoderRatio0, - epicsDouble encoderRatio1, - epicsDouble encoderRatio2, - epicsDouble encoderRatio3) - -Where: - (1) portName asyn port name - (2) numAxes number of axes - (3) movingPollPeriod status polling time period when motor is moving in ms - (4) idlePollPeriod status polling time period when motor is stopped in ms - (5) cardnum Arbitrary card number to assign to this controller (currently not used) - (6) ip_carrier which previously configured IP carrier in the IOC - (7) ipslot which IP Slot on carrier card (0=A etc.) - (8) vector which Interrupt Vector (0 - Find One ?) - (9) useencoder - bit0 for axis0, bit1 for axis1, bit2 for axis2 and bit3 for axis3. - Other bits not used. 1=use encoder, 0=don't use encoder ! - (10) encoderRatio0 - axis0 hardware encoder ratio - (11) encoderRatio1 - axis1 hardware encoder ratio - (12) encoderRatio2 - axis2 hardware encoder ratio - (13) encoderRatio3 - axis3 hardware encoder ratio - -Example: - - Hytec8601Configure("Hy8601", 4, 500, 1000, 0, IPAC0, 0, 70, 15, 0.25, 0.25, 0.25, 0.25) - -This configures the 8601 card with - port name: Hy8601 - 4 axes - poll status every 500ms when moving - poll status every 1000ms when stopped - card number = 0 - carrier serial number = 0 - ipslot = site A - interrupt vector = 70 - all 4 axes use encoder - all 4 axes have quardrature encoder hence their ratios are 0.25 - -Please note, since the parameters in the function is more than 10, in VxWorks, the start up -script loading will complain about " too many parameters..." In this case, adding - - iocsh() - -before this routine in start up script will solve the problem. - - -2). Database definition file ----------------------------- - -Database definition file is: HytecMotorDriver.dbd. - -3). Databases -------------- - -Two databases can be loaded: - - dbLoadRecords("db/basic_asyn_motor.db") - dbLoadRecords("db/HytecMotorControl.db", "dev=IP8601,area=TEST,locn=LAB,PORT=Hy8601") - -Where: - basic_asyn_motor.db is the motor record database. It initialises 4 axes. - HytecMotorControl.db is the special controls for Hy8601 motor controller. It contains few extra asyn records - including POWER, BRAKE controls, synchronous read of absolute position and enocder position and firmware - version etc as below. - - record(bo,"$(dev):$(area):$(locn):POWER") { - field(DTYP,"asynInt32") - field(OUT,"@asyn($(PORT) 0)HYTEC_POWER") - field(VAL, "1") - field(ONAM, "On") - field(ZNAM, "Off") - } - - record(bo,"$(dev):$(area):$(locn):BRAKE") { - field(DTYP,"asynInt32") - field(OUT,"@asyn($(PORT) 0)HYTEC_BRAKE") - field(VAL, "1") - field(ZNAM, "Set") - field(ONAM, "Rls") - } - - record(ai,"$(dev):$(area):$(locn):POSN") { - field(PINI, "YES") - field(DTYP,"asynInt32") - field(INP,"@asyn($(PORT) 0)MOTOR_POSITION") - field(SCAN, "1 second") - } - - record(ai,"$(dev):$(area):$(locn):EN_POSN") { - field(PINI, "YES") - field(DTYP,"asynInt32") - field(INP,"@asyn($(PORT) 0)MOTOR_ENCODER_POSITION") - field(SCAN, "1 second") - } - - record(ai,"$(dev):$(area):$(locn):FIRMWARE_VERSION") { - field(PINI, "YES") - field(DTYP,"asynInt32") - field(INP,"@asyn($(PORT) 0)HYTEC_FWVERSION") - field(SCAN, "1 second") - } - -There are other records in the HytecMotorControl.db which can return the positions synchronously etc. - -These positions are raw values in terms of the "counts". These records can be read by "ai" records -and can be converted to engineering values by EGUF, EGUL etc. - -Notes: - - - The power control uses AUX1 of the 8601 CSR. As it indicates in the record above, command - - caput $(dev):$(area):$(locn):POWER 1 - - means power "On" and it sets the AUX1 bit, i.e. AUX1 output high (1). - - caput $(dev):$(area):$(locn):POWER 0 - - means power "Off" so it clears AUX1 bit, i.e. AUX1 output low (0). Command - - - The brake control uses AUX2 of the 8601 CSR. As it indicates in the record above, command - - caput $(dev):$(area):$(locn):BRAKE 1 - - means to release the brake. It clears AUX2 bit, i.e. AUX2 output low (0). Command - - caput $(dev):$(area):$(locn):BRAKE 0 - - means set the brake. It sets the AUX2 bit, i.e. AUX2 output high (1). - - - The firmware version record returns the IP card PCB board issue number and the firmware version - - caget $(dev):$(area):$(locn):FIRMWARE_VERSION - - will return something like '2210' for example, whereas the first 2 is the PCB issue number and - 210 is the firmware version. - -4). To build an example application ------------------------------------ - -To build an example to test the 8601 asyn driver, use EPICS makeBaseApp.pl script to create -the example as usual. Then modify the following files to include the driver module(s). - - - /configure/RELEASE - - Change the EPICS_BASE and SUPPORT to the proper directories. - Add ASYN, IPAC and MOTOR moudles: - - ASYN=$(SUPPORT)/asyn/asyn4-14 - IPAC=$(SUPPORT)/ipac/ipac-2.11 - MOTOR=/motorR6-5-2 - - - xxxApp/src/Makefile - - In the Makefile of the example src, add following lines: - - example_DBD += asyn.dbd - example_DBD += motorSupport.dbd - example_DBD += motorRecord.dbd - example_DBD += drvIpac.dbd - example_DBD += HytecMotorDriver.dbd - - example_LIBS += HytecMotor - example_LIBS += motor - example_LIBS += Ipac - example_LIBS += asyn - - - - /xxxApp/Db/Makefile - - Copy HytecMotorControl.db to the Db directory and add the following lines in the Makefile of - the Db directory: - - DB += basic_asyn_motor.db - DB += HytecMotorControl.db - - - Build the application from - - - Modify st.cmd in iocBoot/iocexample as per next section and run the start up script from here. - -5). Start up script example ---------------------------- - -The following example is for an IOC that uses RTEMS R4.9.4, MVME5500 processor board. - - # Change directory to TOP of application - cd("../..") - iocBoot=pwd() - ld( "bin/RTEMS-mvme5500/MotionControl.obj") - #ld < bin/vxWorks-ppc604_long/MotionControl.munch #for VxWorks - - ## Set common environment variables - #< all/pre_st.cmd - epicsEnvSet("IOC_NAME", "MC02") - epicsEnvSet("LOCA_NAME", "B025") - epicsEnvSet("ENGINEER", "Condamoor, Shantha") - - epicsEnvSet( "EPICS_CA_MAX_ARRAY_BYTES", "30000") - - # Register all support components - dbLoadDatabase( "dbd/MotionControl.dbd") - MotionControl_registerRecordDeviceDriver( pdbbase) - - bspExtVerbosity=0 - - ########################################################### - # Configure Hytec 8002 carriers - # 8002 carrier VME slot: 3 - # INT level: 5 - # Memory per IP: 1MB - # Memory mapping offset: 8384 - # =================================================================== - #The typical output on beatnik looks like this: - # Cexp@till35>BSP_VMEOutboundPortsShow() - # Tsi148 Outbound Ports: - # Port VME-Addr Size PCI-Adrs Mode: - # 0: 0x20000000 0x0e000000 0x90000000 A32, SUP, D32, SCT - # 1: 0x00000000 0x00ff0000 0x9f000000 A24, SUP, D32, SCT - # 2: 0x00000000 0x00010000 0x9fff0000 A16, SUP, D32, SCT - # 7: 0x00000000 0x01000000 0x9e000000 CSR, SUP, D32, SCT - # =================================================================== - - # A32 space configured to start here: 0x20000000 - # Tell the carrier not to use geographic addressing - IPAC0=ipacAddHy8002("3,5,IPMEM=1,MEMOFFS=8384") - - # - # Hytec MDS-8 8601 driver setup parameters: - # int Hytec8601Configure(char *portName, - # epicsUInt16 numAxes, - # epicsUInt16 movingPollPeriod, - # epicsUInt16 idlePollPeriod, - # epicsUInt16 cardnum, - # epicsUInt16 ip_carrier, - # epicsUInt16 ipslot, - # epicsUInt16 vector, - # epicsUInt16 useencoder, - # epicsDouble encoderRatio0, - # epicsDouble encoderRatio1, - # epicsDouble encoderRatio2, - # epicsDouble encoderRatio3) - # (1) portName asyn port name - # (2) numAxes number of axes - # (3) movingPollPeriod status polling time period when motor is moving in ms - # (4) idlePollPeriod status polling time period when motor is stopped in ms - # (5) cardnum Arbitrary card number to assign to this controller, not used - # (6) ip_carrier which previously configured IP carrier in the IOC - # (7) ipslot which IP Slot on carrier card (0=A etc.) - # (8) vector which Interrupt Vector (0 - Find One ?) - # (9) useencoder - bit0 for axis0, bit1 for axis1, bit2 for axis2 and bit3 for axis3. - # Other bits not used. 1=use encoder, 0=don't use encoder ! - # (10) encoderRatio0 - axis0 hardware encoder ratio - # (11) encoderRatio1 - axis1 hardware encoder ratio - # (12) encoderRatio2 - axis2 hardware encoder ratio - # (13) encoderRatio3 - axis3 hardware encoder ratio - - Hytec8601Configure("Hy8601", 4, IPAC0, 0, 0, 70, 0, 0.25, 0.25, 0.25, 0.25) - - - # ======================================================== - # New Hytec Motor Databases - # ======================================================= - dbLoadRecords("db/basic_asyn_motor.db") - dbLoadRecords("db/HytecMotorControl.db", "dev=IP8601,area=TEST,locn=LAB,PORT=Hy8601") - # ======================================================== - - iocInit() - - - - - - - diff --git a/motorApp/Makefile b/motorApp/Makefile index 580cbf41..4dd28062 100644 --- a/motorApp/Makefile +++ b/motorApp/Makefile @@ -66,12 +66,6 @@ KohzuSrc_DEPEND_DIRS = MotorSrc DIRS += AerotechSrc AerotechSrc_DEPEND_DIRS = MotorSrc -# The Hytec support requires ipac -ifdef IPAC -DIRS += HytecSrc -HytecSrc_DEPEND_DIRS = MotorSrc -endif - DIRS += ACRSrc ACRSrc_DEPEND_DIRS = MotorSrc