// Frequency and impulse counter program which uses the parallel port IRQ. // Based: http://linuxdevices.com/articles/AT9847654820.html // // Successfully tested from 0 to 270 kHz. // 2005-6 by Rolf Freitag #include #include #include #include #define FIFO_R 0 #define FIFO_W 1 #define TIMERTICKS 1000000000 // 1 second #define STACK_SIZE 4096 #define FIFO_SIZE 1024 // parallel port: usually 0x378, IRQ 7 for the first; 0x278, IRQ 5 for the second ... #define PAR_IRQ 7 #define PAR_BASE 0x378 MODULE_LICENSE ("GPL"); // count0: total irq count, count1: frequency volatile unsigned long long int count0, count1; static RT_TASK my_task; static void fun (int t) { static unsigned long long int old_count, i_tmp; for (;;) { i_tmp = count0; count1 = i_tmp - old_count; // frequency = impulses in one second old_count = i_tmp; rt_task_wait_period (); } } int fifo_handler (unsigned int fifo) { char c; rtf_get (FIFO_R, &c, sizeof (c)); // output: count0 for interrupt count till start, count1: frequency switch (c) { case 0: rtf_put (FIFO_W, &count0, sizeof (count0)); break; default: case 1: rtf_put (FIFO_W, &count1, sizeof (count1)); break; } return 0; } static void handler (void) { count0++; } int init_module (void) { RTIME tick_period, now; int i_retval; count0 = 0; count1 = 0; rt_set_periodic_mode (); rt_task_init (&my_task, fun, 0, STACK_SIZE, 0, 0, 0); tick_period = start_rt_timer (nano2count (TIMERTICKS)); now = rt_get_time (); rt_task_make_periodic (&my_task, now + tick_period, tick_period); rtf_create (FIFO_R, FIFO_SIZE); rtf_create (FIFO_W, FIFO_SIZE); rtf_create_handler (FIFO_R, fifo_handler); rtf_reset (FIFO_R); rt_free_global_irq (PAR_IRQ); i_retval = rt_request_global_irq (PAR_IRQ, handler); if (i_retval) { if (i_retval == -EINVAL) { /* irq is not a valid IRQ number or handler is null */ printk ("invalid IRQ\n"); } else if (i_retval == -EBUSY) { /* already a handler */ printk ("IRQ already assigned by RTAI\n"); } return (retval); } rt_startup_irq (PAR_IRQ); rt_enable_irq (PAR_IRQ); outb (0x3b, PAR_BASE + 2); // interrupt enable, data port to input, all controll pins low return (0); } void cleanup_module (void) { outb (0x0b, PAR_BASE + 2); // interrupt disable, data port to output, all controll pins low stop_rt_timer (); rt_busy_sleep (10000000); rt_task_delete (&my_task); rt_disable_irq (PAR_IRQ); rt_shutdown_irq (PAR_IRQ); rt_free_global_irq (PAR_IRQ); rtf_destroy (FIFO_R); rtf_destroy (FIFO_W); }