Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Thread

DDS working

DDS working

2003-12-03 by Leon Heller

Thanks for the suggestions.

It's working OK now (sine, triangle, sawtooth and square waves) with the
following code:

 adder = 202500;               //set up adder
  acc = 0;                    //clear accumulator
  while (1)
  {
    acc = acc + adder;      //update phase accumulator
    ptr = (acc &= 0xFF);    //pointer into table
    IOSET = sawtooth[ptr] << 8;
    IOCLR = (~sawtooth[ptr] << 8);
   }

apart from glitches - spurs on the waveforms. I think I had the ~ in the
wrong place.

I didn't get those glitches with the AVR, using the same DAC. I've got some
LEDs on some of the lines to the DAC, so I'll try disconnecting them - they
might be pulling the signals down. Although the DAC is a 5V device,
according to the spec it is LV CMOS compatible (as low as 2V for a logic
high) on the inputs, so it should be OK with the LPC2106 outputs. I might
try pulling the inputs up to 5V if I still have problems.

Leon
--
Leon Heller, G1HSM
Email: aqzf13@...
http://www.geocities.com/leon_heller

Re: [lpc2100] DDS working

2003-12-03 by microbit

Hi Leon,

> apart from glitches - spurs on the waveforms. I think I had the ~ in the
> wrong place.
>
> I didn't get those glitches with the AVR, using the same DAC. I've got
some
> LEDs on some of the lines to the DAC, so I'll try disconnecting them -
they

I figured it had to do something with the IOCLR write of complemented
values.
I think you'll find that the glitches represent the time it takes between
the IOSET and the IOCLR
operation to update the I/O (ie. there are a few instructions involved).

The only way probably will be to use a latch, unless your DAC has a strobe.

Tip : Try declaring a long* for IOCLR and one for IOSET, and write to the
port that way.
Register move instructions are then generated instead of the LDR, which
takes less cycles/time.
If you find the glitches get "narrower", then it's definitely the update
time between IOSET, and
writing the complement to IOCLR.

-- Kris
www.microbit.com.au

Re: [lpc2100] DDS working

2003-12-03 by Leon Heller

----- Original Message ----- 
Show quoted textHide quoted text
From: "microbit" <microbit@...>
To: <lpc2100@yahoogroups.com>
Sent: Wednesday, December 03, 2003 4:00 PM
Subject: Re: [lpc2100] DDS working


> Hi Leon,
>
> > apart from glitches - spurs on the waveforms. I think I had the ~ in the
> > wrong place.
> >
> > I didn't get those glitches with the AVR, using the same DAC. I've got
> some
> > LEDs on some of the lines to the DAC, so I'll try disconnecting them -
> they
>
> I figured it had to do something with the IOCLR write of complemented
> values.
> I think you'll find that the glitches represent the time it takes between
> the IOSET and the IOCLR
> operation to update the I/O (ie. there are a few instructions involved).
>
> The only way probably will be to use a latch, unless your DAC has a
strobe.

The DAC has got a latch, so I can try that.

>
> Tip : Try declaring a long* for IOCLR and one for IOSET, and write to the
> port that way.
> Register move instructions are then generated instead of the LDR, which
> takes less cycles/time.
> If you find the glitches get "narrower", then it's definitely the update
> time between IOSET, and
> writing the complement to IOCLR.

I'll try that.

Thanks,
Leon
--
Leon Heller, G1HSM
Email: aqzf13@...
http://www.geocities.com/leon_heller

Re: [lpc2100] DDS working

2003-12-03 by Robert Adsett

>   while (1)
>   {
>     acc = acc + adder;      //update phase accumulator
>     ptr = (acc &= 0xFF);    //pointer into table
>     IOSET = sawtooth[ptr] << 8;
>     IOCLR = (~sawtooth[ptr] << 8);
>    }
>
>apart from glitches - spurs on the waveforms. I think I had the ~ in the
>wrong place.
>
>I didn't get those glitches with the AVR, using the same DAC.

Scope your output lines and compare to the glitches.  I suspect they are 
coming from the fact that not all of your lines change at the same 
time.  Going from a value of 3 to a value of 4 I would expect to see a 
sequence of 3, 7, 4 given your code.

I think there may be either a HW or a SW fix.  THE SW fix would involve 
going against the User manuals recommendations though.

Robert

Re: [lpc2100] DDS working

2003-12-03 by Ben Dooks

... yeah, I pointed out the code being produced is loading the table value twice, which is why I suggested that the sawtooth[ptr] be loaded into a temporary

Re: DDS working

2003-12-03 by leon_heller

> 
> which should pre-compute the inverse of val and then do the
> set of the two registers. You could possibly get a little more
> perfomance to go to assembly.


Thanks, Ben. That speeded it up somewhat. Compiling for Release rather
than Debug made a big difference as well.

I've never used C before for this sort of thing, it probaly shows.

