This is the mail archive of the ecos-patches@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Microsecond delay fix


This fixes problems with timers that have large values for
CYGNUM_KERNEL_COUNTERS_RTC_PERIOD.

Before I check this in I would like some others to look it over and
check that the logic is right.



Index: ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/common/current/ChangeLog,v
retrieving revision 1.88
diff -u -5 -r1.88 ChangeLog
--- ChangeLog	3 Mar 2003 17:09:56 -0000	1.88
+++ ChangeLog	31 Mar 2003 17:29:52 -0000
@@ -1,5 +1,10 @@
+2003-03-31  Nick Garnett  <nickg at balti dot calivar dot com>
+
+	* src/hal_if.c (delay_us): Reorganized to cope with high frequency
+	timers by eliminating a source of arithmetic overflow. 
+
 2003-03-03  Knud Woehler <knud dot woehler at microplex dot de>
 
 	* src/hal_if.c:
 	* include/hal_if.h: Add CYGNUM_CALL_IF_FLASH_FIS_OP. FIS read
 	via the virtual vector table.
Index: src/hal_if.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/common/current/src/hal_if.c,v
retrieving revision 1.22
diff -u -5 -r1.22 hal_if.c
--- src/hal_if.c	3 Mar 2003 17:09:56 -0000	1.22
+++ src/hal_if.c	31 Mar 2003 17:29:54 -0000
@@ -8,10 +8,11 @@
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
 // Copyright (C) 2002 Gary Thomas
+// Copyright (C) 2003 Nick Garnett <nickg at calivar dot com>
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
 //
@@ -32,12 +33,12 @@
 // in accordance with section (3) of the GNU General Public License.
 //
 // This exception does not invalidate any other reasons why a work based on
 // this file might be covered by the GNU General Public License.
 //
-// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
-// at http://sources.redhat.com/ecos/ecos-license/
+// Alternative licenses for eCos may be arranged by contacting the copyright
+// holders.
 // -------------------------------------------
 //####ECOSGPLCOPYRIGHTEND####
 //=============================================================================
 //#####DESCRIPTIONBEGIN####
 //
@@ -158,37 +159,65 @@
 delay_us(cyg_int32 usecs)
 {
     CYGARC_HAL_SAVE_GP();
 #ifdef CYGPKG_KERNEL
     {
-        cyg_int32 start, elapsed;
-        cyg_int32 usec_ticks, slice;
-
-        // How many ticks total we should wait for.
-        usec_ticks = usecs*CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
-        usec_ticks /= CYGNUM_HAL_RTC_NUMERATOR/CYGNUM_HAL_RTC_DENOMINATOR/1000;
-
+        cyg_int32 start, elapsed, elapsed_usec;
+        cyg_int32 slice;
+        cyg_int32 usec_per_period = CYGNUM_HAL_RTC_NUMERATOR/CYGNUM_HAL_RTC_DENOMINATOR/1000;
+        cyg_int32 ticks_per_usec = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD/usec_per_period;
+        
         do {
             // Spin in slices of 1/2 the RTC period. Allows interrupts
-            // time to run without messing up the algorithm. If we spun
-            // for 1 period (or more) of the RTC, there'd be also problems
-            // figuring out when the timer wrapped.  We may lose a tick or
-            // two for each cycle but it shouldn't matter much.
-            slice = usec_ticks % (CYGNUM_KERNEL_COUNTERS_RTC_PERIOD / 2);
+            // time to run without messing up the algorithm. If we
+            // spun for 1 period (or more) of the RTC, there would also
+            // be problems figuring out when the timer wrapped.  We
+            // may lose a tick or two for each cycle but it shouldn't
+            // matter much.
+
+            // The test against CYGNUM_KERNEL_COUNTERS_RTC_PERIOD
+            // checks for a value that would cause a 32 bit signed
+            // multiply to overflow. But this also implies that just
+            // multiplying by ticks_per_usec will yield a good
+            // approximation.  Otherwise we need to do the full
+            // multiply+divide to get sufficient accuracy. Note that
+            // this test is actually constant, so the compiler will
+            // eliminate it and only compile the branch that is
+            // selected.
+            
+            if( usecs > usec_per_period/2 )
+                slice = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD/2;
+            else if( CYGNUM_KERNEL_COUNTERS_RTC_PERIOD >= 0x7FFFFFFF/usec_per_period )
+                slice = usecs * ticks_per_usec;
+            else
+            {
+                slice = usecs*CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
+                slice /= usec_per_period;
+            }
     
             HAL_CLOCK_READ(&start);
             do {
                 HAL_CLOCK_READ(&elapsed);
                 elapsed = (elapsed - start); // counts up!
                 if (elapsed < 0)
                     elapsed += CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
             } while (elapsed < slice);
             
-            // Adjust by elapsed, not slice, since an interrupt may have
-            // been stalling us for some time.
-            usec_ticks -= elapsed;
-        } while (usec_ticks > 0);
+            // Adjust by elapsed, not slice, since an interrupt may
+            // have been stalling us for some time.
+
+            if( CYGNUM_KERNEL_COUNTERS_RTC_PERIOD >= 0x7FFFFFFF/usec_per_period )
+                elapsed_usec = elapsed / ticks_per_usec;
+            else
+            {
+                elapsed_usec = elapsed * usec_per_period;
+                elapsed_usec = elapsed_usec / CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
+            }
+
+            usecs -= elapsed_usec;
+            
+        } while (usecs > 0);
     }
 #else // CYGPKG_KERNEL
 #ifdef HAL_DELAY_US
     // Use a HAL feature if defined
     HAL_DELAY_US(usecs);


-- 
Nick Garnett                    eCos Kernel Architect
http://www.ecoscentric.com/     The eCos and RedBoot experts


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]