This is the mail archive of the
ecos-patches@sources.redhat.com
mailing list for the eCos project.
Microsecond delay fix
- From: Nick Garnett <nickg at ecoscentric dot com>
- To: ecos-patches at sources dot redhat dot com
- Date: 31 Mar 2003 17:34:55 +0000
- Subject: 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