/* parda.c: A very simple linux user space program for the simple DA-converter as a function generator via the Parallel Port and 8 330 Ohm resitors between every data pin and the output (= 3 1/2 -bit DAC, short-circuit-proof). Parameter: I/O-Address (usually 888 for standard parallel port), Byte of the data register (pin pattern on output), duration of a high/low period in µs. Example: ./parda 888 255 12345. The bit patter of the output determins the amplitude: 8 bits (255) means 100 %; 0 means 0 %, 4 bits (e. g. 15) means 50 % etc.: 0xff 100 % 0x7f, 0xf7, ... 87,5 % 0x3f, 0xf3, ... 75 % 0x1f, 0xf1, ... 62,5 % 0x0f, 0xf0, ... 50 % 0x07, 0x70, ... 37,5 % 0x03, 0x30, ... 25 % 0x01, 0x10, ... 12,5 % 0x00 0 % Measured frequency with Linux version 2.6.8-24.11-smp (SuSE 9.2) and the onboard port: delay frequency/Hz (onboard port) 10000000 0.05 1000000 0.4988 248000 2.00 100000 4.9 10000 41,6 1000 166 1 ... 100 249,9 0 499,9 0 without udelay approx. 200 kHz The same was measured with a parallel port PCI card. For higher frequencies you should use a kernel module which should have a limit of approx. 500 kHz instead of 250 Hz. For a really constant frequency (no jitter) you need RTAI. Todo: Check of the parameters + help, a function for triangle wave output with the output sequence 0 1 3 7 15 31 63 127 255 254 252 248 240 224 192 128 0 ..., a function for sine wave output, ..., get address from /proc/bus/pci from first device with vendor id 0x9710 and device id 0x9805. Rolf Freitag Feb. 2005, nobodyo@web.de */ #include #include // or asm/io.h; for inb, ioperm, iopl ... #include // atoi #include // getuid(), usleep #include // EPERM #include // bitand etc. int main (int argc, char *argv[]) // Caution: A wrong parameter value can cause serious damage! { int base; // base address of the parallel port int value; // bit pattern for the data pins (0 = off, 255 = all high) int delay; // duration of a pulse/leap in µs int i_tmp=0; if (4 != argc) { printf ("Usage: %s \n", argv[0]); exit (-1); } base = strtol (argv[1], (char **)NULL, 0); // base address of the parallel port value = strtol (argv[2], (char **)NULL, 0); // bit pattern for the data pins (0 = off, 255 = all high) delay = strtol (argv[3], (char **)NULL, 0); // duration of a pulse/leap in µs if (geteuid () != 0) { printf ("\a\n\nError: $EUID==%d!=0 (you are not a superuser, port access would be denied from the kernel), exiting.\n\n", getuid ()); exit (-EPERM); } iopl (3); // unlimited I/O access permission, nessesary above the 0x3ff limit e. g. at 0x9800=38912 i_tmp = inb(base +2); // cache the controll register // outb (0x0b, base +2); // write mode i_tmp or_eq 0x20; // set bit for write mode outb (i_tmp, base +2); // write mode if (delay > 0) for (;;) // endless loop with < 1 % CPU load { outb (value, base); usleep (delay); outb (0, base); usleep (delay); } else for (;;) // 99 % CPU load { outb (value, base); outb (0, base); } iopl (0); // no I/O permission exit (0); };