Nothing quite beats the PC parallel port for electronics tinkering. FreeBSD has a user-space interface to it just for this purpose, "man ppi" has the details.
Accessing the port using /dev/ppi0 is straightforward. Do this as root:
# chmod a+rw /dev/ppi0 |
then this code lets you read and write to the port:
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/dev/ppbus/ppi.h>
#include <sys/dev/ppbus/ppbconf.h>
static int ppi_fd;
static void do_init(void)
{
char port[] = "/dev/ppi0";
ppi_fd = open(port, O_RDWR);
if( ppi_fd < 0 ) {
perror(port);
exit(1);
}
}
static void do_out(unsigned long outval)
{
int val = outval, n;
n = ioctl(ppi_fd, PPISDATA, &val);
if( n < 0 ) {
perror("ioctl PPISDATA");
exit(1);
}
}
static unsigned long do_in(void)
{
int val, n;
n = ioctl(ppi_fd, PPIGSTATUS, &val);
if( n < 0 ) {
perror("ioctl PPIGSTATUS");
exit(1);
}
return val;
}
|
So much for talking on the parallel port. I had some trouble with noise on the port, and the connector (25 pin D-sub) is neither cheap nor convenient, so I made a small PCB to buffer a few signals (6 output, 2 input) and put them on a couple of 10-pin IDC headers so I could use ribbon cable to hook things up. The board plugs straight into the socket on the back of the PC, and takes its power (3.3v - 5v) from the target circuit. Here's the schematic and board for Cadsoft's Eagle.
Parts list
![]() |
![]() |
![]() |
| Connector | Pin | Function | ppi bit |
| SV1 | 1 | out | 0 |
| 2 | GND | - | |
| 3 | out | 1 | |
| 4 | GND | - | |
| 5 | out | 2 | |
| 6 | GND | - | |
| 7 | in | 5 | |
| 8 | GND | - | |
| 9 | VCC | - | |
| 10 | GND | - | |
| SV2 | 1 | out | 4 |
| 2 | GND | - | |
| 3 | out | 5 | |
| 4 | GND | - | |
| 5 | out | 6 | |
| 6 | GND | - | |
| 7 | in | 4 | |
| 8 | GND | - | |
| 9 | VCC | - | |
| 10 | GND | - |
So to set pin 5 on SV1, something like do_out(1 << 2)
does the trick. And to read pin 7 on SV1, (1 & (do_in() >>
5)) will get it.