|
|
View previous topic :: View next topic |
Author |
Message |
Guest
|
Faster code needed |
Posted: Thu Apr 24, 2008 2:31 pm |
|
|
Hi All,
I have a speed problem, I need shorter time for this code.
Is there a faster way to do this code, even in asm ??
Code: | .................... if(Rx_Buffer[0] == DMcntr) output_low(PIN_B0);
0056: MOVLB 2
0058: MOVF x7A,W
005A: SUBWF 0D,W
005C: BTFSC FD8.2
005E: BCF F8A.0
.................... if(Rx_Buffer[1] == DMcntr) output_low(PIN_B1);
0060: MOVF x7A,W
0062: SUBWF 0E,W
0064: BTFSC FD8.2
0066: BCF F8A.1
.................... if(Rx_Buffer[2] == DMcntr) output_low(PIN_B2);
0068: MOVF x7A,W
006A: SUBWF 0F,W
006C: BTFSC FD8.2
006E: BCF F8A.2
.................... if(Rx_Buffer[3] == DMcntr) output_low(PIN_B3);
0070: MOVF x7A,W
0072: SUBWF 10,W
0074: BTFSC FD8.2
0076: BCF F8A.3
.................... if(Rx_Buffer[4] == DMcntr) output_low(PIN_B4);
0078: MOVF x7A,W
007A: SUBWF 11,W
007C: BTFSC FD8.2
007E: BCF F8A.4
.................... if(Rx_Buffer[5] == DMcntr) output_low(PIN_B5);
0080: MOVF x7A,W
0082: SUBWF 12,W
0084: BTFSC FD8.2
0086: BCF F8A.5
.................... if(Rx_Buffer[6] == DMcntr) output_low(PIN_B6);
0088: MOVF x7A,W
008A: SUBWF 13,W
008C: BTFSC FD8.2
008E: BCF F8A.6
.................... if(Rx_Buffer[7] == DMcntr) output_low(PIN_B7);
0090: MOVF x7A,W
0092: SUBWF 14,W
0094: BTFSC FD8.2
0096: BCF F8A.7
....................
.................... if(Rx_Buffer[8] == DMcntr ) output_low(PIN_D0);
0098: MOVF x7A,W
009A: SUBWF 15,W
009C: BTFSC FD8.2
009E: BCF F8C.0 |
|
|
|
Ttelmah Guest
|
|
Posted: Thu Apr 24, 2008 2:44 pm |
|
|
No.
The code being generated there, looks just about how you would code it in assembler. You are already using fast_io mode (which otherwise would use an extra instruction for every I/O operation), and the compiler seems to be optimising pretty well to 'perfect' code.
We might be able to work out a faster overall solution, if we knew what you were actually trying to do. You are lowering individual pins, based on whether a counter matches eight different values. Why?. What is the actual 'objective'?.
The speed will be very quick as it stands. Even if only running at 4MHz, it'll only take 37uSec to execute, while if you can up the clock to 40MHz, it'll only take 3.7uSec. The latter is the 'best' way to speed it up (run the processor faster...).
Best Wishes |
|
|
Guest
|
|
Posted: Thu Apr 24, 2008 3:11 pm |
|
|
Hi,
I need to check if a value exists in one of the buffer bytes and clear a pin.
actually I test the value over 48 bytes on 6 ports.
I already speed up to 40Mhz and still i need to do it under 15us on all 6 ports.
well is there any way to do it? |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
Re: Faster code needed |
Posted: Thu Apr 24, 2008 4:56 pm |
|
|
Anonymous wrote: | Hi All,
I have a speed problem, I need shorter time for this code.
Is there a faster way to do this code, even in asm ??
.................... if(Rx_Buffer[0] == DMcntr) output_low(PIN_B0);
0056: MOVLB 2
0058: MOVF x7A,W
005A: SUBWF 0D,W
005C: BTFSC FD8.2
005E: BCF F8A.0
.................... if(Rx_Buffer[1] == DMcntr) output_low(PIN_B1);
0060: MOVF x7A,W
0062: SUBWF 0E,W
0064: BTFSC FD8.2
0066: BCF F8A.1
.................... if(Rx_Buffer[2] == DMcntr) output_low(PIN_B2);
0068: MOVF x7A,W
006A: SUBWF 0F,W
006C: BTFSC FD8.2
006E: BCF F8A.2
.................... if(Rx_Buffer[3] == DMcntr) output_low(PIN_B3);
0070: MOVF x7A,W
0072: SUBWF 10,W
0074: BTFSC FD8.2
0076: BCF F8A.3
.................... if(Rx_Buffer[4] == DMcntr) output_low(PIN_B4);
0078: MOVF x7A,W
007A: SUBWF 11,W
007C: BTFSC FD8.2
007E: BCF F8A.4
.................... if(Rx_Buffer[5] == DMcntr) output_low(PIN_B5);
0080: MOVF x7A,W
0082: SUBWF 12,W
0084: BTFSC FD8.2
0086: BCF F8A.5
.................... if(Rx_Buffer[6] == DMcntr) output_low(PIN_B6);
0088: MOVF x7A,W
008A: SUBWF 13,W
008C: BTFSC FD8.2
008E: BCF F8A.6
.................... if(Rx_Buffer[7] == DMcntr) output_low(PIN_B7);
0090: MOVF x7A,W
0092: SUBWF 14,W
0094: BTFSC FD8.2
0096: BCF F8A.7
....................
.................... if(Rx_Buffer[8] == DMcntr ) output_low(PIN_D0);
0098: MOVF x7A,W
009A: SUBWF 15,W
009C: BTFSC FD8.2
009E: BCF F8C.0 |
If you write this in assembly you could remove the MOVF x7A,W after it is loaded to the W register the first time. That would be about 20% faster or just under 15uS.
Last edited by Neutone on Thu Apr 24, 2008 4:59 pm; edited 1 time in total |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Apr 24, 2008 4:56 pm |
|
|
Your timing requirements are tight...
Let's assume we could reduce the test for each port to 3 instruction times than you could just make it as this requires 38.4MHz, giving you little time for preparing the next loop.
What is DMcntr? Is this a counter counting up?
If yes, than you might try to change it into a countdown counter instead. Comparing to a value of 0 is easier for the processor and will remove the subwf instruction in every test from the above shown code. Theoretically that would give your desired speed.
Which processor are you using? |
|
|
RLScott
Joined: 10 Jul 2007 Posts: 465
|
Re: Faster code needed |
Posted: Thu Apr 24, 2008 5:11 pm |
|
|
Anonymous wrote: |
.................... if(Rx_Buffer[0] == DMcntr) output_low(PIN_B0);..
|
From your use of the descriptive variable name, Rx_Buffer[], I would guess that the values in Rx_Buffer[] were placed there as the result of a serial read of some sort. You probably took some time to collect those bytes. In that case the way to speed this up is to change your receive routine to make the comparisons while the data is being accumulated. You could store the results in a temporary location, rather than affecting Port B at the time of reception if you like. Then when all 8 bytes have been received, just do:
PortB = TempByte;
Of course this assumes that you know the value of DMcntr during the reception of Rx_Buffer. If you don't then this method won't work.
Robert Scott
Real-Time Specialties |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Apr 24, 2008 5:46 pm |
|
|
I guess this is some kind of LED display application? Maybe RGB led's with changing graphics, where the counter value defines the led intensity/color? Am I right?
Neutone triggered me to think of another optimization possibility, resulting in only two instructions per output pin, twice the speed of the original post. With 8,1us at 40MHz well within the requirements of 15us.
Code: | #define PORTB 0xF8A
void main(void)
{
int8 Rx_Buffer[8];
int8 DMcntr;
// Init
memset(Rx_Buffer, 0, sizeof(Rx_Buffer));
DMcntr = 10;
// Do the tests
#ASM
MOVF DMcntr,w // Load compare value once
CPFSEQ RX_Buffer[0] // if (RX_Buffer[0] != DMcntr) NOTE: this is opposite to original program !!!
BCF PORTB.0 // output_low(PIN B0) Read description below.
CPFSEQ RX_Buffer[1] // if (RX_Buffer[1] != DMcntr)
BCF PORTB.1 // output_low(PIN B1)
CPFSEQ RX_Buffer[2] // if (RX_Buffer[2] != DMcntr)
BCF PORTB.2 // output_low(PIN B2)
CPFSEQ RX_Buffer[3] // if (RX_Buffer[3] != DMcntr)
BCF PORTB.3 // output_low(PIN B3)
CPFSEQ RX_Buffer[4] // if (RX_Buffer[4] != DMcntr)
BCF PORTB.4 // output_low(PIN B4)
CPFSEQ RX_Buffer[5] // if (RX_Buffer[5] != DMcntr)
BCF PORTB.5 // output_low(PIN B5)
CPFSEQ RX_Buffer[6] // if (RX_Buffer[6] != DMcntr)
BCF PORTB.6 // output_low(PIN B6)
CPFSEQ RX_Buffer[7] // if (RX_Buffer[7] != DMcntr)
BCF PORTB.7 // output_low(PIN B7)
#ENDASM
while(1);
} |
There is only one problem... the PIC has no CPFSNEQ instruction causing the shown implementation of the program to do just the opposite of the original program; only clearing the port when the values are not equal. I don't know the application well enough to say what the best workaround is:
1) There must be an output_high somewhere in the code, so with small adaptation to the algorithm that could be swapped around.
or
2) There is an instruction CPFSGT which will skip the output_low when DMcnt is smaller than RX_buffer[x].
or
3) same as 2, but now instruction CPFSLT which will skip if DMcnt larger.
or
4) Use the earlier given suggestion of counting down to zero. Count down the values in RX_Buffer until zero is reached (use INFSNZ). |
|
|
Guest
|
|
Posted: Fri Apr 25, 2008 1:22 pm |
|
|
Hi All,
Neutone: the Idea you had was not working because wreg was lost after the first SUBWF opcode ...
The next SUBWF opcode tests the wrong wreg and everything goes wrong ..
So is there another way ????
ckielstra: I didnt get your Idea, could you please explain in pic valid opcodes.
All others, Any Ideas ??? |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Apr 25, 2008 2:08 pm |
|
|
Quote: | ckielstra: I didnt get your Idea, could you please explain in pic valid opcodes. | Copy/paste all shown code. This is a direct copy from a working example program I made. You only have to add #fuses and the processor type because you still haven't answered the question about which type you are using.
I think we have given you a lot of ideas, maybe you didn't understand all details but then we are willing to give a more detailed explanation.
As you did not answer our questions I can't help you further. Provide more details about your program and answer the questions. |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
|
Posted: Fri Apr 25, 2008 2:29 pm |
|
|
Anonymous wrote: | Hi All,
Neutone: the Idea you had was not working because wreg was lost after the first SUBWF opcode ...
The next SUBWF opcode tests the wrong wreg and everything goes wrong ..
So is there another way ????
ckielstra: I didnt get your Idea, could you please explain in pic valid opcodes.
All others, Any Ideas ??? |
Replace the W's with F's.
SUBWF 11,W places the result in the W register.
SUBWF 11,F places the result in the F register. I think that's how the assembly syntax works.
This will erase/randomize your serial buffer as it goes but it should work. |
|
|
|
|
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
|