Leon

Re: [lpc2100] Re: DDS working

2003-12-03 by microbit

Hmmm, I didn't see the post of Ben, seems like I'm in the same boat
as Robert here :-)
Obviously not all posts are always routed fully to every member.

-- Kris

----- Original Message ----- 
Show quoted textHide quoted text
From: "leon_heller" <leon_heller@...>
To: <lpc2100@yahoogroups.com>
Sent: Thursday, December 04, 2003 5:15 AM
Subject: [lpc2100] Re: DDS working


> 
> 
> > 
> > which should pre-compute the inverse of val and then do the
> > set of the two registers. You could possibly get a little more
> > perfomance to go to assembly.
> 
> 
> Thanks, Ben. That speeded it up somewhat. Compiling for Release rather
> than Debug made a big difference as well.
> 
> I've never used C before for this sort of thing, it probaly shows.
> 
> Leon

Re: [lpc2100] DDS working

2003-12-03 by Robert Adsett

At 05:20 PM 12/3/03 +0000, you wrote:
>if you wanted to get better IOSET/IOCLR then you could do
>
>    while (1)
>    {
>      unsigned int val, vali;
>
>      acc = acc + adder;      //update phase accumulator
>      ptr = (acc &= 0xFF);    //pointer into table
>      val = swatooth[ptr] << 8;  // get our value
>      vali = ~val;
>
>      // set our value onto the output lines..
>      IOSET = val;
>      IOCLR = vali;
>    }
>
>which should pre-compute the inverse of val and then do the
>set of the two registers. You could possibly get a little more
>perfomance to go to assembly.

Even with assembly I would expect to see a significant glitch.  Even at max 
speed I was seeing several hundred nS to perform both operations.  (see 
earlier thread of discussion "Simple test program - is now instruction")

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

Delay routines

2003-12-03 by Curt Powell

Can anyone point me to some delay() routines for the lpc?  I can handle
milliseconds and above but I need something that works down in the
microseconds range and maybe as low as 50-100ns if I can get it.
 
Curt

Re: [lpc2100] DDS working

2003-12-03 by Ben Dooks

... yeah, the best way is to use some form of latch to clean the signal up. -- Ben Q:      What s a light-year? A:      One-third less calories than a regular

Re: DDS working

2003-12-03 by leon_heller

--- In lpc2100@yahoogroups.com, "microbit" <microbit@c...> wrote:
> Hmmm, I didn't see the post of Ben, seems like I'm in the same boat
> as Robert here :-)
> Obviously not all posts are always routed fully to every member.

I have the same problem as well. They appear almost immediately on the
group's web page, but sometimes the emailed version takes a long time.
I've got a feeling that Yahoo sends them out periodically, not when
they are initially posted. I've noticed it with other groups.

Leon

Re: [lpc2100] Re: DDS working

2003-12-03 by otc_friend

I have the same feeling.
- Henry

-----Urspr\ufffdngliche Nachricht-----
Von: leon_heller <leon_heller@...>
An: lpc2100@yahoogroups.com <lpc2100@yahoogroups.com>
Datum: Mittwoch, 3. Dezember 2003 19:31
Betreff: [lpc2100] Re: DDS working
Show quoted textHide quoted text
>--- In lpc2100@yahoogroups.com, "microbit" <microbit@c...> wrote:
>> Hmmm, I didn't see the post of Ben, seems like I'm in the same boat
>> as Robert here :-)
>> Obviously not all posts are always routed fully to every member.
>
>I have the same problem as well. They appear almost immediately on the
>group's web page, but sometimes the emailed version takes a long time.
>I've got a feeling that Yahoo sends them out periodically, not when
>they are initially posted. I've noticed it with other groups.
>
>Leon
>
>
>
>To unsubscribe from this group, send an email to:
>lpc2100-unsubscribe@yahoogroups.com
>
>
>
>Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
>
>

Re: [lpc2100] Delay routines

2003-12-04 by Robert Adsett

Curiouser & curiouser.  I just had my latest message echoed back in about 
10 minutes and then this one showed up.  It looks like it took about 5 
hours.  I've never had this much scrambling from a mailing list before.  It 
seems that some messages get stuck somewhere.

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

Re: [lpc2100] Re: DDS working

2003-12-04 by microbit

I think the server gets silly at times, or whatever.
There was a stage very recently where I didn't get posts from the CW430
group for like 12 days,
and then the stream just started again.
I know it's not my end, because as far as I know the Yahoo servers suspend
posting to you
after a "bounced" Email, until you re-confirm you're a valid destination.

I had however RXd Ben's posts, but they were always blank with an
attachment.
McAfee didn't have problem with it, but unsolicited attachments _always_ go
straight to
the bin AFAIAC.

I only realised when I looked on the LPC2100 group page ......

