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      


UPDATE: Click here if you have problems with the interrupt and check the changed syntax of request_irq in the kernel

Serial Port (RS232) Interrupt Kernel Module Examples - Simple Device Driver:

Two kernel modules (RTAI hard real time and normal soft real time) for capturing the serial port interrupt when modem status lines like Carrier Detect (CD), Data Set Ready (DSR) and Clear To Send (CTS) change their state. This can be used i.e. for counting events.
In order to test this module you need a simple cable:
Connect one of the parallel port data output pins (D0-D7; pin2-9) with Clear To Send (CTS) on the first serial port (pin8 on a SUB-D9; pin5 on a SUB-D25). Ground (GND) is i.e. pin18 on the parallel port and pin5 on a SUB-D9; pin7 on a SUB-D25 on the serial port.


Connect the cable to the parallel port and ttyS0 (1. serial port), compile the modules, load one and check the kernel log file for the generated messages.

First one "ctsint.c" measures the parallel port interrupt latency with RTAI (real-time linux).
The second example shows how to handle the irq's without hard real time.

Since a serial interrupt is generated when the parallel port signal goes high *and* goes low, there are 2x2 serial port messages in the kernel log. Only the first latency is correct, since the start time for the second latency is not correct. Change this if you want.

This examples are derived from the parallel port kernel modules and therefore also measure the parallel port latency if one data pin of the par port is connected to the INT/ACK line (pin10) of the parallel port.

For further details on the pin-out and registers of the serial port see: Serial (RS232) Port Pins and Registers

Developed on kernel 2.6.7 / RTAI 3.1 with gcc 3.3.4 and gcc 2.95.4

Example "ctsint.c" (RTAI hard real time)
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <rtai.h>
#include <rtai_sched.h>

#define PARPORT 0x378
#define SERPORT 0x3F8

static int time;
static int time2;
static int timex;
static int timex2;

static int stime;
static int stime2;
static int stimex;
static int stimex2;

static void handler(void)
{
	int timediff;
	time2 = rt_get_time_ns();
	timex2 = rt_get_cpu_time_ns();
	timediff = time2 - time;
	rt_printk(">>> parallel port interrupt latency = %d ns\n", timediff);
	timediff = timex2 - timex;
	rt_printk(">>> parallel port interrupt latency = %d ns\n", timediff);
	rt_ack_irq(7);
}

static void handler2(void)
{
	int tmp;
	int timediff;
	stime2 = rt_get_time_ns();
	stimex2 = rt_get_cpu_time_ns();
	timediff = stime2 - stime;
	rt_printk(">>> serial port interrupt latency = %d ns\n", timediff);
	timediff = stimex2 - stimex;
	rt_printk(">>> serial port interrupt latency = %d ns\n", timediff);
	tmp = inb_p( SERPORT + 5);
	tmp = inb_p( SERPORT + 6);
	rt_ack_irq(4);
}

int xinit_module(void)
{
	int ret;
	ret = rt_request_global_irq(7, (void *)handler);
	if (ret)	{ printk ("##### error requesting irq 7: returned %d\n", ret); }	
	rt_enable_irq(7);
	
	outb_p(0, SERPORT + 3); // reset DLAB
	outb_p(0, SERPORT + 1);

	ret = rt_request_global_irq(4, (void *)handler2);
	if (ret)	{ printk ("##### error requesting irq 4: returned %d\n", ret); }	
	rt_enable_irq(4);

	outb_p(0, SERPORT + 3);
	outb_p(0xC7, SERPORT + 2);
	outb_p(0x0B, SERPORT + 4);

	// Bit 3 Enable Modem Status Interrupt
	//	Bit 2 Enable Receiver Line Status Interrupt 
	outb_p(0x0C, SERPORT + 1); 	
	
	outb_p(0x10, PARPORT + 2); //set port to interrupt mode; pins are output

	rt_printk("Generating interrupt now on all output pins (intr/ACK = pin 10)\n");
	
	//generate interrupt
	outb_p(0, PARPORT);
	rt_set_oneshot_mode();
	time = rt_get_time_ns();
	timex = rt_get_cpu_time_ns();
	stime = rt_get_time_ns();
	stimex = rt_get_cpu_time_ns();
	outb_p(255, PARPORT);
	outb_p(0, PARPORT);
	rt_printk("Interrupt generated. You should see the latency messages\n");
	return 0;
}

void xcleanup_module(void)
{
	rt_printk("Unloading serial port test\n");
	rt_disable_irq(4);
	outb_p(0, SERPORT + 3);  // disable DLAB
	outb_p(0, SERPORT + 1); // disable serial ints
	rt_free_global_irq(4);
	rt_disable_irq(7);
	rt_free_global_irq(7);
}

module_init(xinit_module);
module_exit(xcleanup_module);
MODULE_LICENSE("GPL");
Makefile for ctsint.c: (kernel 2.4)
TARGET	:= ctsint
INCLUDE	:= -I/lib/modules/`uname -r`/build/include -I/usr/realtime/include
CFLAGS	:= -O2 -Wall -DMODULE -DUSEFIFO -D__KERNEL__ -DLINUX
CC	:= gcc

${TARGET}.o: ${TARGET}.c
	$(CC) $(CFLAGS) ${INCLUDE} -c ${TARGET}.c


