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 CCS Technical Support

CCS handling of int16 in if statement
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Futterama



Joined: 17 Oct 2005
Posts: 98

View user's profile Send private message

CCS handling of int16 in if statement
PostPosted: Sun Jul 17, 2016 12:48 pm     Reply with quote

Hi forum,

I'm building a time critical application in a PIC10F222, where each loop of code needs to take an equal amount of time/instructions to execute. I found a pretty good way of doing this, but I face a problem when CCS is evaluating a line like this:
Code:
if(value1 == value2)

when values are int16 variables. I'm looking at the ASM output in the list file, and I know each ASM line equals one instruction, and I know what the GOTO statement does. It seems to me that the ASM code evaluates one byte first, maybe the MSB, and if these don't match, then there is no reason to check the LSB, so the code makes a GOTO. This is causing me problems, because the execution time of this statement then relies on the ever changing content of the int16 values.

The problem does not exist when evaluating int8, but I need the range of int16.

Is there a clever way to compare two int16 where the execution time remains the same regardless of variable content? It would be OK if the evaluation took a bit more code, and hence time, because my application is only sensitive to a change in looping time, not actual loop time.

Another solution I have been working on, is letting a timer run while my code executes, and then in the end of the code, check the timer value this way:
Code:
while(TMR0 != 1);

It worked OK in the beginning, but there are still fluctuations in execution time (because the statement above in itself is taking a few instructions to execute and is thereby not instantaneous when the timer reaches the value of 1) and that is apparently enough to disturb my application in a negative way.

Last resort is to split the most time accuracy critical tasks between several PIC10F222 and just use a pin high/low to communicate between them (reading a pin status is as fast as it gets).
temtronic



Joined: 01 Jul 2010
Posts: 9245
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sun Jul 17, 2016 4:31 pm     Reply with quote

OK, I'm SURE Mr. T posted a reply earlier(....make8()...) but it doesn't show up on my PC !
Did someone let the gremlins out ??

Jay
guy



Joined: 21 Oct 2005
Posts: 297

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

PostPosted: Sun Jul 17, 2016 5:59 pm     Reply with quote

One approach would be to get your hands dirty with ASM and rewrite the IF instruction so it takes up a constant amount of time.
Another approach is to use the timer together with an interrupt routine. This would improve the timing jitter but not solve it completely (plus it will take up more CPU time).
And a third possible solution is to see if your timing-critical mission could be accomplished by one of the peripherals of a more capable PIC. Higher clock rate will also improve the jitter problem (a 2-instruction jitter with a 64MHz internal clock is merely 125ns !)
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jul 17, 2016 7:05 pm     Reply with quote

Quote:
Is there a clever way to compare two int16 where the execution
time remains the same regardless of variable content?

If you XOR the 16-bit values, the compiler will first XOR the LSB's then
XOR the MSB's and then OR the results of each test. Use this line:
Code:
if(value1 ^ value2)

If the two values are not equal, the body of the if() statement will be
executed. That's because if you XOR two equal bit values, you get 0.
If they are not equal, you get one or more of the bits set to 1, and
that's non-zero, which is seen as "True" by the compiler.

It gives this ASM code:
Code:
.................... if(value1 ^ value2)
0019:  MOVF   16,W   
001A:  XORWF  18,W  // XOR LSB's
001B:  MOVWF  10
001C:  MOVF   17,W
001D:  XORWF  19,W    // XOR MSB's
001E:  MOVWF  13
001F:  MOVF   10,W 
0020:  IORWF  13,W   // OR together the two previous results
0021:  BTFSC  03.2   // Branch if the result is non-zero 
0022:  GOTO   026    // Jump if zero (both values are equal)


Partial test program:
Code:

void main()
{
int16 value1 = 0x1235;
int16 value2 = 0x1234;
int8 equal;

if(value1 ^ value2)
   equal = FALSE;
else
   equal = TRUE;

}


If you want to make it operate with positive logic, which is more
reasonable, you can negate the XOR result:
Code:

if(!(value1 ^ value2))
   equal = TRUE;
else
   equal = FALSE;

if(equal == TRUE)
   printf("Equal\r");
else
   printf("Not equal\r");
guy