-- Kris
Show quoted textHide quoted text
----- Original Message -----
From: "otc_friend" <otc_friend@...>
To: <lpc2100@yahoogroups.com>
Sent: Thursday, December 04, 2003 10:33 AM
Subject: Re: [lpc2100] Re: DDS working


I have the same feeling.
- Henry

-----Urspr\ufffdngliche Nachricht-----
Von: leon_heller <leon_heller@...>
An: lpc2100@yahoogroups.com <lpc2100@yahoogroups.com>
Datum: Mittwoch, 3. Dezember 2003 19:31
Betreff: [lpc2100] Re: DDS working


>--- In lpc2100@yahoogroups.com, "microbit" <microbit@c...> wrote:
>> Hmmm, I didn't see the post of Ben, seems like I'm in the same boat
>> as Robert here :-)
>> Obviously not all posts are always routed fully to every member.
>
>I have the same problem as well. They appear almost immediately on the
>group's web page, but sometimes the emailed version takes a long time.
>I've got a feeling that Yahoo sends them out periodically, not when
>they are initially posted. I've noticed it with other groups.
>
>Leon
>
>
>
>To unsubscribe from this group, send an email to:
>lpc2100-unsubscribe@yahoogroups.com
>
>
>
>Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
>
>


      Yahoo! Groups Sponsor
            ADVERTISEMENT




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.

Re: [lpc2100] Delay routines

2003-12-05 by Robert Adsett

At 10:28 AM 12/3/03 -0800, you wrote:
>Can anyone point me to some delay() routines for the lpc?  I can handle 
>milliseconds and above but I need something that works down in the 
>microseconds range and maybe as low as 50-100ns if I can get it.
>
>Curt
>
I'm just starting to look into this myself.  A pointer in the general 
direction.  Look at timer 0 (or 1) and the match registers).  I'll followup 
with more later.

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

RE: [lpc2100] Delay routines

2003-12-05 by Curt Powell

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?
Show quoted textHide quoted text
-----Original Message-----
From: Robert Adsett [mailto:radsett@...] 
Sent: Friday, December 05, 2003 8:16 AM
To: lpc2100@yahoogroups.com
Subject: Re: [lpc2100] Delay routines



At 10:28 AM 12/3/03 -0800, you wrote:
>Can anyone point me to some delay() routines for the lpc?  I can handle

