Robert,
I note you are using IOSET/IOCLR on 0x100 (P0.08). It doesn't apear to
be used by timer 0. Was it included for some other purpose?
Curt
-----Original Message-----
From: Robert Adsett [mailto:radsett@...]
Sent: Saturday, December 06, 2003 4:39 PM
To: lpc2100@yahoogroups.com
Subject: RE: [lpc2100] Delay routines
At 05:02 PM 12/5/03 -0500, you wrote:
>At 09:26 AM 12/5/03 -0800, you wrote:
> >I had looked at the timers before but it was unclear if you would
have to
> >give up GPIO pins by putting them into alternate function mode (we're
> >already pin-constricted). I'm hoping for something with this type of
> >functionality but that doesn't require giving up such vital (to us)
> >resources as i/o pins. Care to guess whether the match registers
could be
> >used without putting the i/o pins into alternate function mode?
>
>I would be surprised it they couldn't be used that way. I see two ways
of
>doing it. One is to use interrupts on match. The other is to poll the
>status bit in the external match register (That's what I'm trying
first).
A timer using timer 0. This is a first pass and still could use some
refinement and verification but it does show a method that works. Using
the instrumented set and clear in the wait routine (last routine) I get
an
11.4 uS delay when asking for 10uS which fits with the bit toggle time I
measured earlier. It works fine down to 1uS and fails at 0.1uS. I
haven't
delved further to determine just what the minimum wait time is. If you
want to time really short event (< a few microseconds) you would
probably
want to perform the wait operation in-line rather than make a function
call
otherwise the overhead becomes significant.
The real guts are in wait_ns, everything else is setup or support.
This is a polling version (no interrupts) that should keep time as long
as
a wait or time gathering call is made every minute and a half or so.
Other
than that there is no extra runtime overhead.
This code is forming a portion of a I/O library I'm building up. I
suspect
I'll back off on the resolution but I haven't decided yet.
#define CLOCK_SPEED (10000000) /* Nominal speed for internal
*/
/* clock (timer not CPU) in
Hz. */
/* Used for converting between counts and nS for time
function.*/
/* An unsigned long long so overflows are not possible during
*/
/* the conversion.
*/
#define NS_PER_COUNT (100uLL)
#define COUNTER_RESET ((unsigned char)2)
#define COUNTER_ENABLE ((unsigned char)1)
static unsigned long timing_scale_factor;
static int start_clock(
struct _reent *r)
{
unsigned long rate, divider;
rate = VPB_rate( r); /* Get the clock rate of the
*/
/* peripheral bus.
*/
if( rate == 0) {
return -1;
}
/* Set clock to reset. This will keep them at zero.
*/
T0TCR = COUNTER_RESET;
/* Calculate a divider that will cause the internal clock to
*/
/* approximate the target clock speed. This should give a
*/
/* clock counting rate between the desired rate and twice the
*/
/* desired rate.
*/
divider = rate/ CLOCK_SPEED;
if( divider == 0) { /* Sanity check on the divider. If we have a
*/
divider = 1uL; /* pclk slower than our desired rate we won't
*/
} /* be able to reach the desired rate so just
*/
/* run as fast as we can.
*/
T0PR = divider - 1; /* Set prescaler to give us our target rate.
*/
/* Since the actual clock rate we have and our target rate may
*/
/* not be the same, calculate a corrective factor for routines
*/
/* that make use of it. This value will be divided by
*/
/* CLOCK_SPEED when dealing with time and so should produce a
*/
/* result precise to 1 part in CLOCK_SPEED.
*/
timing_scale_factor = rate / divider;
T0MCR &= ~7u; /*lint !e915 */
T0EMR &= ~0x31u; /*lint !e915 */
T0EMR |= 0x20u; /*lint !e915 */
T0TCR = COUNTER_ENABLE; /* Enable clocks.
*/
return 0;
}
static unsigned long long counts_to_ns( unsigned long counts)
{
unsigned long long ns;
/* Convert the counts to nanoseconds taking the actual clock
*/
/* rate into account. Note: NS_PER_COUNT * CLOCK_SPEED should
*/
/* always be 1,000,000,000. The expanded form just shows the
*/
/* intent more clearly.
*/
ns = ( counts * NS_PER_COUNT * CLOCK_SPEED)/timing_scale_factor;
return ns;
}
static unsigned long ns_to_counts( unsigned long ns)
{
unsigned long long counts;
/* Convert the nanoseconds to counts taking the actual clock
*/
/* rate into account. Note: NS_PER_COUNT * CLOCK_SPEED should
*/
/* always be 1,000,000,000. The expanded form just shows the
*/
/* intent more clearly. Note 2: This can only result in a
*/
/* value larger than an unsigned long if ther are multiple
*/
/* counts in a nS, i.e. a rate > ~4GHz
*/
counts = ((unsigned long long)ns * timing_scale_factor)/(CLOCK_SPEED *
NS_PER_COUNT);
return (unsigned long)counts;
}
static unsigned long high_counts = 0uL;
static void accumulate_time( void)
{
static unsigned long last_time = 0uL;
unsigned long current_time;
/* A simple polled rollover check. This should work as long
as*/
/* this routine is called at least once every time the counter
*/
/* has incremented 1/2 of its maximum count.
*/
current_time = T0TC; /* Get the current count
*/
if(current_time < last_time) { /* If we have rolled over,
*/
high_counts++; /* increment the high oder
*/
} /* accumulator.
*/
last_time = current_time; /* Record last read value for
*/
/* the next check.
*/
}
static unsigned long long get_full_counts( void)
{
unsigned long low;
unsigned long long full_count;
accumulate_time(); /* Check for rollover of HW clock.
*/
/* Read in the clock counts. It is necessary to perform a
*/
/* rollover check so we don't end up with the low order value
*/
/* that of after the rollover and the high order count from
*/
/* before the rollover. If that were to happen our time would
*/
/* not increase in a monotonic fashion.
*/
do {
low = T0TC; /* Read current count.
*/
/* Form low order and high order counts into a single value.
*/
full_count = ((unsigned long long)high_counts << 32) | low;
} while( low > T0TC); /* Check for rollover and redo if one
*/
/* has happened.
*/
return full_count; /* All done.
*/
}
static void wait_ns(
const unsigned long *ptr)
{
unsigned long counts;
accumulate_time(); /* Check for rollover of HW clock.
*/
counts = ns_to_counts( *ptr); /* Convert from requested wait in nS
*/
/* to counts used by the HW counter.
*/
/* If counts is at zero then the wait interval is too small
*/
/* and we should just return. The smallest count we can deal
*/
/* with is the count that occurs between reading the HW clock
*/
/* and setting the match register. It is quite possible there
*/
/* is a small non-zero count that will be missed because it is
*/
/* smaller than the time taken to perform those operations. The
*/
/* value of this minimum will depend on the timer rate and the
*/
/* CPU execution speed. In addition any wait will have a fixed
*/
/* overhead for setup and tear down. It may be possible to
*/
/* compensate for one or both of these on startup in a future
*/
/* revision.
*/
if( counts > 0) {
IOSET = 0x100u;
T0EMR &= ~0x31;/*lint !e915*//* Set external match 0 output to 0
*/
/* and operation on match to do
nothing.*/
T0MR0 = T0TC + counts; /* Set match to current time + delay
*/
/* time.
*/
T0EMR |= 0x20;/*lint !e915*//* Set operation on match to set to 1.
*/
while( (T0EMR & 0x1) == 0) { /* Wait for match to set
output*/
} /* to 1.
*/
T0EMR &= ~0x31;/*lint !e915*//* Set external match 0 output to 0
*/
/* and operation on match to do nothing
*/
/* so we don't trigger next wait early
*/
/* by accident.
*/
IOCLR = 0x100u;
}
}
Robert
" 'Freedom' has no meaning of itself. There are always restrictions,
be they legal, genetic, or physical. If you don't believe me, try to
chew a radio signal. "
Kelvin Throop, III
Yahoo! Groups Sponsor
ADVERTISEMENT
<http://rd.yahoo.com/SIG=12cbf8iq2/M=267637.4116730.5333196.1261774/D=eg
roupweb/S=1706554205:HM/EXP=1070843978/A=1853618/R=0/*http://www.netflix
.com/Default?mqso=60178338&partid=4116730> click here
<http://us.adserver.yahoo.com/l?M=267637.4116730.5333196.1261774/D=egrou
pmail/S=:HM/A=1853618/rand=419195907>
To unsubscribe from this group, send an email to:
lpc2100-unsubscribe@yahoogroups.com
Your use of Yahoo! Groups is subject to the Yahoo! Terms of Service
<http://docs.yahoo.com/info/terms/> .Message
RE: [lpc2100] Delay routines
2003-12-20 by Curt Powell
Attachments
- No local attachments were found for this message.