pulse.c

00001 /* Pulse Generator
00002    Copyright (C) 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 
00088 #include <sys/param.h>
00089 #include <sys/ports.h>
00090 #include <sys/interrupts.h>
00091 #include <sys/sio.h>
00092 #include <sys/locks.h>
00093 
00094 void output_compare_interrupt (void) __attribute__((interrupt));
00095 
00096 #define US_TO_CYCLE(N) ((N) * 2)
00097 
00098 /* The cycle table defines the sequence of pulses to generate.
00099    Each value indicates the number of cycles to wait before inverting
00100    the output pin.  The US_TO_CYCLE macro makes the translation so
00101    that values can be expressed in microseconds (assuming QZ at 8Mhz).
00102 
00103    Note: A value below 100 cycles will produce a 32ms pulse because
00104    we are not that fast to update the next output compare value.  */
00105 static const unsigned short cycle_table[] = {
00106    US_TO_CYCLE (500),
00107    US_TO_CYCLE (500),
00108    US_TO_CYCLE (500),
00109    US_TO_CYCLE (1000),
00110    US_TO_CYCLE (1000),
00111    US_TO_CYCLE (5000),
00112    US_TO_CYCLE (100),
00113    US_TO_CYCLE (500),
00114    US_TO_CYCLE (5000),
00115    US_TO_CYCLE (1000),
00116    US_TO_CYCLE (100),
00117    US_TO_CYCLE (100)
00118 };
00119 
00120 #define TABLE_SIZE(T) ((sizeof T / sizeof T[0]))
00121 
00122 #ifdef USE_INTERRUPT_TABLE
00123 
00124 /* Interrupt table used to connect our timer_interrupt handler.
00125 
00126    Note: the `XXX_handler: foo' notation is a GNU extension which is
00127    used here to ensure correct association of the handler in the struct.
00128    This is why the order of handlers declared below does not follow
00129    the HC11 order.  */
00130 struct interrupt_vectors __attribute__((section(".vectors"))) vectors = 
00131 {
00132   res0_handler:           fatal_interrupt, /* res0 */
00133   res1_handler:           fatal_interrupt,
00134   res2_handler:           fatal_interrupt,
00135   res3_handler:           fatal_interrupt,
00136   res4_handler:           fatal_interrupt,
00137   res5_handler:           fatal_interrupt,
00138   res6_handler:           fatal_interrupt,
00139   res7_handler:           fatal_interrupt,
00140   res8_handler:           fatal_interrupt,
00141   res9_handler:           fatal_interrupt,
00142   res10_handler:          fatal_interrupt, /* res 10 */
00143   sci_handler:            fatal_interrupt, /* sci */
00144   spi_handler:            fatal_interrupt, /* spi */
00145   acc_overflow_handler:   fatal_interrupt, /* acc overflow */
00146   acc_input_handler:      fatal_interrupt,
00147   timer_overflow_handler: fatal_interrupt,
00148   output5_handler:        fatal_interrupt, /* out compare 5 */
00149   output3_handler:        fatal_interrupt, /* out compare 3 */
00150   output2_handler:        fatal_interrupt, /* out compare 2 */
00151   output1_handler:        fatal_interrupt, /* out compare 1 */
00152   capture3_handler:       fatal_interrupt, /* in capt 3 */
00153   capture2_handler:       fatal_interrupt, /* in capt 2 */
00154   capture1_handler:       fatal_interrupt, /* in capt 1 */
00155   rtii_handler:           fatal_interrupt,
00156   irq_handler:            fatal_interrupt, /* IRQ */
00157   xirq_handler:           fatal_interrupt, /* XIRQ */
00158   swi_handler:            fatal_interrupt, /* swi */
00159   illegal_handler:        fatal_interrupt, /* illegal */
00160   cop_fail_handler:       fatal_interrupt,
00161   cop_clock_handler:      fatal_interrupt,
00162 
00163   /* What we really need.  */
00164   output4_handler:        output_compare_interrupt, /* out compare 4 */
00165   reset_handler:          _start
00166 };
00167 
00168 #endif
00169 
00170 static const unsigned short* cycle_next;
00171 static volatile unsigned char wakeup;
00172 static unsigned short change_time;
00173 
00174 /* Output compare interrupt to setup the new timer.  */
00175 void
00176 output_compare_interrupt (void)
00177 {
00178   unsigned short dt;
00179 
00180   _io_ports[M6811_TFLG1] |= M6811_OC4F;
00181 
00182   /* Setup the new output compare as soon as we can.  */
00183   dt = *cycle_next;
00184   dt += change_time;
00185   set_output_compare_4 (dt);
00186   change_time = dt;
00187 
00188   /* Prepare for the next interrupt.  */
00189   cycle_next++;
00190   if (cycle_next >= &cycle_table[TABLE_SIZE (cycle_table)])
00191     cycle_next = cycle_table;
00192 
00193   wakeup = 1;
00194 }
00195 
00196 int
00197 main ()
00198 {
00199   unsigned short j;
00200   unsigned char c = 0;
00201   unsigned char i = 0;
00202   
00203   lock ();
00204   serial_init ();
00205 
00206   /* Install the interrupt handler (unless we use the interrupt table).  */
00207   set_interrupt_handler (TIMER_OUTPUT4_VECTOR, output_compare_interrupt);
00208 
00209   cycle_next = cycle_table;
00210 
00211   /* Set OC4 compare to toggle the output pin.  */
00212   _io_ports[M6811_TCTL1] = M6811_OL4;
00213   _io_ports[M6811_TMSK1] = M6811_OC4I;
00214 
00215   /* Start the pulse generation.  */
00216   change_time = get_timer_counter () + 300;
00217   set_output_compare_4 (change_time);
00218   unlock ();
00219 
00220   for (j = 0; j < 1000; j++)
00221     {
00222       /* Wait for the output compare interrupt to be raised.  */
00223       wakeup = 0;
00224       while (wakeup == 0)
00225         continue;
00226 
00227       /* Produce some activity on serial line so that we know
00228          it is running and interrupts are raised/caught correctly.  */
00229       c++;
00230       if (c == 1)
00231         serial_send ('\b');
00232       else if (c == 128)
00233         serial_send ("-\\|/"[(++i) & 3]);
00234     }
00235   return 0;
00236 }