>milliseconds and above but I need something that works down in the 
>microseconds range and maybe as low as 50-100ns if I can get it.
>
>Curt
>
I'm just starting to look into this myself.  A pointer in the general 
direction.  Look at timer 0 (or 1) and the match registers).  I'll
followup 
with more later.

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=12c44uqqe/M=267637.4116732.5333197.1261774/D=eg
roupweb/S=1706554205:HM/EXP=1070727383/A=1853619/R=0/*http://www.netflix
.com/Default?mqso=60178356&partid=4116732> click here	
 
<http://us.adserver.yahoo.com/l?M=267637.4116732.5333197.1261774/D=egrou
pmail/S=:HM/A=1853619/rand=479185965> 	

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/> .

Re: Delay routines

2003-12-05 by lpc2100_fan

Curt,

it is my understanding that you can use the match registers without
changing the I/O pins but I will make sure this statement is true. In
regards to the number of I/O pins there is relief on the way. The
LPC2114 / LPC2124 is in a 64-pin package and offers additional GPIO
pins. According to my information the 2114 is very similar priced to
the LPC2104 but offers more I/O pins and a 4-channel 10-ADC as well as
a second SPI interface. For RAM intensive applications however, the
2105/2106 offer 32/64k RAM which is not an option for the 64-pin device.
Overall it seems that Philips is serious with the slogan "Let's make
things better" ;-)

Bob

--- In lpc2100@yahoogroups.com, "Curt Powell" <curt.powell@s...> wrote:
Show quoted textHide quoted text
> 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?
>  
> 
> -----Original Message-----
> From: Robert Adsett [mailto:radsett@a...] 
> Sent: Friday, December 05, 2003 8:16 AM
> To: lpc2100@yahoogroups.com
> Subject: Re: [lpc2100] Delay routines
> 
> 
> 
> At 10:28 AM 12/3/03 -0800, you wrote:
> >Can anyone point me to some delay() routines for the lpc?  I can handle
> 
> >milliseconds and above but I need something that works down in the 
> >microseconds range and maybe as low as 50-100ns if I can get it.
> >
> >Curt
> >
> I'm just starting to look into this myself.  A pointer in the general 
> direction.  Look at timer 0 (or 1) and the match registers).  I'll
> followup 
> with more later.
> 
> 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
> 
>

RE: [lpc2100] Re: Delay routines

2003-12-05 by Curt Powell

That sounds great; let's hope they follow with a LPC2126 for us
RAM-hungry types!
Show quoted textHide quoted text
-----Original Message-----
From: lpc2100_fan [mailto:lpc2100_fan@...] 
Sent: Friday, December 05, 2003 10:22 AM
To: lpc2100@yahoogroups.com
Subject: [lpc2100] Re: Delay routines


Curt,

it is my understanding that you can use the match registers without
changing the I/O pins but I will make sure this statement is true. In
regards to the number of I/O pins there is relief on the way. The
LPC2114 / LPC2124 is in a 64-pin package and offers additional GPIO
pins. According to my information the 2114 is very similar priced to
the LPC2104 but offers more I/O pins and a 4-channel 10-ADC as well as
a second SPI interface. For RAM intensive applications however, the
2105/2106 offer 32/64k RAM which is not an option for the 64-pin device.
Overall it seems that Philips is serious with the slogan "Let's make
things better" ;-)

Bob

--- In lpc2100@yahoogroups.com, "Curt Powell" <curt.powell@s...> 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?
>  
> 
> -----Original Message-----
> From: Robert Adsett [mailto:radsett@a...] 
> Sent: Friday, December 05, 2003 8:16 AM
> To: lpc2100@yahoogroups.com
> Subject: Re: [lpc2100] Delay routines
> 
> 
> 
> At 10:28 AM 12/3/03 -0800, you wrote:
> >Can anyone point me to some delay() routines for the lpc?  I can
handle
> 
> >milliseconds and above but I need something that works down in the 
> >microseconds range and maybe as low as 50-100ns if I can get it.
> >
> >Curt
> >
> I'm just starting to look into this myself.  A pointer in the general 
> direction.  Look at timer 0 (or 1) and the match registers).  I'll
> followup 
> with more later.
> 
> 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=12c3djt76/M=267637.4116732.5333197.1261774/D=eg
roupweb/S=1706554205:HM/EXP=1070734909/A=1853619/R=0/*http://www.netflix
.com/Default?mqso=60178356&partid=4116732> click here	
 
<http://us.adserver.yahoo.com/l?M=267637.4116732.5333197.1261774/D=egrou
pmail/S=:HM/A=1853619/rand=140577080> 	

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/> .

Re: [lpc2100] Re: Delay routines

2003-12-05 by Bill Knight

While I have yet to implement this on the LPC ARMs the following
is an approach I have been using with success for years.

At system startup setup a timer counter to increment at a rate
that will cause it to rollover at a convenient period (1-15 mSec).
Also initialize a 32 bit variable 'sysTICs' to 0.

In the rollover interrupt routine, increment sysTICs.

For delays of the rollover interval use routines like:

uint32_t getSysTICs(void)

  return sysTICs;


uint32_t getElapsedTICs(uint32_t startTICs)

  return (sysTICs - startTICs);


void pause(uint32_t pauseTICs)

  uint32_t startTime = getSysTICs();

  while (getElapsedTICs(startTICs) < pauseTICs)
    /* do something else */ ;


For short delays, you can replace sysTICs with the current value
of the Timer Counter Register.

uint32_t delay(uint32_t delay)

  uint32_t start = TC;

  while ((TC - start) < delay)
    /* do almost nothing else */ ;


Hope this helps.

-Bill Knight
R O SoftWare

RE: [lpc2100] Delay routines

2003-12-05 by Robert Adsett

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).

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

RE: [lpc2100] Delay routines

2003-12-07 by Robert Adsett

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

RE: [lpc2100] Delay routines

2003-12-20 by Curt Powell

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
Show quoted textHide quoted text
-----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/> .

RE: [lpc2100] Delay routines

2003-12-20 by Robert Adsett

At 04:01 PM 12/19/03 -0800, you wrote:
>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

I'll try to answer both questions in one post :)

The IOSET and IOCLR were in there just for measuring the delay time.  They 
can (and probably should) be removed for actual use.

struct __reent is a structure used in newlib to provide reentrancy.  If you 
are not using newlib there is no reason to keep it.  Even if you are it may 
be of limited use.

VPBrate just returns the rate of the VPB clock in HZ.  If you are using a 
fixed rate it will be simpler to just use a define.  If you have set your 
vpb divider to divide by 1 this will be the same as your CPU clock rate.

My routine uses the nominal rate, the PLL multiplier and the VPB divider to 
work out what the rate is.  I'll make it available (probably by years end) 
as soon as I've cleaned it up a bit.  Right now it's between 
implementations.  It'll be part of a set of newlib routines.

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

RE: [lpc2100] Delay routines

2003-12-30 by Robert Adsett

At 10:01 AM 12/20/03 -0500, you wrote:
>My routine uses the nominal rate, the PLL multiplier and the VPB divider to
>work out what the rate is.  I'll make it available (probably by years end)
>as soon as I've cleaned it up a bit.  Right now it's between
>implementations.  It'll be part of a set of newlib routines.