Makefile for ctsint.c: (kernel 2.6)
obj-m	:= ctsint.o

KDIR	:= /lib/modules/$(shell uname -r)/build
PWD	:= $(shell pwd)
EXTRA_CFLAGS := -I/usr/realtime/include -I/usr/include/

default:
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
Insert the modules with: (kernel 2.4)
#!/bin/sh

TMP=$PWD
cd /usr/realtime/modules/

check=`lsmod | grep -c "^rtai_hal"`
if [ $check == 0 ]
then
	insmod ./rtai_hal.o
fi

check=`lsmod | grep -c "^rtai_ksched"`
if [ $check == 0 ]
then
	insmod ./rtai_ksched.o
fi

cd $TMP

check=`lsmod | grep -c "^ctsint"`
if [ $check == 0 ]
then
	insmod ./ctsint.o
else
	rmmod ctsint
	insmod ./ctsint.o
fi
Insert the modules with: (kernel 2.6)
#!/bin/sh
TMP=$PWD
cd /usr/realtime/modules/

check=`lsmod | grep -c "^rtai_hal"`
if [ $check == 0 ]
then
	insmod ./rtai_hal.ko
fi

check=`lsmod | grep -c "^rtai_up"`
if [ $check == 0 ]
then
	insmod ./rtai_ksched.ko
fi

cd $TMP

check=`lsmod | grep -c "^ctsint"`
if [ $check == 0 ]
then
	insmod ./ctsint.ko
else
	rmmod ctsint
	insmod ./ctsint.ko
fi
Remove the modules with:
#!/bin/sh
rmmod ctsint
rmmod rtai_ksched
#rmmod rtai_up
rmmod rtai_hal




Example "ctsint.c" (soft real-time):
#include <linux/module.h>
#include <linux/interrupt.h>
#include <asm/io.h>

#define PARPORT 0x378
#define SERPORT 0x3F8

static int handler(void)
{
	// do stuff
	int tmp;
	printk(">>> SERIAL PORT CTS INT HANDLED\n");
	// read  Line Status Register & Modem Status Register to ACK IRQ
	tmp = inb_p( SERPORT + 5);
	tmp = inb_p( SERPORT + 6);
	return IRQ_HANDLED;
}
static int handler2(void)
{
	// do stuff
	printk(">>> PARALLEL PORT INT HANDLED\n");
	return IRQ_HANDLED;
}

int xinit_module(void)
{
	int ret;
	int ret2;
	
	ret = request_irq(7, handler2, SA_INTERRUPT, "parallelport", handler2);
	if (ret)	{ printk ("##### error requesting irq 7: returned %d\n", ret); }	
	enable_irq(7);

	outb_p(0, SERPORT + 3); // reset DLAB
	outb_p(0, SERPORT + 1);

	ret = request_irq(4, handler, SA_INTERRUPT, "serialport", handler);
	if (ret)	{ printk ("##### error requesting irq 4: returned %d\n", ret); }	
	enable_irq(4);

	outb_p(0, SERPORT + 3);
	outb_p(0xC7, SERPORT + 2);
	outb_p(0x0B, SERPORT + 4);

	// Bit 3 Enable Modem Status Interrupt
	//	Bit 2 Enable Receiver Line Status Interrupt 
	outb_p(0x0C, SERPORT + 1);

	//set port to interrupt mode; pins are output
	outb_p(0x10, PARPORT + 2); 

	printk("Generating interrupt now on all PARALLEL PORT output pins\n");
	printk(" Serial Port: CTS = pin 8 on SUB-D9\n");
	printk(" Parallel Port: intr/ACK = pin 10\n");
	
	//generate interrupt
	outb_p(0, PARPORT);
	outb_p(255, PARPORT);
	outb_p(0, PARPORT);
	printk("Interrupt generated. You should see the handler-messages\n");
	return 0;
}

void xcleanup_module(void)
{
	disable_irq(4);
	outb_p(0, SERPORT + 3);  // disable DLAB
	outb_p(0, SERPORT + 1); // disable serial ints
	free_irq(4, handler);
	disable_irq(7);
	free_irq(7, handler2);
	printk("MODULE REMOVED!\n");
}

module_init(xinit_module);
module_exit(xcleanup_module);
MODULE_LICENSE("GPL");
Makefile for ctsint.c: (kernel 2.4)
TARGET	:= ctsint
INCLUDE	:= -I/lib/modules/`uname -r`/build/include
CFLAGS	:= -O2 -Wall -DMODULE -D__KERNEL__ -DLINUX
CC	:= gcc

${TARGET}.o: ${TARGET}.c
	$(CC) $(CFLAGS) ${INCLUDE} -c ${TARGET}.c
Makefile for ctsint.c: (kernel 2.6)
obj-m	:= ctsint.o

KDIR	:= /lib/modules/$(shell uname -r)/build
PWD		:= $(shell pwd)

default:
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
Insert the module with: (kernel 2.4)
# insmod ./ctsint.o
Insert the module with: (kernel 2.6)
# insmod ./ctsint.ko
Remove the module with:
# rmmod ctsint


Last-Modified: Tue, 17 Jun 2008 18:30:08 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