RTAI Parallel Port Interrupt LXRT Example (RTAI3.1) Standalone Version:
A user-space (LXRT) hard real time example for capturing the parallel port interrupt.
This is the same as Parallel Port Interrupt LXRT Example for RTAI 3.2 - Standalone (with a square wave realtime task),
but modified to compile and run on RTAI 3.1.
Also see:Parallel Port Interrupt LXRT Example (RTAI3.0r4 or RTAI3.1),
Parallel Port Interrupt LXRT Example (RTAI3.2)
and RTAI/fusion Parallel Port Interrupt ISR - Standalone version (with a square wave realtime task)
Bugfix 10-MAY-2005: Make sure you do any nano2count after the real time timer has been started!
rt_set_oneshot_mode();
start_rt_timer(0);
period = nano2count(PERIOD);
rt_make_hard_real_time();
It also can be used as template for writing or reading to/from the parallel port in certain intervals.
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 "par_rw.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).
Load the RTAI kernel modules with "loadmods.sh"
Start "par_rw" in one shell and you'll see the detected interrupts:
muon:/home/rtai/par_rw31# ./par_rw
GIVE THE NUMBER OF INTERRUPTS YOU WANT TO COUNT: 3
RETVAL 7, OVERRUNS 0, INTERRUPT COUNT 1
RETVAL 7, OVERRUNS 0, INTERRUPT COUNT 2
RETVAL 7, OVERRUNS 0, INTERRUPT COUNT 3
TEST ENDS
Developed and tested on kernel 2.6.7 / RTAI3.1
Example "par_rw.c" (RTAI LXRT hard real time)
/* RTAI LXRT Parallel Port Interrupt - www.captain.at
based on usi_process.c from showroom
Needs a "null-modem" for the parallel port:
connect any output pin (pin 2-9) with the IRQ pin (pin 10 = ACK).
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sched.h>
#include <signal.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <rtai_lxrt.h>
#include <rtai_sem.h>
#include <rtai_usi.h>
#include <sys/io.h>
#define PARPORT_IRQ 7
#define BASEPORT 0x378
static SEM *intsem, *dspsem;
static volatile int end = 1;
static volatile int endsquare = 1;
static volatile int ovr, intcnt, retval, maxcnt;
#define PERIOD 1000000000
static void *timer_handler(void *args)
{
RT_TASK *handler;
if (!(handler = rt_task_init_schmod(nam2num("HANDLR"), 0, 0, 0, SCHED_FIFO, 0xF))) {
printf("CANNOT INIT HANDLER TASK > HANDLR <\n");
exit(1);
}
rt_allow_nonroot_hrt();
mlockall(MCL_CURRENT | MCL_FUTURE);
rt_make_hard_real_time();
end = 0;
while (!end) {
do {
ovr = rt_wait_intr(intsem, (void *)&retval);
hard_sti();
if (end) break;
// overrun processing, if any, goes here
if (ovr > 0) {
rt_sem_signal(dspsem);
}
/* normal processing goes here */
intcnt++;
rt_sem_signal(dspsem); // notify main()
rt_ack_irq(PARPORT_IRQ);
} while (ovr > 0);
rt_pend_linux_irq(PARPORT_IRQ);
}
rt_make_soft_real_time();
rt_task_delete(handler);
intcnt = maxcnt;
return 0;
}
static void *square_handler(void *args)
{
RT_TASK *handler;
RTIME period;
if (!(handler = rt_task_init_schmod(nam2num("SQHDLR"), 0, 0, 0, SCHED_FIFO, 0xF))) {
printf("CANNOT INIT HANDLER TASK > SQHDLR <\n");
exit(1);
}
rt_allow_nonroot_hrt();
mlockall(MCL_CURRENT | MCL_FUTURE);
rt_set_oneshot_mode();
start_rt_timer(0);
period = nano2count(PERIOD);
rt_make_hard_real_time();
endsquare = 0;
rt_task_make_periodic(handler, rt_get_time() + period, period);
while ( !endsquare ) {
outb_p(0, BASEPORT);
rt_task_wait_period();
outb_p(255, BASEPORT);
rt_task_wait_period();
}
stop_rt_timer();
rt_make_soft_real_time();
rt_task_delete(handler);
intcnt = maxcnt;
return 0;
}
static pthread_t thread, squarethread;
int main(void)
{
RT_TASK *maint;
printf("GIVE THE NUMBER OF INTERRUPTS YOU WANT TO COUNT: ");
scanf("%d", &maxcnt);
if (!(maint = rt_task_init(nam2num("MAIN"), 1, 0, 0))) {
printf("CANNOT INIT MAIN TASK > MAIN <\n");
exit(1);
}
// Create semaphore for notification when interrupt occurs
// In the thread we wait with rt_wait_intr until an interrupt occurs
if (!(intsem = rt_sem_init(nam2num("IRQSEM"), 0))) {
printf("CANNOT INIT SEMAPHORE > IRQSEM <\n");
exit(1);
}
// create semaphore to notify main() when interrupt occurs
if (!(dspsem = rt_sem_init(nam2num("DSPSEM"), 0))) {
printf("CANNOT INIT SEMAPHORE > DSPSEM <\n");
exit(1);
}
if (iopl(3)) { // ask for permission to access the parallel port from user-space
printf("iopl err\n");
rt_task_delete(maint);
rt_sem_delete(intsem);
rt_sem_delete(dspsem);
exit(1);
}
outb_p(0x10, BASEPORT + 2); //set port to interrupt mode; pins are output
// create thread
pthread_create(&thread, NULL, timer_handler, NULL);
// wait until thread went to hard real time
while (end) {
usleep(100000);
}
// create squarethread
pthread_create(&squarethread, NULL, square_handler, NULL);
// wait until thread went to hard real time
while (endsquare) {
usleep(100000);
}
// request the interrupt and bind it to semaphore
rt_request_global_irq(PARPORT_IRQ, intsem, USI_SEM);
rt_startup_irq(PARPORT_IRQ);
rt_enable_irq(PARPORT_IRQ);
while (intcnt < maxcnt) {
rt_sem_wait(dspsem);
printf("RETVAL %d, OVERRUNS %d, INTERRUPT COUNT %d\n", retval, ovr, intcnt);
}
end = 1;
endsquare = 1;
printf("TEST ENDS\n");
outb_p(0, BASEPORT);
outb_p(255, BASEPORT); // generate final interrupt to unblock rt_wait_intr
outb_p(0, BASEPORT);
pthread_join(thread, NULL);
pthread_join(squarethread, NULL);
rt_free_global_irq(PARPORT_IRQ);
rt_task_delete(maint);
rt_sem_delete(intsem);
rt_sem_delete(dspsem);
return 0;
}
Makefile for par_rw.c:
prefix := $(shell rtai-config --prefix)
ifeq ($(prefix),)
$(error Please add <rtai-install>/bin to your PATH variable)
endif
CC = $(shell rtai-config --cc)
LXRT_CFLAGS = $(shell rtai-config --lxrt-cflags)
LXRT_LDFLAGS = $(shell rtai-config --lxrt-ldflags)
all: par_rw
par_rw: par_rw.c
$(CC) $(LXRT_CFLAGS) -o $@ $< $(LXRT_LDFLAGS)
clean:
rm -f *.o par_rw
.PHONY: clean
Insert the modules with "loadmods.sh":
#!/bin/sh
TMP=$PWD
cd /usr/realtime/modules/
KERNELVERSION=`uname -r | awk '{print substr($1,1,3)}'`
if [ "$KERNELVERSION" = "2.6" ]
then
insmod ./rtai_hal.ko
insmod ./rtai_lxrt.ko
insmod ./rtai_sem.ko
insmod ./rtai_tasklets.ko
insmod ./rtai_usi.ko
cd $TMP
else
insmod ./rtai_hal.o
insmod ./rtai_lxrt.o
insmod ./rtai_sem.o
insmod ./rtai_tasklets.o
insmod ./rtai_usi.o
cd $TMP
fi
Remove the modules with "rmmods.sh":
#!/bin/sh
rmmod rtai_usi
rmmod rtai_tasklets
rmmod rtai_sem
rmmod rtai_lxrt
rmmod rtai_hal
Last-Modified: Sat, 04 Feb 2006 16:13:55 GMT