I promised I'd make the newlib routines I mentioned available by the end of 
the year.  It looks like I'll have a day to spare :).  They are 
downloadable in a zip file from

http://www.aeolusdevelopment.com/Articles/download.html

This has timer (and delay) support as well as stdin/stdout/stderr support 
for newlib.  Also some CPU setup routines.

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

RE: [lpc2100] Delay routines

2004-01-02 by Curt Powell

Robert,
 
I ran some side-by-side comparisons on the first vs. the second versions
of delay that you posted.  
Because I know there is call overhead I just put the delay routines in a
loop that sets a pin high, delays, sets pin low, etc. and looked at
differences from delay to delay on a logic analyzer, i.e.:
for (i=2;i<=10;++i)
{
    -drive output pin high
    WaitUs(i);
    -drive output pin low
}
-drive trigger high
 
The results are interesting (at least to me).  First, there is a
potential bug in both versions:
Using my CLOCK_SPEED of 14,745,000hz , processor speed of 58,980,000 and
a VPB divider of 2 so VPBRate() is 29,490,000, a call to WaitUs(1) takes
many minutes to execute.  It hangs in
 
while( (REG(TIMER0_EMR) & 0x8) == 0).  
 
WaitUs for values > 1 succeeds.  I assume that with a value of 1 the
timer has to go "around the horn" to get back to the target value, hence
the delay.
However, if I use your original CLOCK_SPEED of 10,000,000 it works OK.
I haven't tracked down in the code why this is happening but I wonder
that with such a short delay the counter is already past the target
value before the match gets set?
 
Delays that the logic analyzer (el-cheapo ant16) reports are
interesting:
i(uS, requested)    Delay (uS, measured)   Difference from previous
----------------    ----------------       ------------------------
2                   12                     
3                   12.8                   0.8
4                   13.7                   0.9
5                   14.9                   1.2
6                   15.9                   1.0
7                   16.9                   1.0
8                   18                     1.1
9                   18.8                   0.8
10                  19.8                   1.0
(These are pretty reproducible from run to run)
 
So there seems to be a constant overhead factor of 10us in the call.  
 
Question 1:  Does this overhead seem excessive to you for the processor
running at 60Mhz?  
Question 2:  Does the variation in 'difference from previous' seem
excessive?
 
Anyone else with thougths/observations/experiences feel free to chime
in...
 
Curt
Show quoted textHide quoted text
-----Original Message-----
From: Robert Adsett [mailto:subscriptions@...] 
Sent: Tuesday, December 30, 2003 1:10 PM
To: lpc2100@yahoogroups.com
Subject: RE: [lpc2100] Delay routines



At 10:01 AM 12/20/03 -0500, you wrote:
>My routine uses the nominal rate, the PLL multiplier and the VPB
divider to
>work out what the rate is.  I'll make it available (probably by years
end)
>as soon as I've cleaned it up a bit.  Right now it's between
>implementations.  It'll be part of a set of newlib routines.

I promised I'd make the newlib routines I mentioned available by the end
of 
the year.  It looks like I'll have a day to spare :).  They are 
downloadable in a zip file from

http://www.aeolusdevelopment.com/Articles/download.html

This has timer (and delay) support as well as stdin/stdout/stderr
support 
for newlib.  Also some CPU setup routines.

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 Links


*	To visit your group on the web, go to:
http://groups.yahoo.com/group/lpc2100/
  

*	To unsubscribe from this group, send an email to:
lpc2100-unsubscribe@yahoogroups.com
<mailto:lpc2100-unsubscribe@yahoogroups.com?subject=Unsubscribe> 
  

*	Your use of Yahoo! Groups is subject to the Yahoo! Terms of
Service <http://docs.yahoo.com/info/terms/> .

RE: [lpc2100] Delay routines

2004-01-02 by Robert Adsett

At 04:29 PM 1/1/04 -0800, you wrote:
>Robert,
>
>I ran some side-by-side comparisons on the first vs. the second versions 
>of delay that you posted.
>Because I know there is call overhead I just put the delay routines in a 
>loop that sets a pin high, delays, sets pin low, etc. and looked at 
>differences from delay to delay on a logic analyzer, i.e.:
>for (i=2;i<=10;++i)
>{
>     -drive output pin high
>     WaitUs(i);
>     -drive output pin low
>}
>-drive trigger high
>
>The results are interesting (at least to me).  First, there is a potential 
>bug in both versions:
>Using my CLOCK_SPEED of 14,745,000hz , processor speed of 58,980,000 and a 
>VPB divider of 2 so VPBRate() is 29,490,000, a call to WaitUs(1) takes 
>many minutes to execute.  It hangs in
>
>while( (REG(TIMER0_EMR) & 0x8) == 0).
>
>WaitUs for values > 1 succeeds.  I assume that with a value of 1 the timer 
>has to go "around the horn" to get back to the target value, hence the delay.

