|
|
View previous topic :: View next topic |
Author |
Message |
kypec
Joined: 20 Sep 2003 Posts: 54
|
How to save the execution time? |
Posted: Tue Nov 18, 2003 8:51 am |
|
|
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
perhaps guys from CCS could help me with this |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Nov 18, 2003 3:52 pm |
|
|
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
|
|
Posted: Sat Nov 29, 2003 3:11 pm |
|
|
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 |
Posted: Sat Nov 29, 2003 4:49 pm |
|
|
x=thickness/10;
content_t10=digit[x];
content_t1=digit[thickness-(x<<3)-(x<<1)]; |
|
|
Ttelmah Guest
|
Re: One easy way |
Posted: Sun Nov 30, 2003 3:37 pm |
|
|
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 |
|
|
|
|
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
|