timer.c

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 }