Unfortunately, yes.    If the delay gets small enough there will be a 
problem.  This should be detectable by calibrating the timer at startup 
(thus the comment about refinement at the top of the file).  Hmm, I also 
need more robust documentation.


>However, if I use your original CLOCK_SPEED of 10,000,000 it works OK.  I 
>haven't tracked down in the code why this is happening but I wonder that 
>with such a short delay the counter is already past the target value 
>before the match gets set?

Hmm,
Set CLOCK_SPEED to 14745000
then you presumably set COUNTS_PER_US to 14? (or 15?)

As a matter of curiosity, why?

I can see where the truncation involved might make the delay fail 
earlier.  I'd have to work through the math to see exactly what the effect 
would be and it's getting late tonight ;)  I'll take a look tomorrow.

>
>Delays that the logic analyzer (el-cheapo ant16) reports are interesting:
>i(uS, requested)    Delay (uS, measured)   Difference from previous
>----------------    ----------------       ------------------------
>2                   12
>3                   12.8                   0.8
>4                   13.7                   0.9
>5                   14.9                   1.2
>6                   15.9                   1.0
>7                   16.9                   1.0
>8                   18                     1.1
>9                   18.8                   0.8
>10                  19.8                   1.0
>(These are pretty reproducible from run to run)
>
>So there seems to be a constant overhead factor of 10us in the call.
>
>Question 1:  Does this overhead seem excessive to you for the processor 
>running at 60Mhz?

10uS would be 60 instructions at full rate.  A quick operation count gives 
me 32 operations including a division that will have to be done in SW (no 
HW div on the ARM).  So it's in the right ball park (documentation again).

If you need a delay in the uS range you are going to have to get closer to 
the HW.  On the other hand if you need a delay in the 10's of uS or more 
but with uS (or 2) accuracy I think we can make this work.  (For now you 
will get +/-10uS or so accurracy, mostly +).

>Question 2:  Does the variation in 'difference from previous' seem excessive?


Hmm, figure +/ 0.1 from the counter.  Is this with count at 10000000?

Given a vpbrate of 29490000 that will give a rate counter rate of 
14745000.  2us becomes 2*10*14745000/10000000 = 29 counts, 3 uS becomes 44 
counts, and 4 us becomes 58 counts.  Those are respectively (1.9-2.0uS), 
(2.92-2.98 uS ), (3.86 - 3.93uS), (4.88-4.95).  You may lose one count if 
you read from the timer just before it increments.  That gives a calculated 
set of possible variations of (.92 - 1.08) [for 2us to 3us delay] and, 
(0.86 - 1.01) [for 3uS to 4uS] delay.  If you have CLOCK_SPEED set such 
that you have a non integral number of counts per us truncation errors will 
add to the variation (finite arithmetic will get you every time).

Let me know what you have CLOCK_SPEED and COUNTS_PER_US set to for this 
measurement, I'd like to work a little further on it.



Nice set of measurements Curt.

>
>Anyone else with thougths/observations/experiences feel free to chime in...
>
>Curt

Absolutely.  I just moved some of that 'refinement' up my priority list.

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

RE: [lpc2100] Delay routines

2004-01-02 by Curt Powell

I used 15 for COUNTS_PER_US.  Are you implying that setting leaving
CLOCK_SPEED at 10000000 and COUNTS_PER_US at 10 would have no
difference?  (I haven't followed this logic line through the code to see
if it holds)
 
One more thing:  I found that the first call to WaitUs took much longer
than expected.  I got around it by making an initial call at the end of
the setup function.  (Forgot to mention that.)
 
BTW, so far this will be entirely adequate for my needs.  I was just
testing the lower boundary to see how it would perform...
Show quoted textHide quoted text
-----Original Message-----
From: Robert Adsett [mailto:subscriptions@...] 
Sent: Thursday, January 01, 2004 9:03 PM
To: lpc2100@yahoogroups.com
Subject: RE: [lpc2100] Delay routines


At 04:29 PM 1/1/04 -0800, you wrote:
>Robert,
>
>I ran some side-by-side comparisons on the first vs. the second
versions 
>of delay that you posted.
>Because I know there is call overhead I just put the delay routines in
a 
>loop that sets a pin high, delays, sets pin low, etc. and looked at 
>differences from delay to delay on a logic analyzer, i.e.:
>for (i=2;i<=10;++i)
>{
>     -drive output pin high
>     WaitUs(i);
>     -drive output pin low
>}
>-drive trigger high
>
>The results are interesting (at least to me).  First, there is a
potential 
>bug in both versions:
>Using my CLOCK_SPEED of 14,745,000hz , processor speed of 58,980,000
and a 
>VPB divider of 2 so VPBRate() is 29,490,000, a call to WaitUs(1) takes 
>many minutes to execute.  It hangs in
>
>while( (REG(TIMER0_EMR) & 0x8) == 0).
>
>WaitUs for values > 1 succeeds.  I assume that with a value of 1 the
timer 
>has to go "around the horn" to get back to the target value, hence the
delay.

