Captain's Universe Home
Captain's Universe Home
Cosmic Ray Muon DetectorTeleGarden Pages
Time on MarsBryophyllum Plants
Jupiter Radio AstronomyAncient Pages
Salzburg Tourist GuideEarth Magnetometer
  H O M E     AJAX & MORE     LINUX & MORE     RTAI     XENOMAI     ADEOS IPIPE      
    JAVA & BROWSERS     *NIX     ELECTRONICS     REVIEWS     ARTEMIA     FAIRY SHRIMP      



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

Google
 
Web www.captain.at
go to top
© 1996-2010 . All rights reserved.
No reproduction, distribution, publishing or transmission of the copyrighted materials at this site is permitted. Policy
go to top