freqmeter.c

00001 /* Simple Frequency meter.
00002    Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
00003    Written by Stephane Carrez (stcarrez@nerim.fr)       
00004 
00005 This file is free software; you can redistribute it and/or modify it
00006 under the terms of the GNU General Public License as published by the
00007 Free Software Foundation; either version 2, or (at your option) any
00008 later version.
00009 
00010 In addition to the permissions in the GNU General Public License, the
00011 Free Software Foundation gives you unlimited permission to link the
00012 compiled version of this file with other programs, and to distribute
00013 those programs without any restriction coming from the use of this
00014 file.  (The General Public License restrictions do apply in other
00015 respects; for example, they cover modification of the file, and
00016 distribution when not linked into another program.)
00017 
00018 This file is distributed in the hope that it will be useful, but
00019 WITHOUT ANY WARRANTY; without even the implied warranty of
00020 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021 General Public License for more details.
00022 
00023 You should have received a copy of the GNU General Public License
00024 along with this program; see the file COPYING.  If not, write to
00025 the Free Software Foundation, 59 Temple Place - Suite 330,
00026 Boston, MA 02111-1307, USA.  */
00027 
00050 #include <stdio.h>
00051 #include <sys/param.h>
00052 #include <sys/ports.h>
00053 #include <sys/interrupts.h>
00054 #include <sys/sio.h>
00055 #include <sys/locks.h>
00056 
00057 #define TIMER_DIV  (8192L)
00058 #define TIMER_TICK (M6811_CPU_E_CLOCK / TIMER_DIV)
00059 
00060 /* Setup for a 8Mhz quartz, and prescaler set to 1
00061    (500ns period).  */
00062 #define USEC_PER_TICK (1)
00063 #define USEC_DIVISOR  (2)
00064 
00065 unsigned short prev_time;
00066 unsigned long dt_sum;
00067 unsigned short dt_count;
00068 
00069 unsigned long tick_sum;
00070 unsigned short m_count;
00071 
00072 volatile unsigned char new_measure = 0;
00073 
00074 void input_capture_interrupt (void) __attribute__((interrupt));
00075 void timer_overflow_interrupt (void) __attribute__((interrupt));
00076 
00077 #ifdef USE_INTERRUPT_TABLE
00078 
00079 /* Interrupt table used to connect our timer_interrupt handler.
00080 
00081    Note: the `XXX_handler: foo' notation is a GNU extension which is
00082    used here to ensure correct association of the handler in the struct.
00083    This is why the order of handlers declared below does not follow
00084    the HC11 order.  */
00085 struct interrupt_vectors __attribute__((section(".vectors"))) vectors = 
00086 {
00087   res0_handler:           fatal_interrupt, /* res0 */
00088   res1_handler:           fatal_interrupt,
00089   res2_handler:           fatal_interrupt,
00090   res3_handler:           fatal_interrupt,
00091   res4_handler:           fatal_interrupt,
00092   res5_handler:           fatal_interrupt,
00093   res6_handler:           fatal_interrupt,
00094   res7_handler:           fatal_interrupt,
00095   res8_handler:           fatal_interrupt,
00096   res9_handler:           fatal_interrupt,
00097   res10_handler:          fatal_interrupt, /* res 10 */
00098   sci_handler:            fatal_interrupt, /* sci */
00099   spi_handler:            fatal_interrupt, /* spi */
00100   acc_overflow_handler:   fatal_interrupt, /* acc overflow */
00101   acc_input_handler:      fatal_interrupt,
00102   output5_handler:        fatal_interrupt, /* out compare 5 */
00103   output4_handler:        fatal_interrupt, /* out compare 4 */
00104   output3_handler:        fatal_interrupt, /* out compare 3 */
00105   output2_handler:        fatal_interrupt, /* out compare 2 */
00106   output1_handler:        fatal_interrupt, /* out compare 1 */
00107   capture3_handler:       fatal_interrupt, /* in capt 3 */
00108   capture2_handler:       fatal_interrupt, /* in capt 2 */
00109   rtii_handler:           fatal_interrupt,
00110   irq_handler:            fatal_interrupt, /* IRQ */
00111   xirq_handler:           fatal_interrupt, /* XIRQ */
00112   swi_handler:            fatal_interrupt, /* swi */
00113   illegal_handler:        fatal_interrupt, /* illegal */
00114   cop_fail_handler:       fatal_interrupt,
00115   cop_clock_handler:      fatal_interrupt,
00116 
00117   /* What we really need.  */
00118   capture1_handler:       input_capture_interrupt, /* in capt 1 */
00119   timer_overflow_handler: timer_overflow_interrupt,
00120   reset_handler:          _start
00121 };
00122 
00123 #endif
00124 
00125 void __attribute__((interrupt))
00126 input_capture_interrupt (void)
00127 {
00128   unsigned short t;
00129   unsigned short dt;
00130   
00131   t = get_input_capture_1 ();
00132   if (t > prev_time)
00133     {
00134       dt = t - prev_time;
00135       dt_sum += dt;
00136       dt_count++;
00137     }
00138   prev_time = t;
00139   _io_ports[M6811_TFLG1] |= M6811_IC1F;
00140 }
00141 
00142 void __attribute__((interrupt))
00143 timer_overflow_interrupt (void)
00144 {
00145   static unsigned char nr_overflow = 100;
00146 
00147   nr_overflow--;
00148   if (nr_overflow == 0)
00149     {
00150       tick_sum = dt_sum;
00151       m_count = dt_count;
00152       dt_sum = 0;
00153       dt_count = 0;
00154       prev_time = 0xffff;
00155       new_measure++;
00156       nr_overflow = 100;
00157     }
00158   _io_ports[M6811_TFLG2] |= M6811_TOF;
00159 }
00160 
00161 static void
00162 report_frequency (unsigned long dt, unsigned short cnt)
00163 {
00164   if (cnt)
00165     dt = dt / cnt;
00166   dt = (dt * USEC_PER_TICK) / USEC_DIVISOR;
00167   dt = 1000000000L / dt;
00168   printf ("\rP: %ld HZ   ", dt / 1000);
00169 }
00170 
00171 int
00172 main ()
00173 {
00174   lock ();
00175   serial_init ();
00176 
00177   set_interrupt_handler (TIMER_INPUT1_VECTOR, input_capture_interrupt);
00178   set_interrupt_handler (TIMER_OVERFLOW_VECTOR, timer_overflow_interrupt);
00179 
00180   _io_ports[M6811_TMSK2] = M6811_TOI;
00181   _io_ports[M6811_TCTL2] = M6811_EDG1B | M6811_EDG2B | M6811_EDG3B;
00182   _io_ports[M6811_TMSK1] = M6811_IC1I;
00183   new_measure = 0;
00184   prev_time = 0xffff;
00185   unlock ();
00186   
00187   while (1)
00188     {
00189       while (new_measure == 0)
00190         continue;
00191 
00192       new_measure = 0;
00193       report_frequency (tick_sum, m_count);
00194     }
00195 }