Unfortunately, yes.    If the delay gets small enough there will be a 
problem.  This should be detectable by calibrating the timer at startup 
(thus the comment about refinement at the top of the file).  Hmm, I also

need more robust documentation.


>However, if I use your original CLOCK_SPEED of 10,000,000 it works OK.
I 
>haven't tracked down in the code why this is happening but I wonder
that 
>with such a short delay the counter is already past the target value 
>before the match gets set?

Hmm,
Set CLOCK_SPEED to 14745000
then you presumably set COUNTS_PER_US to 14? (or 15?)

As a matter of curiosity, why?

I can see where the truncation involved might make the delay fail 
earlier.  I'd have to work through the math to see exactly what the
effect 
would be and it's getting late tonight ;)  I'll take a look tomorrow.

>
>Delays that the logic analyzer (el-cheapo ant16) reports are
interesting:
>i(uS, requested)    Delay (uS, measured)   Difference from previous
>----------------    ----------------       ------------------------
>2                   12
>3                   12.8                   0.8
>4                   13.7                   0.9
>5                   14.9                   1.2
>6                   15.9                   1.0
>7                   16.9                   1.0
>8                   18                     1.1
>9                   18.8                   0.8
>10                  19.8                   1.0
>(These are pretty reproducible from run to run)
>
>So there seems to be a constant overhead factor of 10us in the call.
>
>Question 1:  Does this overhead seem excessive to you for the processor

>running at 60Mhz?

10uS would be 60 instructions at full rate.  A quick operation count
gives 
me 32 operations including a division that will have to be done in SW
(no 
HW div on the ARM).  So it's in the right ball park (documentation
again).

If you need a delay in the uS range you are going to have to get closer
to 
the HW.  On the other hand if you need a delay in the 10's of uS or more

but with uS (or 2) accuracy I think we can make this work.  (For now you

will get +/-10uS or so accurracy, mostly +).

>Question 2:  Does the variation in 'difference from previous' seem
excessive?


Hmm, figure +/ 0.1 from the counter.  Is this with count at 10000000?

Given a vpbrate of 29490000 that will give a rate counter rate of 
14745000.  2us becomes 2*10*14745000/10000000 = 29 counts, 3 uS becomes
44 
counts, and 4 us becomes 58 counts.  Those are respectively (1.9-2.0uS),

(2.92-2.98 uS ), (3.86 - 3.93uS), (4.88-4.95).  You may lose one count
if 
you read from the timer just before it increments.  That gives a
calculated 
set of possible variations of (.92 - 1.08) [for 2us to 3us delay] and, 
(0.86 - 1.01) [for 3uS to 4uS] delay.  If you have CLOCK_SPEED set such 
that you have a non integral number of counts per us truncation errors
will 
add to the variation (finite arithmetic will get you every time).

Let me know what you have CLOCK_SPEED and COUNTS_PER_US set to for this 
measurement, I'd like to work a little further on it.



Nice set of measurements Curt.

>
>Anyone else with thougths/observations/experiences feel free to chime
in...
>
>Curt

Absolutely.  I just moved some of that 'refinement' up my priority list.

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 Links


*	To visit your group on the web, go to:
http://groups.yahoo.com/group/lpc2100/
  

*	To unsubscribe from this group, send an email to:
lpc2100-unsubscribe@yahoogroups.com
<mailto:lpc2100-unsubscribe@yahoogroups.com?subject=Unsubscribe> 
  

*	Your use of Yahoo! Groups is subject to the Yahoo! Terms of
Service <http://docs.yahoo.com/info/terms/> .

RE: [lpc2100] Delay routines

2004-01-03 by Robert Adsett

At 09:58 AM 1/2/04 -0800, you wrote:
>I used 15 for COUNTS_PER_US.  Are you implying that setting leaving 
>CLOCK_SPEED at 10000000 and COUNTS_PER_US at 10 would have no 
>difference?  (I haven't followed this logic line through the code to see 
>if it holds)

CLOCK_SPEED is a target speed for the timer.  The startup for the timer 
routines sets the prescaler to get the timer as close to CLOCK_SPEED as it 
can without going below it.  It gets the oscillator input frequency from 
SetNativeSpeed (It shouldn't be necessary to recompile the library if you 
change the oscillator frequency, just change the call to 
SetNativeSpeed).  The reason for choosing the value I did for CLOCK_SPEED 
was to provide resolution in the counter better than needed for timing, 
delay overflow of the counter as long as possible and to make the number of 
counter increments per microsecond an integral number to avoid and errors 
due to finite precision.  The actual timer frequency gets recorded in 
timing_scale_factor and the ratio timing_scale_factor/CLOCK_SPEED is used 
to correct any mismatch due to the actual frequency not matching the 
requested nominal frequency.

