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 }