/* C subprograms to access SpeedDaq data acquisition board. IBM bi-directional parallel port to SpeedDaq transfer routines Copyright (c) 1994-2002 Embedded Acquisition Systems email: jfong@embeddedtronics.com URL: http://www.embeddedtronics.com Maxim 197 12bit A/D Compiled with: gnu gcc 2.96 Version: August 17, 2002 port1 Parallel port output register port2 Parallel port input status register port3 Parallel port output control register baseaddress Base address location of parallel port ****************************************************************************** speeddac.c gcc example program to read in single bipolar A/D value and print it to screen need to use gcc option -O (optimize) and run as root to work or set su root. ioperm command needs to be run with root permissions to set the i/o port (baseaddress) before reading data from the parallel port. Program will segfault if not. compiles under linux only due to using ioperm. compile with command line: gcc -O speeddac.c -o speeddac ****************************************************************************** */ #include #include #include #include #include #include #define LMAX 1024 void outbyte(int portaddr, int portdata) /* outbyte Version 1.0 by EMBEDDED ACQUISITION SYSTEMS Function will output a byte to a specified port portaddr is address of output port portdata is byte sent out */ { /*begin function outbyte*/ outb(portdata, portaddr); } /*end function outbyte*/ int inbyte(int portaddr) /* inbyte Version 1.0 by EMBEDDED ACQUISITION SYSTEMS Function will read in a byte from a specified port portaddr is address of input port */ { /*begin function inbyte*/ int portdata; portdata = inb(portaddr); return (portdata); } /*end function inbyte*/ int bipolar10(int channel, int baseaddress) /* bipolar10 Version 1.0 by EMBEDDED ACQUISITION SYSTEMS Function will start a bipolar single ended conversion process and return a integer value The returned value is between -2048 and +2047 +2047 = Vref/2 - 1LSB -2048 = -Vref/2 -10 to 9.9951 Volts maximum input channel is a input integer from 0 to 7 Port3, Control out, format D7 D6 D5 D4 D3 D2 D1 D0 X X Bidir IRQ HBEN CS RD WR set bit 5 high for bidirectional ON Port1 input set bit 5 low for bidirectional OFF Port1 output IRQ is always to low, off state */ { /*begin function bipolar10*/ int data_out,cbyte,port1,port2,port3,x; port1=baseaddress; port2=baseaddress+1; port3=baseaddress+2; data_out=0; switch(channel) { case 0: cbyte = 0x58; break; case 1: cbyte = 0x59; break; case 2: cbyte = 0x5A; break; case 3: cbyte = 0x5B; break; case 4: cbyte = 0x5C; break; case 5: cbyte = 0x5D; break; case 6: cbyte = 0x5E; break; case 7: cbyte = 0x5F; break; } outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ outb(cbyte, port1); /*send out control byte*/ outb(0x1, port3); /*CS and WR low*/ outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ outb(0x24, port3); /*set CS, RD, WR high - Bidir high*/ x=0; do{ /*wait for A/D to finish (INT)*/ x++; }while( ((inb(port2) & 0x8) == 0x8) && (x<15)); outb(0x22,port3); /*CS and RD low, HBEN high, WR high*/ data_out=(inb(port1)& 0xF)<<8; /*get high byte. Mask off 4 high bits,shift contents 8 left*/ outb(0x2A, port3); /*CS and RD low, HBEN low*/ data_out=data_out + inb(port1); /*get low byte and add to high byte*/ outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ if (data_out >= 2048) { /*scale for +2048 to -2048*/ data_out=data_out-4096; } return (data_out); }/*end function bipolar10*/ int bipolar5(int channel, int baseaddress) /* bipolar5 Version 1.0 by EMBEDDED ACQUISITION SYSTEMS Function will start a bipolar single ended conversion process and return a integer value The returned value is between -2048 and +2047 -5 to 4.997 Volts maximum input channel is a input integer from 0 to 7 Port3, Control out, format D7 D6 D5 D4 D3 D2 D1 D0 X X Bidir IRQ HBEN CS RD WR set bit 5 high for bidirectional ON Port1 input set bit 5 low for bidirectional OFF Port1 output IRQ is always to low, off state */ { /*begin function bipolar5*/ int data_out,cbyte,port1,port2,port3,x; port1=baseaddress; port2=baseaddress+1; port3=baseaddress+2; data_out=0; switch(channel) { case 0: cbyte = 0x48; break; case 1: cbyte = 0x49; break; case 2: cbyte = 0x4A; break; case 3: cbyte = 0x4B; break; case 4: cbyte = 0x4C; break; case 5: cbyte = 0x4D; break; case 6: cbyte = 0x4E; break; case 7: cbyte = 0x4F; break; } outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ outb(cbyte, port1); /*send out control byte*/ outb(0x1, port3); /*CS and WR low*/ outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ outb(0x24, port3); /*set CS, RD, WR high - Bidir high*/ x=0; do{ /*wait for A/D to finish (INT)*/ x++; }while( ((inb(port2) & 0x8) == 0x8) && (x<15)); outb(0x22,port3); /*CS and RD low, HBEN high, WR high*/ data_out=(inb(port1)& 0xF)<<8; /*get high byte. Mask off 4 high bits,shift contents 8 left*/ outb(0x2A, port3); /*CS and RD low, HBEN low*/ data_out=data_out + inb(port1); /*get low byte and add to high byte*/ outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ if (data_out >= 2048) { /*scale for +2048 to -2048*/ data_out=data_out-4096; } return (data_out); }/*end function bipolar5*/ int unipolar10(int channel, int baseaddress) /* unipolar10 Version 1.0 by EMBEDDED ACQUISITION SYSTEMS Function will start a unipolar single ended conversion process and return a integer value The returned value is between 0 and +4095 0 to 9.998 Volts maximum input channel is a input integer from 0 to 7 Port3, Control out, format D7 D6 D5 D4 D3 D2 D1 D0 X X Bidir IRQ HBEN CS RD WR set bit 5 high for bidirectional ON Port1 input set bit 5 low for bidirectional OFF Port1 output IRQ is always to low, off state */ { /*begin function unipolar10*/ int data_out,cbyte,port1,port2,port3,x; port1=baseaddress; port2=baseaddress+1; port3=baseaddress+2; data_out=0; switch(channel) { case 0: cbyte = 0x50; break; case 1: cbyte = 0x51; break; case 2: cbyte = 0x52; break; case 3: cbyte = 0x53; break; case 4: cbyte = 0x54; break; case 5: cbyte = 0x55; break; case 6: cbyte = 0x56; break; case 7: cbyte = 0x57; break; } outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ outb(cbyte, port1); /*send out control byte*/ outb(0x1, port3); /*CS and WR low*/ outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ outb(0x24, port3); /*set CS, RD, WR high - Bidir high*/ x=0; do{ /*wait for A/D to finish (INT)*/ x++; }while( ((inb(port2) & 0x8) == 0x8) && (x<15)); outb(0x22,port3); /*CS and RD low, HBEN high, WR high*/ data_out=(inb(port1)& 0xF)<<8; /*get high byte. Mask off 4 high bits,shift contents 8 left*/ outb(0x2A, port3); /*CS and RD low, HBEN low*/ data_out=data_out + inb(port1); /*get low byte and add to high byte*/ outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ return (data_out); }/*end function unipolar10*/ int unipolar5(int channel, int baseaddress) /* unipolar10 Version 1.0 by EMBEDDED ACQUISITION SYSTEMS Function will start a unipolar single ended conversion process and return a integer value The returned value is between 0 and +4095 0 to 4.998 Volts maximum input channel is a input integer from 0 to 7 Port3, Control out, format D7 D6 D5 D4 D3 D2 D1 D0 X X Bidir IRQ HBEN CS RD WR set bit 5 high for bidirectional ON Port1 input set bit 5 low for bidirectional OFF Port1 output IRQ is always to low, off state */ { /*begin function unipolar5*/ int data_out,cbyte,port1,port2,port3,x; port1=baseaddress; port2=baseaddress+1; port3=baseaddress+2; data_out=0; switch(channel) { case 0: cbyte = 0x40; break; case 1: cbyte = 0x41; break; case 2: cbyte = 0x42; break; case 3: cbyte = 0x43; break; case 4: cbyte = 0x44; break; case 5: cbyte = 0x45; break; case 6: cbyte = 0x46; break; case 7: cbyte = 0x47; break; } outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ outb(cbyte, port1); /*send out control byte*/ outb(0x1, port3); /*CS and WR low*/ outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ outb(0x24, port3); /*set CS, RD, WR high - Bidir high*/ x=0; do{ /*wait for A/D to finish (INT)*/ x++; }while( ((inb(port2) & 0x8) == 0x8) && (x<15)); outb(0x22,port3); /*CS and RD low, HBEN high, WR high*/ data_out=(inb(port1)& 0xF)<<8; /*get high byte. Mask off 4 high bits,shift contents 8 left*/ outb(0x2A, port3); /*CS and RD low, HBEN low*/ data_out=data_out + inb(port1); /*get low byte and add to high byte*/ outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ return (data_out); }/*end function unipolar5*/ int locatedaq() /* locatedaq Version 1.0 by EMBEDDED ACQUISITION SYSTEMS Function will try to find which parallel port SpeedDaq is connected to. Return values are 0x278, 0x378 or 0x3bc. If SpeedDac cannot be located, function will return -1 Port3, Control out, format D7 D6 D5 D4 D3 D2 D1 D0 X X Bidir IRQ HBEN CS RD WR set bit 5 high for bidirectional ON Port1 input set bit 5 low for bidirectional OFF Port1 output IRQ is always to low, off state */ { /*begin function locatedaq*/ int port1,port2,port3,x,baseaddress; /* check port 0x278*/ baseaddress = 0x278; /*set i/o port so we can talk to it*/ ioperm(baseaddress, 1, 1); ioperm(baseaddress+1, 1, 1); ioperm(baseaddress+2, 1, 1); ioperm(0x80, 1, 1); port1=baseaddress; port2=baseaddress+1; port3=baseaddress+2; outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ outb(0x58, port1); /*send out control byte, biploar channel0*/ outb(0x1, port3); /*CS and WR low*/ outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ outb(0x24, port3); /*set CS, RD, WR high - Bidir high*/ x=0; do{ /*wait for A/D to finish (INT)*/ x++; }while( ((inb(port2) & 0x8) == 0x8) && (x<50)); outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ if (x<50) { return 0x278; } /* check port 0x378*/ baseaddress = 0x378; /*set i/o port so we can talk to it*/ ioperm(baseaddress, 1, 1); ioperm(baseaddress+1, 1, 1); ioperm(baseaddress+2, 1, 1); ioperm(0x80, 1, 1); port1=baseaddress; port2=baseaddress+1; port3=baseaddress+2; outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ outb(0x58, port1); /*send out control byte, biploar channel0*/ outb(0x1, port3); /*CS and WR low*/ outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ outb(0x24, port3); /*set CS, RD, WR high - Bidir high*/ x=0; do{ /*wait for A/D to finish (INT)*/ x++; }while( ((inb(port2) & 0x8) == 0x8) && (x<50)); outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ if (x<50) { return 0x378; } /* check port 0x3bc*/ baseaddress = 0x3bc; /*set i/o port so we can talk to it*/ ioperm(baseaddress, 1, 1); ioperm(baseaddress+1, 1, 1); ioperm(baseaddress+2, 1, 1); ioperm(0x80, 1, 1); port1=baseaddress; port2=baseaddress+1; port3=baseaddress+2; outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ outb(0x58, port1); /*send out control byte, biploar channel0*/ outb(0x1, port3); /*CS and WR low*/ outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ outb(0x24, port3); /*set CS, RD, WR high - Bidir high*/ x=0; do{ /*wait for A/D to finish (INT)*/ x++; }while( ((inb(port2) & 0x8) == 0x8) && (x<50)); outb(0x4, port3); /*set CS, RD, WR high - Bidir low*/ if (x<50) { return 0x3bc; } /*didn't find SpeedDaq*/ return -1; }/*end function locatedaq*/ /*********************************************************************************/ /*begin main*/ int main(int argc, char **argv){ int channel, baseaddress, data_out; if(argc < 2) { printf("SpeedDac 12 Bit A/D ** www.embeddedtronics.com **\n"); printf("Max input -10 to +10 Volts \n"); printf("Syntax:\tspeeddac \"channel\"\n"); return(0); } /* NOTE: Set baseaddress to correct parallel port address in Hex Typical parallel port assignments are lpt1 0x3BC lpt2 0x378 lpt2 0x278*/ baseaddress=locatedaq(); /*find address of parallel port*/ if (baseaddress==-1) { printf("SpeedDac not found \n"); exit(1); /*exit if no SpeedDac*/ } /*set i/o port so we can talk to it*/ ioperm(baseaddress, 1, 1); ioperm(baseaddress+1, 1, 1); ioperm(baseaddress+2, 1, 1); ioperm(0x80, 1, 1); data_out= bipolar10(atoi(argv[1]),baseaddress); if (data_out >= 2048) { /*scale for +2048 to -2048*/ data_out=data_out-4096; } printf("Voltage = %3.2f \n" , data_out *.004882813 ); } /*end main*/