Now to work through a few examples with various settings

First a 10MHz oscillator,   CLOCK_SPEED set to 10000000, COUNTS_PER_US to 
10, CPU pll'd to 60MHz and VPBrate to div by 1.  We get a timer frequency 
of 10000000 (prescale divide by 6).

uS counts Should Be Actual uS Min wait
1 10 10 1 0.9
2 20 20 2 1.9
3 30 30 3 2.9
4 40 40 4 3.9
5 50 50 5 4.9
6 60 60 6 5.9
7 70 70 7 6.9
8 80 80 8 7.9
9 90 90 9 8.9
10 100 100 10 9.9
1000 10000 10000 1000 999.9


Second a 14.745MHz oscillator,   CLOCK_SPEED set to 14745000, COUNTS_PER_US 
to 15, CPU pll'd to 58.98MHz and VPBrate to div by 2.  We get a timer 
frequency of 14745000 (prescale divide by 2).

uS      counts  Should Be       Actual uS       Min wait
1       15      14.745          1.01729 0.94947
2       30      29.49           2.03458 1.96676
3       45      44.235          3.05188 2.98406
4       60      58.98           4.06917 4.00135
5       75      73.725          5.08646 5.01865
6       90      88.47           6.10376 6.03594
7       105     103.215 7.12105 7.05323
8       120     117.96          8.13835 8.07053
9       135     132.705 9.15564 9.08782
10      150     147.45          10.1729 10.1051
1000    15000   14745           1017.29 1017.22


Third a 14.745MHz oscillator,   CLOCK_SPEED set to 10000000, COUNTS_PER_US 
to 10, CPU pll'd to 58.98MHz and VPBrate to div by 2.  We get a timer 
frequency of 14745000 (prescale divide by 2).

uS      counts  Should Be       Actual uS       Min wait
1       14      14.745          0.94947 0.88165
2       29      29.49           1.96676 1.89894
3       44      44.235          2.98406 2.91624
4       58      58.98           3.93353 3.86571
5       73      73.725          4.95083 4.88301
6       88      88.47           5.96812 5.90030
7       103     103.215 6.98541 6.91759
8       117     117.96          7.93489 7.86707
9       132     132.705 8.95218 8.88436
10      147     147.45          9.96948 9.90166
1000    14745   14745           1000            999.932

Note that because the nominal timer frequency is chosen so that there are 
an integral number of counts per uS the error that occurs because the 
actual frequency does not allow that get corrected by the 
timing_scale_factor rather than by COUNTS_PER_US.  Both numbers can only be 
accurate to +/-1 but since timing_scale factor is so much larger to begin 
with the error it introduces is much less (6 orders of magnitude).  Of 
course this still neglects the constant call overhead.


>One more thing:  I found that the first call to WaitUs took much longer 
>than expected.  I got around it by making an initial call at the end of 
>the setup function.  (Forgot to mention that.)

Good point.  There is an init that takes place on the first call.  I'll 
move that out.

>
>BTW, so far this will be entirely adequate for my needs.  I was just 
>testing the lower boundary to see how it would perform...

Great.  I still think I'll make it a little bit better though.

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

RE: [lpc2100] Delay routines

2004-02-10 by Robert Adsett

At 12:21 PM 1/3/04 -0500, you wrote:
>At 09:58 AM 1/2/04 -0800, you wrote:
> >
> >BTW, so far this will be entirely adequate for my needs.  I was just
> >testing the lower boundary to see how it would perform...
>
>Great.  I still think I'll make it a little bit better though.

I did say I was going to improve the timing routines.  I have, and release 
2 of the newlib support routines is available at 
http://www.aeolusdevelopment.com along with some additional documentation 
and a couple of application notes on the timer, including one that 
documents the test results.

Just a quick subset of the tests here.  This covers the small wait area 
previously talked about.  Everything is in microseconds.

req     actual_us       Error
0       1.3     1.3
1       9.2     8.2
2       9.3     7.3
3       9.2     6.2
4       9.2     5.2
5       9.2     4.2
6       9.3     3.3
7       9.2     2.2
8       9.2     1.2
9       9.3     0.3
10      9.2     -0.8
11      9.2     -1.8
12      11.9    -0.1
13      12.9    -0.1
14      13.9    -0.1
15      14.9    -0.1
16      15.9    -0.1
17      16.9    -0.1
18      17.9    -0.1
19      18.9    -0.1
20      20.2    0.2
21      20.9    -0.1
22      22.2    0.2
23      22.9    -0.1
24      24.2    0.2
25      25.2    0.2
26      25.9    -0.1
27      27.2    0.2
28      28.2    0.2
29      28.9    -0.1
30      30.2    0.2

As you can see, it plateaus below 12uS but the constant offset is gone.

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

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.