Xenomai 2.2 Parallel Port Interrupt ISR - Standalone version (with a square wave realtime task)
A user-space Xenomai 2.2 hard real time example for capturing the parallel port interrupt.
The real time task "squarewave" generates a square wave on all parallel port data output pins, which triggers the interrupt.
Another task is printing how many interrupts occured. Furthermore the Interrupt Service Routine
writes to a PIPE (equal to a FIFO in RTAI/classic), which is read (blocking read) in "main".
It also can be used as template for writing or reading to/from the parallel port in certain intervals i.e. for
logging purposes.
I.e. write to the parallel port to start the AD conversion - the interrupt service routine (ISR) is triggered when
the analog digital converter is ready, the ISR reads the value and does something with it ;-)
Compile "parint.c" with "make".
Make a "null-modem" for the parallel port - connect any output pin (pin 2-9) with the IRQ pin (pin 10 = ACK).
Run "parint" (press CTRL-C to end the program) - you'll see an output like this:
# ./parint
start
rt_intr_create=0
Read from pipe: 1
Read from pipe: 2
Read from pipe: 3
3 interrupts occured
Read from pipe: 4
Read from pipe: 5
Read from pipe: 6
6 interrupts occured
Read from pipe: 7
Read from pipe: 8
cleanup
exit
read error
The "read error" is due the fact that the rt_pipe is deleted and then "main" attempts to read from it.
Nothing to worry about in this example, but try to avoid this in real world examples ;-)
parint.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/io.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <native/task.h>
#include <native/queue.h>
#include <native/intr.h>
#include <native/pipe.h>
#define STACK_SIZE 8192
#define STD_PRIO 1
#define STD_PRIORITY 1
#define HIGH_PRIORITY 99
#define MID_PRIORITY 50
#define BASEPORT 0x378
#define PARPORTINT 7
#define PIPE_MINOR 0
RT_TASK print_task_ptr;
RT_TASK square_task_ptr;
RT_TASK interrupt_task_ptr;
RT_INTR intr_desc;
RT_PIPE mypipe;
int int_count = 0;
int end = 0;
int test;
// --s-ms-us-ns
RTIME task_period_ns = 1000000000llu;
RTIME print_period_ns = 1000000000llu;
RTIME square_period_ns = 300000000llu;
// simple task to count interrupts
void interrupt_task(void *cookie) {
int err = 0;
int error;
error = rt_pipe_create(&mypipe, "intpipe", PIPE_MINOR, 0);
// todo: add error handling
while (!end) {
err = rt_intr_wait(&intr_desc, TM_INFINITE);
if (err > 0) {
int_count++;
rt_pipe_write(&mypipe, &int_count, sizeof(int_count), P_NORMAL);
} else {
//printf("interrupt_task error = %i\n", err);
}
rt_intr_enable (&intr_desc);
}
rt_pipe_delete(&mypipe);
}
// print out the interrupt-count periodically
void print_task(void *cookie) {
unsigned long overrun;
int ret = rt_task_set_periodic(NULL, TM_NOW, rt_timer_ns2ticks(print_period_ns));
if (ret) {
printf("error while set periodic, code %d\n",ret);
return;
}
while (!end) {
ret = rt_task_wait_period(&overrun);
if (ret) {
printf("error while rt_task_wait_period, code %d\n",ret);
return;
}
printf("%d interrupts occured\n", int_count);
fflush(NULL);
}
}
// generates a square wave on the parallel port
void squaretask(void *cookie) {
unsigned long overrun;
int ret = rt_task_set_periodic(NULL, TM_NOW, rt_timer_ns2ticks(square_period_ns));
if (ret) {
printf("error while set periodic, code %d\n",ret);
return;
}
ret = rt_task_wait_period(&overrun);
if (ret) {
printf("error while rt_task_wait_period, code %d\n",ret);
return;
}
while (!end) {
outb_p(0xff, BASEPORT);
ret = rt_task_wait_period(&overrun);
if (ret) {
printf("error while rt_task_wait_period, code %d\n",ret);
return;
}
outb_p(0x00, BASEPORT);
ret = rt_task_wait_period(&overrun);
if (ret) {
printf("error while rt_task_wait_period, code %d\n",ret);
return;
}
}
}
// signal-handler, to ensure clean exit on Ctrl-C
void clean_exit(int dummy) {
printf("cleanup\n");
end = 1;
rt_task_delete(&print_task_ptr);
rt_task_delete(&square_task_ptr);
rt_task_delete(&interrupt_task_ptr);
rt_intr_delete(&intr_desc);
rt_pipe_delete(&mypipe);
printf("end\n");
}
int main(int argc, char *argv[]) {
int err, fd;
printf("start\n");
// install signal handler
signal(SIGTERM, clean_exit);
signal(SIGINT, clean_exit);
// ask for permission to access the parallel port from user-space
if (iopl(3)) {
printf("iopl err\n");
exit(1);
}
// set parallel port to interrupt mode
outb_p(0x10, BASEPORT + 2);
//create interrupt object
//err = rt_intr_create(&intr_desc, PARPORTINT, I_AUTOENA);
mlockall(MCL_CURRENT | MCL_FUTURE);
// CONFIG_XENO_OPT_NATIVE_INTR=y otherwise it fails with ENOSYS (38)
err = rt_intr_create(&intr_desc, "parint", PARPORTINT, I_NOAUTOENA);
printf("rt_intr_create=%i\n", err);
rt_intr_enable (&intr_desc);
err = rt_task_spawn(&square_task_ptr, "Square", STACK_SIZE, STD_PRIO, 0,
&squaretask, NULL);
if (err) {
printf("error rt_task_spawn\n");
return 0;
}
err = rt_task_spawn(&interrupt_task_ptr, "Int", STACK_SIZE, STD_PRIO, 0,
&interrupt_task, NULL);
if (err) {
printf("error rt_task_spawn 2\n");
return 0;
}
err = rt_task_spawn(&print_task_ptr, "Printer", STACK_SIZE, STD_PRIO, 0,
&print_task, NULL);
if (err) {
printf("error rt_task_spawn 3\n");
return 0;
}
//pause(); // or read from pipe
fd = open("/dev/rtp0", O_RDONLY);
while (!end) {
err = read(fd, &test, sizeof(test));
if (err == -1) {
printf("read error\n");
} else {
printf("Read from pipe: %d\n", test);
}
}
fflush(NULL);
return 0;
}
Makefile
TARGET = parint
ifeq ($(XENODIR),)
XENODIR = /usr/xenomai
endif
XENO_LIB_DIR = $(shell $(XENODIR)/bin/xeno-config --library-dir)
CC = $(shell $(XENODIR)/bin/xeno-config --cc)
CFLAGS = -g -I $(XENODIR)/include -lpthread -lnative -lrtdm -L $(XENO_LIB_DIR) -Wall -O2
all: $(TARGET)
$(TARGET): $(TARGET).c
clean:
$(RM) $(TARGET)
Last-Modified: Sun, 23 Jul 2006 20:45:38 GMT