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

Faster code needed

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








Faster code needed
PostPosted: Thu Apr 24, 2008 2:31 pm     Reply with quote

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







PostPosted: Thu Apr 24, 2008 2:44 pm     Reply with quote

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








PostPosted: Thu Apr 24, 2008 3:11 pm     Reply with quote

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

View user's profile Send private message

Re: Faster code needed
PostPosted: Thu Apr 24, 2008 4:56 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Apr 24, 2008 4:56 pm     Reply with quote

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

View user's profile Send private message

Re: Faster code needed
PostPosted: Thu Apr 24, 2008 5:11 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Apr 24, 2008 5:46 pm     Reply with quote

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








PostPosted: Fri Apr 25, 2008 1:22 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Apr 25, 2008 2:08 pm     Reply with quote

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.

Quote:
Any Ideas ???
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

View user's profile Send private message

PostPosted: Fri Apr 25, 2008 2:29 pm     Reply with quote

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.
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