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

How to save the execution time?

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



Joined: 20 Sep 2003
Posts: 54

View user's profile Send private message

How to save the execution time?
PostPosted: Tue Nov 18, 2003 8:51 am     Reply with quote

Hello,

I need to load 7-segment LED displays with characters
depending on the binary 8-bit value of a variable.
I'm using PIC18F452 and PCH 3.180
My table for 7-segment digits patterns and used variables
are defined like this:
int8 const digit[10]={
CHARACTER_0,
CHARACTER_1,
CHARACTER_2,
CHARACTER_3,
CHARACTER_4,
CHARACTER_5,
CHARACTER_6,
CHARACTER_7,
CHARACTER_8,
CHARACTER_9
};
int8 content_t10,content_t1; //thickness LEDs
int8 thickness=98;

and CHARACTER_n is composed of several bit masks of single
segments.

Below you can see an excerpt from Disassembly window (MPLAB 6.32).

Code:

339:                              content_t10=digit[thickness/10];
00042E    C01F     MOVFF 0x1f, 0x2c
000432    0E0A     MOVLW 0xa
000434    6E2D     MOVWF 0x2d, ACCESS
000436    EC12     CALL 0x24, 0
00043A    6A03     CLRF 0x3, ACCESS
00043C    5001     MOVF 0x1, W, ACCESS
00043E    EC02     CALL 0x4, 0
000442    6E01     MOVWF 0x1, ACCESS
000444    C001     MOVFF 0x1, 0x12
340:                              content_t1=digit[thickness%10];
000448    C01F     MOVFF 0x1f, 0x2c
00044C    0E0A     MOVLW 0xa
00044E    6E2D     MOVWF 0x2d, ACCESS
000450    EC12     CALL 0x24, 0
000454    6A03     CLRF 0x3, ACCESS
000456    5000     MOVF 0, W, ACCESS
000458    EC02     CALL 0x4, 0
00045C    6E01     MOVWF 0x1, ACCESS
00045E    C001     MOVFF 0x1, 0x13


as you may see the integer division /10 and modulo %10 are both
using the same function CALL 0x24, 0

is there any chance to simplify my code so that it will execute
the division just once?
if this could be achieved then all I need to do is to retrieve the proper
results of division /10 (MOVF 0x1, W, ACCESS @00043C)
and modulo %10 (MOVF 0, W, ACCESS @000456) only once thus
saving the execution time significantly Wink

perhaps guys from CCS could help me with this Question
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Nov 18, 2003 3:52 pm     Reply with quote

One possible solution is to reverse-engineer the CCS division routine.
You can see it, if you open the Program Memory window in MPLAB.
It's called @DIV88. You could put that code in a "wrapper" function
and then put the results into global variables. Or, you could return
an int16 value, and put the result in the lower byte, and the modulus
in the high byte. You could also return an 8 bit value, but put
the modulus in a global variable.

int16 divide88(int8 numerator, int8 divisor)
{
char count; // local variable
#asm

// Put the @DIV88 code here.
// Modify it to use parameter variable
// names such as "numerator", "divisor", and "count"
// instead of memory locations.

#endasm

}

Also, remember that CCS has a special variable that allows
you to easily return an 8-bit value from ASM code. It's called _RETURN_.
Example:

return(_RETURN_);

But, this is only 8 bits. You need to return two bytes, so maybe use
a global for the modulus, or return a 16 bit value.
Ttelmah
Guest







PostPosted: Sat Nov 29, 2003 3:11 pm     Reply with quote

PCM programmer wrote:
One possible solution is to reverse-engineer the CCS division routine.
You can see it, if you open the Program Memory window in MPLAB.
It's called @DIV88. You could put that code in a "wrapper" function
and then put the results into global variables. Or, you could return
an int16 value, and put the result in the lower byte, and the modulus
in the high byte. You could also return an 8 bit value, but put
the modulus in a global variable.

int16 divide88(int8 numerator, int8 divisor)
{
char count; // local variable
#asm

// Put the @DIV88 code here.
// Modify it to use parameter variable
// names such as "numerator", "divisor", and "count"
// instead of memory locations.

#endasm

}

Also, remember that CCS has a special variable that allows
you to easily return an 8-bit value from ASM code. It's called _RETURN_.
Example:

return(_RETURN_);

But, this is only 8 bits. You need to return two bytes, so maybe use
a global for the modulus, or return a 16 bit value.


I happened to be looking at this, following the above comments, in relation to a latter thread, where the same pair of routines (division and modulus), were being used together for a numeric output of a scaled integer value. Since being able to access the two results from a single division would be an elegant way of reducing code size, and execution time, it made sense to try to 'combine' the data returns in some way.
While playing with trying to 'embed' the function, and access the scratch area, I can across a shortcut, that takes advantage of the way that the CCS compiler executes.

union fullval {
int32 whole;
int8 b[4];
};

union fullval div16_rem(int16 val,int16 div) {
int16 temp;
temp=val/div;
return;
}

void main() {
union fullval val;
int16 source;
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_CLOCK_DIV_2);
setup_spi(FALSE);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
source=12345;
val=div16_rem(source,100l);
printf("val %lu.%2lu",make16(val.b[2],val.b[1]),make16(val.b[3],val.b[0]));
while(1) {

}
}

Basically, I found that if you execute a call to a routine that is declared to return a value, but then don't actually generate a return value inside the routine, the 'scratch' values are returned instead.
The scratch area, contains four bytes used to return the results of an int16 division. It appears that the result in in the centre 'pair' of bytes, while the remainder is in the other two. I therefore declare a union, allowing me to access the four bytes of the returned value seperately. A single call to 'div16_rem', returns the entire 4 bytes of the scratch area used by the compilers div1616 function, in the union. I can then assemble the individual pairs of bytes to generate the required values (using make16).
I haven't actually checked that the numbers are in the right order, but the code generated, definately transfers all four returned bytes to the printf function, making it an 'elegant' way of accessing the scratch area. The same trick could be used in the above thread, but with the union accessing only two bytes, and calling int8 division instead of int16.
It may well be a worthwhile 'trick' to remember as a way to access the scratch area (since the compiler doesn't allow this to be accessed easily by any other means).

Best Wishes
KerryW
Guest







One easy way
PostPosted: Sat Nov 29, 2003 4:49 pm     Reply with quote

x=thickness/10;
content_t10=digit[x];
content_t1=digit[thickness-(x<<3)-(x<<1)];
Ttelmah
Guest







Re: One easy way
PostPosted: Sun Nov 30, 2003 3:37 pm     Reply with quote

KerryW wrote:
x=thickness/10;
content_t10=digit[x];
content_t1=digit[thickness-(x<<3)-(x<<1)];

Yes. For the 'div88' solution, this is quick, and elegant (binary multiply by 10). This is a lot quicker than repeating a division.
My comment was more aimed at a 'general' solution, for anybody wanting to access the 'scratch' area from a CCS function. :-)

Best Wishes
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