00001 /* Timer example for 68HC11 00002 Copyright (C) 2000, 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 00039 #include "timer.h" 00040 00041 #ifdef USE_INTERRUPT_TABLE 00042 00043 /* Interrupt table used to connect our timer_interrupt handler. 00044 00045 Note: the `XXX_handler: foo' notation is a GNU extension which is 00046 used here to ensure correct association of the handler in the struct. 00047 This is why the order of handlers declared below does not follow 00048 the HC11 order. */ 00049 struct interrupt_vectors __attribute__((section(".vectors"))) vectors = 00050 { 00051 res0_handler: fatal_interrupt, /* res0 */ 00052 res1_handler: fatal_interrupt, 00053 res2_handler: fatal_interrupt, 00054 res3_handler: fatal_interrupt, 00055 res4_handler: fatal_interrupt, 00056 res5_handler: fatal_interrupt, 00057 res6_handler: fatal_interrupt, 00058 res7_handler: fatal_interrupt, 00059 res8_handler: fatal_interrupt, 00060 res9_handler: fatal_interrupt, 00061 res10_handler: fatal_interrupt, /* res 10 */ 00062 sci_handler: fatal_interrupt, /* sci */ 00063 spi_handler: fatal_interrupt, /* spi */ 00064 acc_overflow_handler: fatal_interrupt, /* acc overflow */ 00065 acc_input_handler: fatal_interrupt, 00066 timer_overflow_handler: fatal_interrupt, 00067 output5_handler: fatal_interrupt, /* out compare 5 */ 00068 output4_handler: fatal_interrupt, /* out compare 4 */ 00069 output3_handler: fatal_interrupt, /* out compare 3 */ 00070 output2_handler: fatal_interrupt, /* out compare 2 */ 00071 output1_handler: fatal_interrupt, /* out compare 1 */ 00072 capture3_handler: fatal_interrupt, /* in capt 3 */ 00073 capture2_handler: fatal_interrupt, /* in capt 2 */ 00074 capture1_handler: fatal_interrupt, /* in capt 1 */ 00075 irq_handler: fatal_interrupt, /* IRQ */ 00076 xirq_handler: fatal_interrupt, /* XIRQ */ 00077 swi_handler: fatal_interrupt, /* swi */ 00078 illegal_handler: fatal_interrupt, /* illegal */ 00079 cop_fail_handler: fatal_interrupt, 00080 cop_clock_handler: fatal_interrupt, 00081 00082 /* What we really need. */ 00083 rtii_handler: timer_interrupt, 00084 reset_handler: _start 00085 }; 00086 00087 #endif 00088 00089 #define TIMER_DIV (8192L) 00090 #define TIMER_TICK (M6811_CPU_E_CLOCK / TIMER_DIV) 00091 00092 unsigned long timer_count; 00093 unsigned long boot_time; 00094 00095 /* Timer interrupt handler. */ 00096 void __attribute__((interrupt)) 00097 timer_interrupt (void) 00098 { 00099 timer_count++; 00100 timer_acknowledge (); 00101 } 00102 00103 /* Returns the current number of ticks that ellapsed since we started. */ 00104 static inline unsigned long 00105 timer_get_ticks () 00106 { 00107 unsigned long t; 00108 00109 lock (); 00110 t = timer_count; 00111 unlock (); 00112 return t; 00113 } 00114 00115 /* Translate the number of ticks into some seconds. */ 00116 static unsigned long 00117 timer_seconds (unsigned long ntime) 00118 { 00119 unsigned long n; 00120 00121 /* To compute SECS = NTIME * TIMER_DIV / M6811_CPU_E_CLOCK accurately, 00122 use Bezous relation (A = BQ + R). */ 00123 n = ntime * (TIMER_DIV / M6811_CPU_E_CLOCK); 00124 n += (ntime * (TIMER_DIV % M6811_CPU_E_CLOCK)) / M6811_CPU_E_CLOCK; 00125 n += boot_time; 00126 return n; 00127 } 00128 00129 /* Translate the number of ticks into some microseconds. */ 00130 static unsigned long 00131 timer_microseconds (unsigned long ntime) 00132 { 00133 unsigned long n; 00134 00135 /* To compute SECS = NTIME * TIMER_DIV / M6811_CPU_E_CLOCK accurately, 00136 use Bezous relation (A = BQ + R). */ 00137 n = ntime * (TIMER_DIV / 2); 00138 n += (ntime * (TIMER_DIV % 2)) / 2; 00139 n = n % 1000000L; 00140 return n; 00141 } 00142 00143 /* Translate the string pointed to by *p into a number. 00144 Update *p to point to the end of that number. */ 00145 static unsigned short 00146 get_value (char **p) 00147 { 00148 char *q; 00149 unsigned short val; 00150 00151 q = *p; 00152 while (*q == ' ') 00153 q++; 00154 00155 val = 0; 00156 while (1) 00157 { 00158 char c = *q++; 00159 if (c < '0' || c > '9') 00160 break; 00161 val = (val * 10) + (c - '0'); 00162 } 00163 q--; 00164 *p = q; 00165 return val; 00166 } 00167 00168 /* Ask for the boot time. */ 00169 static void 00170 get_time () 00171 { 00172 char buf[32]; 00173 int pos; 00174 char c; 00175 unsigned short hours, mins, secs; 00176 char *p; 00177 int error = 0; 00178 00179 print ("\r\nBoot time ? "); 00180 pos = 0; 00181 while (1) 00182 { 00183 c = serial_recv (); 00184 if (c == '\r' || c == '\n') 00185 break; 00186 00187 if (c == '\b') 00188 { 00189 print ("\b \b"); 00190 pos--; 00191 if (pos < 0) 00192 pos = 0; 00193 } 00194 else if (pos < sizeof (buf) - 1) 00195 { 00196 buf[pos] = c; 00197 buf[pos+1] = 0; 00198 print (&buf[pos]); 00199 pos++; 00200 } 00201 } 00202 00203 print ("\n"); 00204 buf[pos] = 0; 00205 p = buf; 00206 hours = get_value (&p); 00207 if (*p++ != ':') 00208 error = 1; 00209 mins = get_value (&p); 00210 if (*p++ != ':' || mins >= 60) 00211 error = 1; 00212 secs = get_value (&p); 00213 if (*p++ != 0 || secs >= 60) 00214 error = 1; 00215 00216 if (error == 0) 00217 { 00218 boot_time = (hours * 3600) + (mins * 60) + (secs); 00219 print ("Boot time is set.\r\n"); 00220 } 00221 else 00222 { 00223 print ("Invalid boot time.\r\n"); 00224 print ("Format is: HH:MM:SS\r\n"); 00225 } 00226 } 00227 00228 /* Display the current time on the serial line. */ 00229 static void 00230 display_time (unsigned long ntime) 00231 { 00232 unsigned long seconds; 00233 unsigned short hours, mins; 00234 unsigned long nus; 00235 char buf[12]; 00236 00237 static unsigned long last_sec = 0xffffffff; 00238 static unsigned long last_us = 0; 00239 00240 /* Translate the number of ticks in seconds and milliseconds. */ 00241 seconds = timer_seconds (ntime); 00242 nus = timer_microseconds (ntime); 00243 00244 nus = nus / 100000L; 00245 00246 /* If the seconds changed, re-display everything. */ 00247 if (seconds != last_sec) 00248 { 00249 last_sec = seconds; 00250 last_us = nus; 00251 hours = (unsigned short) (seconds / 3600L); 00252 mins = (unsigned short) (seconds % 3600L); 00253 seconds = (unsigned long) (mins % 60); 00254 mins = mins / 60; 00255 buf[0] = '0' + (hours / 10); 00256 buf[1] = '0' + (hours % 10); 00257 buf[2] = ':'; 00258 buf[3] = '0' + (mins / 10); 00259 buf[4] = '0' + (mins % 10); 00260 buf[5] = ':'; 00261 buf[6] = '0' + (seconds / 10); 00262 buf[7] = '0' + (seconds % 10); 00263 buf[8] = '.'; 00264 buf[9] = '0' + nus; 00265 buf[10] = 0; 00266 serial_print ("\r"); 00267 serial_print (buf); 00268 } 00269 00270 /* Only re-display the tens of a second. */ 00271 else if (last_us != nus) 00272 { 00273 last_us = nus; 00274 buf[0] = '0' + nus; 00275 buf[1] = 0; 00276 serial_print ("\b"); 00277 serial_print (buf); 00278 } 00279 serial_flush (); 00280 } 00281 00282 int 00283 main () 00284 { 00285 unsigned long prev_time; 00286 00287 serial_init (); 00288 lock (); 00289 boot_time = 0; 00290 timer_count = 0; 00291 00292 /* Set interrupt handler for bootstrap mode. */ 00293 set_interrupt_handler (RTI_VECTOR, timer_interrupt); 00294 00295 /* Initialize the timer. */ 00296 timer_initialize_rate (M6811_TPR_16); 00297 prev_time = timer_count; 00298 00299 unlock (); 00300 00301 /* Ask for the boot time. */ 00302 get_time (); 00303 00304 /* Loop waiting for the time to change and redisplay it. */ 00305 while (1) 00306 { 00307 unsigned long ntime; 00308 00309 /* Reset the COP (in case it is active). */ 00310 cop_optional_reset (); 00311 00312 /* If something is received on the serial line, 00313 ask for the boot time again. */ 00314 if (serial_receive_pending ()) 00315 get_time (); 00316 00317 /* Get current time and see if we must re-display it. */ 00318 ntime = timer_get_ticks (); 00319 if (ntime != prev_time) 00320 { 00321 prev_time = ntime; 00322 display_time (ntime); 00323 } 00324 } 00325 }