Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

ppmc_encoder.c

Go to the documentation of this file.
00001 #include "ppmc.h"
00002 #include "extintf.h"
00003 
00004 #ifdef RTLINUX
00005 #ifndef MODULE
00006 #define MODULE
00007 #endif
00008 #define DO_IT
00009 #endif
00010 
00011 #ifdef LINUX
00012 #define DO_IT
00013 /*
00014   Compiling this for LINUX (not RTLINUX) means linking this into a Linux
00015   process, running non-real-time in user space. This is useful for debugging.
00016   If this is done, then the following stuff needs to be done to access the
00017   IO space.
00018   */
00019 
00020 /*
00021   Because of a limitation in gcc (present at least in 2.7.2.1 and below), you
00022   _have to_ compile any source code that uses these routines with optimisation
00023   turned on (gcc -O1 or higher), or alternatively #define extern to be
00024   empty before #including <asm/io.h>.
00025 
00026   Otherwise, you'll get errors at link time like:
00027 
00028   stg.c:475: undefined reference to `__inbc'
00029  */
00030 #define extern
00031 
00032 /*
00033   Need to access ports in range 0x278 - 0x378, for default
00034   PPMC base address. ioperm() only enables up to 0x3FF, so we need to use
00035   iopl() to grant full access to IO space.
00036   */
00037 // already included in ppmc_internal.c
00038 //# include <unistd.h>          /* iopl() */
00039 
00040 #endif /* LINUX  */
00041 
00042 #ifdef DO_IT
00043 // io.h already included in ppmc_internal.c
00044 //# include <asm/io.h>  /*for faster I/O we have to eliminate subroutine calls */
00045 #else
00046 /* otherwise do nothing */
00047 
00048 #include <stdio.h>
00049 
00050 static int iopl(int level)
00051 {
00052   return 0;
00053 }
00054 
00055 #endif
00056 
00057 //extern unsigned int ppmc_base_addr;
00058 
00059 #define CONTROLPORT ppmc_base_addr+2
00060 #define DATAPORT ppmc_base_addr+4
00061 
00062 
00063 //ppmc encoder functions
00064 int EncoderInit(void)
00065 {
00066 #ifdef PPMC_8_AXES
00067   unsigned int wAdd;
00068 #endif
00069   short success=0;
00070         
00071 
00072   /* set all channels to normal mode (no find index, no load counters */
00073   SelWrt(ENCCTRL_0,0);
00074 #ifdef PPMC_8_AXES
00075   SelWrt(ENCCTRL_1,0);
00076   SelWrt(ENCRATE_1,0);  // in all cases, the 2nd encoder board is slaved to first
00077 #endif
00078   //  SelWrt(ENCRATE_0,0x10);  // make encoder board 0 master
00079   SelWrt(ENCRATE_0,0x00);  // don't make encoder board 0 master for software latch
00080  // zero the encoder counters  ( not needed )
00081   SelWrt(ENCLOAD_0,0);             /* clear 3-byte preload register */
00082   WriteData(0);
00083   WriteData(0);
00084   SelWrt(ENCCTRL_0,0xF0);  /* select load pos counter # and enable */
00085   SelWrt(ENCCTRL_0,0xF0);  /* select load pos counter # and enable */
00086   SelWrt(ENCCTRL_0,0xF0);  /* delay to give time for load to take place */
00087   SelWrt(ENCCTRL_0,0xF0);  /* more delay */
00088   SelWrt(ENCCTRL_0,0);         /* turn off load position counter function */
00089       
00090 #ifdef PPMC_8_AXES
00091   SelWrt(ENCLOAD_1,0);             /* clear 3-byte preload register */
00092   WriteData(0);
00093   WriteData(0);
00094   for (wAdd = 0; wAdd <= 3; wAdd ++)
00095     {
00096       SelWrt(ENCCTRL_1,(unsigned char)((wAdd>>3)+32));  /* select load pos counter # and enable */
00097     }
00098   SelWrt(ENCCTRL_1,0);         /* turn off load position counter function */
00099 #endif
00100         return success;
00101 }
00102 int EncoderQuit(void)
00103 {
00104         return 0;
00105 }
00106 void SelectInterruptPeriod(long lPeriodSelect)   
00107 {
00108 #ifdef PPMC_8_AXES
00109   SelWrt(ENCRATE_1,0);             /* set 2nd board to slave timer mode */
00110 #endif 
00111    
00112   switch (lPeriodSelect)
00113     {
00114     case _500_MICROSECONDS:
00115       SelWrt(ENCRATE_0,0x0B);                   /* master mode, 10 KHz / 5 = 2 KHz */
00116       break;
00117     case _1_MILLISECOND:
00118       SelWrt(ENCRATE_0,0x16);                   /* master mode, 10 KHz / 10 = 1 KHz */
00119       break;
00120     case _2_MILLISECONDS:
00121       SelWrt(ENCRATE_0,0x00);                   /* master mode, 10 KHz / 16 = 0.667 KHz */
00122       break;
00123     case _3_MILLISECONDS:
00124       SelWrt(ENCRATE_0,0x10);                   /* master mode, 10 KHz / 10 = 1 KHz */
00125       break;
00126     case _4_MILLISECONDS:
00127       SelWrt(ENCRATE_0,0x10);                   /* master mode, 10 KHz / 10 = 1 KHz */
00128       break;
00129     case _5_MILLISECONDS:
00130       SelWrt(ENCRATE_0,0x10);                   /* master mode, 10 KHz / 10 = 1 KHz */
00131       break;
00132     case _10_MILLISECONDS:
00133       SelWrt(ENCRATE_0,0x10);                   /* master mode, 10 KHz / 10 = 1 KHz */
00134       break;
00135     case _100_MILLISECONDS:
00136       SelWrt(ENCRATE_0,0x10);                   /* master mode, 10 KHz / 10 = 1 KHz */
00137       break;
00138     case _1_SECOND:
00139       SelWrt(ENCRATE_0,0x10);                   /* master mode, 10 KHz / 10 = 1 KHz */
00140       break;
00141     default:
00142       /* wrong input? then don't change it */
00143       break;
00144     }
00145 }
00146 
00147 
00148 int EncoderLatch()
00149 {
00150         SelWrt(ENCRATE_0, 0x20);           /* pulse software generated strobe pulse */
00151         SelWrt(ENCRATE_0, 0x00);  // no need to do anything to 2nd encoder,
00152         // it is automatically slaved to first
00153      
00154   return 0;
00155 }
00156 
00157 int EncReadAll(LONGBYTE * lbEnc)
00158 {
00159   static unsigned char byOldByte2[PPMC_MAX_AXIS];
00160   static unsigned char byEncHighByte[PPMC_MAX_AXIS];
00161   short i,max;
00162 
00163   SelAddr(ENCCNT0);
00164   //  outb(0x24,CONTROLPORT);    // set EPP port to input mode
00165   max = PPMC_MAX_AXIS;
00166   if (max > 4) max = 4;
00167   for (i = 0; i < max; i++)            /* 24 bits means get 3 bytes each */
00168     {
00169       lbEnc[i].Byte[0] = ReadData();
00170       lbEnc[i].Byte[1] = ReadData();
00171       lbEnc[i].Byte[2] = ReadData();  
00172       /* lbEnc[i].Byte[0] = inb(DATAPORT);
00173       lbEnc[i].Byte[1] = inb(DATAPORT);
00174       lbEnc[i].Byte[2] = inb(DATAPORT); */
00175     }
00176 #ifdef PPMC_8_AXES
00177   if (PPMC_MAX_AXIS > 4)
00178     {
00179       SelAddr(ENCCNT4);
00180       for (i = 4; i < PPMC_MAX_AXIS; i++)            /* 24 bits means get 3 bytes each */
00181         {
00182           lbEnc[i].Byte[0] = ReadData();
00183           lbEnc[i].Byte[1] = ReadData();
00184           lbEnc[i].Byte[2] = ReadData();
00185         }
00186     }
00187 #endif
00188   
00189   /* code to sign extend the 24 bit value */
00190   /* but we won't do this. */
00191   /*for ( i = 0; i < 8; i++) */
00192   /*  lbEnc[i].Byte[3] = lbEnc[i].Byte[2] & 0x80 ? 0xff : 0; */
00193   
00194   /* maintain the high byte, to extend the counter to 32 bits */
00195   /* */
00196   /* base decisions to increment or decrement the high byte */
00197   /* on the highest 2 bits of the 24 bit value.  To get the */
00198   /* highest 2 bits, use 0xc0 as a mask on byte [2] (the third */
00199   /* byte). */
00200   
00201   for (i = 0; i < PPMC_MAX_AXIS; i++)
00202     {
00203       /* check for -1 to 0 transition */
00204 
00205       if (    ( (byOldByte2[i]    & 0xc0) == 0xc0 ) /* 11xxxxxx */
00206               && ( (lbEnc[i].Byte[2] & 0xc0) == 0 ) /* 00xxxxxx */
00207               )
00208         byEncHighByte[i]++;
00209 
00210       /* check for 0 to -1 transition */
00211 
00212       if (    ( (byOldByte2[i]    & 0xc0) == 0 ) /* 00xxxxxx */
00213               && ( (lbEnc[i].Byte[2] & 0xc0) == 0xc0 ) /* 11xxxxxx */
00214               )
00215         byEncHighByte[i]--;
00216 
00217       lbEnc[i].Byte[3] = byEncHighByte[i];
00218       byOldByte2[i] = lbEnc[i].Byte[2]; /* current byte 2 becomes old one */
00219     }
00220 
00221   return 0;
00222 }
00223 
00224 
00225 
00226 int ppmcEncoderSetIndexModel(unsigned int model)//eek not sure i got this right
00227 {
00228   if (model != EXT_ENCODER_INDEX_MODEL_MANUAL)
00229     {
00230       return -1;
00231     }
00232   
00233   return 0;
00234 }
00235 
00236 int ppmcEncoderNum()
00237 {
00238   return PPMC_MAX_AXIS;
00239 }
00240 
00241 int ppmcEncoderRead(int encoder, double * counts)
00242 {
00243         double allCounts[PPMC_MAX_AXIS];
00244 
00245   if (encoder < 0 ||
00246       encoder >= PPMC_MAX_AXIS) {
00247     *counts = 0.0;
00248     return 0;
00249   }
00250 
00251   ppmcEncoderReadAll(encoder + 1, allCounts);
00252 
00253   *counts = allCounts[encoder];
00254 
00255   return 0;
00256   
00257 }
00258 
00259 int ppmcEncoderReadAll(int max, double * counts)
00260 {
00261   LONGBYTE lbEnc[PPMC_MAX_AXIS];
00262   int t;
00263   int smax;                     /* how many we actually have */
00264 
00265   /* clip smax to max supported-- if they want more, give
00266      them zeros */
00267   if (max > PPMC_MAX_AXIS) {
00268     smax = PPMC_MAX_AXIS;
00269   }
00270   else {
00271     smax = max;
00272   }
00273 
00274   EncoderLatch();
00275   EncReadAll(lbEnc);
00276 
00277   /* fill ours with the actual values */
00278   for (t = 0; t < smax; t++) {
00279     counts[t] = (double) lbEnc[t].Long;
00280   }
00281   /* and fill the rest with zeros */
00282   for (t = smax; t < max; t++) {
00283     counts[t] = 0.0;
00284   }
00285 
00286   return 0;
00287 }
00288 
00289 /*
00290 //this routine reads the latch.  the index
00291 //may not still be valid.  For a manual mode encoder
00292 //interface such as this they may want to know if the
00293 //index pulse has gone past.  Generally, emc 
00294 //resets the latch before reading the latch
00295 */
00296 
00297 int ppmcEncoderReadLatch(int encoder, int * flag)
00298 {
00299 #ifdef NO_INDEX_PULSE
00300   *flag = 1;
00301   return 0;
00302 #else
00303   short int index_sense_data;
00304   short int index_mask;
00305   
00306   if (encoder>PPMC_MAX_AXIS) return -1; //not that many encoders
00307 #ifdef PPMC_8_AXES
00308           if (encoder>=4)
00309           {  
00310                   index_sense_data=SelRead(ENCISR_1);
00311                   index_mask=(1<<((short)encoder-4));
00312                   if(index_sense_data&index_mask)*flag=1;
00313                   else *flag=0;
00314                   return 0;
00315           }
00316 #endif 
00317           //either wasn't 8 axis or was first encoder board
00318                   index_sense_data=SelRead(ENCISR_0);
00319                   index_mask=(1<<((short)encoder));
00320                   if(index_sense_data&index_mask)*flag=1;
00321                   else *flag=0;
00322                   return 0;
00323 
00324 #endif
00325 }
00326 
00327 int ppmcEncoderReadLevel(int encoder, int * flag)
00328 {
00329   return ppmcEncoderReadLatch(encoder,flag);
00330 }
00331 
00332 //read the latch to clear it
00333 int ppmcEncoderResetIndex(int encoder)
00334 {
00335   int dummyflag;
00336   return ppmcEncoderReadLatch(encoder,&dummyflag);
00337 
00338 }
00339 

Generated on Sun Dec 2 15:27:41 2001 for EMC by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001