Joined: 21 Oct 2005
Posts: 297

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

PostPosted: Mon Jul 18, 2016 2:10 am     Reply with quote

PCM programmer - Like! Cool
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Mon Jul 18, 2016 8:47 am     Reply with quote

There are potentially big problems with ths sort of approach. There is no guarantee that code produced by later versions of the compiler, or even the same compiler with different options or with altered/enlarged code, will work the same, so you are going to have to at least check every time you do a compilation.

High level code, or even medium level code such as C, is NOT guaranteed to be implemented in any particular way, and is not intended and should not be expected to produce machine code that has any particular timing characteristic. In short, using high level code to produce strictly controlled execution times is not a good thing. In fact it's very bad programming practice. It might work for a one-off, experimental hobby project, but it's not going to fly for professional use, and such techniques certainly will not be allowed to fly, as in be acceptable for avionics use, at all.

If you really want repeatable, accurate timing, then use hardware. Software is not the tool for that sort of job.

What is the application? Why do you need precise, repeatable timing? Why are you not using hardware?
temtronic



Joined: 01 Jul 2010
Posts: 9245
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Jul 18, 2016 9:14 am     Reply with quote

Man , I have to ask WHY the 10F222 ? 512 word of mem ain't much UNLESS you code in ASM.
As pointed out C doesn't always compile the same ASM twice.

Jay
Futterama



Joined: 17 Oct 2005
Posts: 98

View user's profile Send private message

PostPosted: Mon Jul 18, 2016 11:03 am     Reply with quote

Thanks for all the answers, especially to PCM programmer, I'll try that tonight.

RF_Developer: End application is a special hobby RC related device that takes a servo signal, and generates pulses if the signal is long enough (like when the switch is flipped on the transmitter) and the pulse frequency depends on the signal length from the RC receiver. I got this working very reliably, because I only need to read the servo signal length once. But the challenge is that I need to generate an accurate signal for an attached servo (not the same signal as the one from the RC receiver), and if the loop time in my code changes, so does the output signal to the servo and hence the servo will be moving when it shouldn't. I don't have the hardware available in the PIC10F222.

temtronic: I'm using the PIC10F222 basically because I have more than 100 of them in stock from another project, and for this limited code project, it was suited just fine and the pin count is just perfect. Also, I find it very educating to have limited code and memory space, my code gets more and more optimized, which it wouldn't have been if I had a lot more RAM and ROM available.
temtronic



Joined: 01 Jul 2010
Posts: 9245
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Jul 18, 2016 11:17 am     Reply with quote

Yup.. that makes sense ! Use what you have in inventory and get educated at the same time. BTDT.

Jay
Futterama



Joined: 17 Oct 2005
Posts: 98

View user's profile Send private message

PostPosted: Mon Jul 18, 2016 11:33 am     Reply with quote

PCM programmer wrote:
Quote:
Is there a clever way to compare two int16 where the execution
time remains the same regardless of variable content?

If you XOR the 16-bit values, the compiler will first XOR the LSB's then
XOR the MSB's and then OR the results of each test. Use this line:
Code:
if(value1 ^ value2)

If the two values are not equal, the body of the if() statement will be
executed. That's because if you XOR two equal bit values, you get 0.
If they are not equal, you get one or more of the bits set to 1, and
that's non-zero, which is seen as "True" by the compiler.

It gives this ASM code:
Code:
.................... if(value1 ^ value2)
0019:  MOVF   16,W   
001A:  XORWF  18,W  // XOR LSB's
001B:  MOVWF  10
001C:  MOVF   17,W
001D:  XORWF  19,W    // XOR MSB's
001E:  MOVWF  13
001F:  MOVF   10,W 
0020:  IORWF  13,W   // OR together the two previous results
0021:  BTFSC  03.2   // Branch if the result is non-zero 
0022:  GOTO   026    // Jump if zero (both values are equal)


Partial test program:
Code:

void main()
{
int16 value1 = 0x1235;
int16 value2 = 0x1234;
int8 equal;

if(value1 ^ value2)
   equal = FALSE;
else
   equal = TRUE;

}


If you want to make it operate with positive logic, which is more
reasonable, you can negate the XOR result:
Code:

if(!(value1 ^ value2))
   equal = TRUE;
else
   equal = FALSE;

if(equal == TRUE)
   printf("Equal\r");
else
   printf("Not equal\r");

Thank you sir, this works flawlessly!

If you need some PIC10F222 for a project, just give me a shout, and I will supply Very Happy
Ttelmah



Joined: 11 Mar 2010
Posts: 19545

View user's profile Send private message

PostPosted: Mon Jul 18, 2016 12:04 pm     Reply with quote

As a couple of 'add on' comments to this. When you have finished, and have it working as you want, store the source files, and the compiler used. Put a note in the source file saying 'using compiler x.xx', and noting the reason. Then if you come back to it, you can carry on from where you are.

Generally, the use of the logic test here is pretty certain to ensure the operation remains '16bit', since done like this, any bit set has the same priority, which is not the case for an arithmetic test.
Futterama



Joined: 17 Oct 2005
Posts: 98

View user's profile Send private message

PostPosted: Mon Jul 18, 2016 12:27 pm     Reply with quote

Ttelmah, thanks, I will do that.

Now, can we do something similar with the following statement?

Code:
if((InputPin) && (Some_int8_value > 0))


I think the ASM code says if InputPin is not high, GOTO the else statement, so here it doesn't check the second statement if the first evaluates as false:

Code:
0040:  BTFSS  06.3
0041:  GOTO   053
0042:  MOVF   0F,F
0043:  BTFSC  03.2
0044:  GOTO   053
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Tue Jul 19, 2016 2:02 am     Reply with quote

Futterama wrote:
Now, can we do something similar with the following statement?

Code:
if((InputPin) && (Some_int8_value > 0))


I think the ASM code says if InputPin is not high, GOTO the else statement, so here it doesn't check the second statement if the first evaluates as false.


Yes, that's what happens. It's called "lazy evaluation" and is intended as a speed optimisation. Many implimentations of many languages do it, and it generally cannot be turned off. You are asking the compiler to waste time and run slowly. The obvious way round it would be to split the condition into two if statements. Be aware that optimisation may affect the code generated. Try something like:

Code:
if(InputPin)
{
    if (Some_int8_value > 0)
    {
        // Do something.
    }
    else
    {
        // Do another thing.
    }
}
else
{
    // Do another thing copy. Must be the same as above to balance the code paths.
}
Futterama



Joined: 17 Oct 2005
Posts: 98

View user's profile Send private message

PostPosted: Tue Jul 19, 2016 4:23 am     Reply with quote

RF_Developer, thanks, I actually already did that, and it will actually fit my code flow better that way Smile
Futterama



Joined: 17 Oct 2005
Posts: 98

View user's profile Send private message

PostPosted: Sat Jul 23, 2016 9:01 am     Reply with quote

Followup on this thread. I succeeded in making my code do the loop in exactly the same amount of time +/- 100ns according to my scope.

The way I did it was to clear Timer0 at the very beginning of my mail while-loop. The prescale is set so that the TMR0 value changes from 0 to 1 in 32µs. Since the polling of TMR0 takes 3 instructions:
Code:
....................       while(TMR0 != 1); // Wait for Timer0 to get predictive duration for each loop
0175:  DECFSZ 01,W
0176:  GOTO   175
0177:  GOTO   0C0

all I had to do was to make sure all the different ways through the code wound take a number of instructions that can be divided by 3. E.g. 3-6-9-12 and so on. This way, when the code reaches the TMR0 polling, TMR0 would change to 1 at just the right moment.
This would then also mean that some of my code looks like this:
Code:
            case 3: // 6µs or 7,5µs
               if(!(ShotDelayCount ^ SparkDuration)) // ShotDelayCount == SparkDuration
               {
                  HV2 = 0;       // Deactivate spark on output 2
                  ShootMode = 4; // Jump to wait mode
                  Skip;
               }else{Skip;Skip;}
               Skip;Skip;
            break;

"Skip" is a define:
Code:
#define Skip{#asm NOP #endasm }

A lot of "Skips" are used throughout my code, and it gets a bit confusing at times, but it works really well now. I couldn't have done it without my 4-channel digital scope, or maybe an ASM book Laughing

Thanks to you all! Very Happy
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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