CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

delay_us has a spurious check that introduces error

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
vsmguy



Joined: 13 Jan 2007
Posts: 91

View user's profile Send private message Visit poster's website

delay_us has a spurious check that introduces error
PostPosted: Mon Jul 12, 2010 9:58 pm     Reply with quote

For delays less than 153uS, CCS C generates the delay inline yeilding a 100% accurate delay.

Above 154uS ( and < 256uS ), CCS C uses a function call.

This function has a spurious check that introduces error into what, otherwise, could have been a 100% accurate delay.

Let's have a look:

Code:
....................       volatile int8 a  = 255;
0199:  MOVLW  FF
019A:  MOVWF  21
....................       
....................       delay_us( a );
019B:  MOVF   21,W      1
019C:  MOVWF  22      1
019D:  GOTO   01D      2

 ( .. function body below .. )
.................... #use delay(clock=20000000)
*
001D:  MOVLW  03      1
001E:  SUBWF  22,F      1
001F:  BTFSS  03.0      1/2 ( is argument value < 3uS ? If so, exit. Hence, this function delays a min of 13 ticks. whatever be the argument value )
0020:  GOTO   02B      2
0021:  MOVLW  22      1
0022:  MOVWF  04      1
0023:  BCF    03.7      1
0024:  MOVF   00,W      1
0025:  BTFSC  03.2      1/2
0026:  GOTO   02B      2
[ I DO NOT understand why this check ( lines 25 and 36 ) are there as this is ALWAYS going to fail ( there is not code path leading to 25 either! ).
I am complaining about these lines ( esp. the check at 25 that always fail because this introduces the error in the delay ( the GOTO is essentially a NOP ) - otherwise this would have been a 100% accurate delay :-( ]
0027:  GOTO   029      2
0028:  GOTO   029      2
0029:  DECFSZ 00,F      1/2
002A:  GOTO   028      2
[ Loop 27 to 2A gives consumes 5( argument - 1 - 3 (subtracted at line 1E)) + 4 ticks ]
002B:  BCF    0A.3      1
002C:  BCF    0A.4      1
002D:  GOTO   19E (RETURN)   2


Hence,

Quote:
for uS = 200, total ticks = 8 ( till & incl. skipped/nop line 20 ) + 6 + [ 5(196) + 4 = 984 ] + 4 = 1002 ticks ( expected 200/0.2 = 1000 ticks )
for uS = 255, total ticks = 8 ( till & incl. skipped/nop line 20 ) + 6 + [ 5(251) + 4 = 1259 ] + 4 = 1277 ticks ( expected 255/0.2 = 1275 ticks )


This is an error of 0.002% - not good for time critical code!

This could be fixed by CCS by removing the spurious check at lines 25 and 26.

What's the raison d'etre for those lines?

If I am missing something here, please let me know!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Jul 12, 2010 10:18 pm     Reply with quote

You are the first person to care if it's off by .002 % or whatever.
Ring up CCS and demand satisfaction.
vsmguy



Joined: 13 Jan 2007
Posts: 91

View user's profile Send private message Visit poster's website

PostPosted: Mon Jul 12, 2010 10:41 pm     Reply with quote

It's not about the inaccuracy.

It's about the spurious check making the delay inaccurate.

Had those two lines not being there - it would have been 100% accurate.

( why handcode a delay - as I have to do now for accuracy - when you could have the library do it! )

BTW - Does my analysis look correct?
Ttelmah



Joined: 11 Mar 2010
Posts: 19387

View user's profile Send private message

PostPosted: Tue Jul 13, 2010 2:40 am     Reply with quote

What compiler version?.

You comment on their not being routes to some parts of the code. Yet looking through the code, I can see routes to every line. So 'no', I don't think your analysis is correct. The test at 25, is for if the incoming value equalling 22uSec.
Seriously, you are not going to generate a variable delay, that gives 100% accuracy over the entire possible range. The CCS fixed delays do (easy, since they can pad the code with single nops as needed), but a variable delay, will always have the overhead of reading the variable, tetsing to see what it is, etc. etc.. The listing you post, is not exactly what is generated by the current compiler, which takes fractionally longer to loop, and so has a higher minimum value, but does then give accurate values at the top end. In a sense you have the trade off, that increasing the accuracy at the 'top', has increased the minimum time taken.
If you want 'uSec' accuracy, program a timer, and just test when the interrupt flag sets.

Best Wishes
vsmguy



Joined: 13 Jan 2007
Posts: 91

View user's profile Send private message Visit poster's website

PostPosted: Tue Jul 13, 2010 5:26 am     Reply with quote

Ttelmah wrote:
What compiler version?.


4.107

Ttelmah wrote:

You comment on their not being routes to some parts of the code. Yet looking through the code, I can see routes to every line.

[/quote]

I was talking about no loop/goto pointing back to 25.

The check at 25 is to check if the ( input argument - 3 ) is 0 is not - which is very pointless, as an input check has already been done at 1F.

Ttelmah wrote:

So 'no', I don't think your analysis is correct.


Leaving out the above analysis of 25, don't you agree with the remaining portion? :-)

Ttelmah wrote:

The test at 25, is for if the incoming value equalling 22uSec.


The test at 25, is for if the incoming value stored at INDF ( 00 ).
The INDF was loaded with register 22 at lines 21 and 22.

The value of register 22 is a copy of the input parameter less 3 ( lines 1D, 1E )
Ttelmah



Joined: 11 Mar 2010
Posts: 19387

View user's profile Send private message

PostPosted: Tue Jul 13, 2010 6:48 am     Reply with quote

Start at the beginning.
The code subtracts 3.
If there is a _carry_ (the requested uSec value was less than this), it drops out immediately. If it drops out at this point, including the exit code, it uses 11uSec, which is 2.2uSec.
Then it does some initialisation using five more machine cycles, and tests if the subtraction had resulted in zero. If so, it drops out at the second test. Again as close as possible.
Nothing 'points back to 25'. The code jumps to the exit at 2B.
The only code path, except the earlier exit, _always_ leads to location 25.

Code:

#include <16f877A.h>
#fuses HS, NOLVP, NOWDT, PUT
#use delay (clock = 20000000)

void main ()
{
   int8 a2;
   a2=255;
   delay_us(a2);
   
   a2=3;
   delay_us(a2);
   
   a2=2;
   delay_us(a2);
   while(true);
}

Put this into MPLAB. Put a breakpoint at the entry to each delay. Reset the stopwatch at this point. Put another breakpoint on the instruction after each delay. You get:

255uSec (spot on)
3.4uSec (still less than 0.5uSec error)
2.2uSec (same comment)

This last is the minimum delay generated by the code. 11 instructions.

Best Wishes
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Jul 13, 2010 3:48 pm     Reply with quote

Quote:
This is an error of 0.002% - not good for time critical code!
I'm curious what kind of application requires this accuracy. Could you please enlighten us?
If you tell us what you want to achieve we might be able to suggest you another solution.

Just wondering.... 0.002% == 20ppm
Have you checked the accuracy of your clock? Most likely your crystal will have a larger frequency spread over your application's operating temperature range.
vsmguy



Joined: 13 Jan 2007
Posts: 91

View user's profile Send private message Visit poster's website

PostPosted: Tue Jul 13, 2010 6:50 pm     Reply with quote

ckielstra wrote:

Just wondering.... 0.002% == 20ppm
Have you checked the accuracy of your clock? Most likely your crystal will have a larger frequency spread over your application's operating temperature range.


I was being pedantic :-D
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Tue Jul 13, 2010 11:57 pm     Reply with quote

Quote:
I was being pedantic.

Your previously reported result is incorrect though, or at least not valid for PCM V4.107. As Ttelmah mentioned, you get a delay exact to the us, for longer delay values and int8 delay parameter. The said error of 1002 versus 1000 cycles would mean 0.2 rather than 0.002 %, by the way.

Using an int16 parameter introduces an additional error however. Apparently CCS didn't see a necessity to provide separate delay_us versions for 8 and 16 bit parameters, which would be inappropriate also in my opinion.

In a practical designs, the programmed delay always adds to the execution time of the delayed action, so an empirical correction seems unavoidable in any case.

I basically appreciate pedantic software development - in the right place.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group