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

Speeding up loop

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



Joined: 09 Feb 2007
Posts: 56

View user's profile Send private message

Speeding up loop
PostPosted: Wed Apr 23, 2008 11:25 am     Reply with quote

I have a simple loop to transmit data to a device which I need to speed up. The code I have is as follows:

for (i=0; i<n; i++)
{
output_d(Data[i]);
while (input(TXE)) //Wait till ready
delay_cycles(1);
output_high(WR);
output_low(WR);
}

My problem is that the peak rate of the loop is about a byte very 2.1us. The command that is taking the longest is the 'output_d(Data[i])' Any suggestions of how I could speed this up? My target is about a byte every 1us..

I am using a PIC18F97J60 at 41.6MHz. The external device is very fast and it only takes 400ns to recover after being written to.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Apr 23, 2008 11:33 am     Reply with quote

Look at your .LST file, and then make changes in your source, and
watch the effect on the code size.

You could speed it up a little bit by using Fast i/o mode, and set the TRIS
before you enter the loop.

The major thing is indexing into that array. You'll see that in the .LST file.
If you want to speed it up, you've got to get rid of that.
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

Re: Speeding up loop
PostPosted: Wed Apr 23, 2008 12:17 pm     Reply with quote

How about this:
Code:

int *DataPtr;
DataPtr = &Data[0];
i = n;
do
{
  output_d(*DataPtr);
  DataPtr++;
  while (input(TXE)) //Wait till ready
     ;
  output_high(WR);
  output_low(WR);
}while(--i);


There is no sense calling delaycycles() as long as input(TXE) is something that you can do over and over without harm. Also, doing the DataPtr++ before checking TXE increases the chances that you may not need to go around the while(input(TXE)) loop at all. And decrementing "i" at the end and checking for zero is the fastest iteration control because the compiler optimizes this construct with a DECFSZ.

Robert Scott
Real-Time Specialties
n-squared



Joined: 03 Oct 2006
Posts: 99

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Wed Apr 23, 2008 4:45 pm     Reply with quote

I would like to suggest a little twist on RLScott's code.
By adding a single int variable, you may squeeze a small gain in speed.
next_byte variable is updated with next byte to send while waiting for TXE to fall.


Code:

int *DataPtr;
int next_byte;
next_byte = Data[0];
DataPtr = &Data[1];
i = n;
do
  {
  output_d(next_byte);
  next_byte = *DataPtr++;
  while (input(TXE)) //Wait till ready
     ;
  output_high(WR);
  output_low(WR);
  }
while(--i);



Noam Naaman
Meteorox - Access Control Systems
_________________
Every solution has a problem.
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

Re: Speeding up loop
PostPosted: Wed Apr 23, 2008 8:02 pm     Reply with quote

nazoa wrote:
I have a simple loop to transmit data to a device which I need to speed up. The code I have is as follows:

for (i=0; i<n; i++)
{
output_d(Data[i]);
while (input(TXE)) //Wait till ready
delay_cycles(1);
output_high(WR);
output_low(WR);
}

My problem is that the peak rate of the loop is about a byte very 2.1us. The command that is taking the longest is the 'output_d(Data[i])' Any suggestions of how I could speed this up? My target is about a byte every 1us..

I am using a PIC18F97J60 at 41.6MHz. The external device is very fast and it only takes 400ns to recover after being written to.


This should be a small incremental bump in speed. With the improved loop and fast IO it should be under 1uS loop time.
Code:
   #Byte Target_Inc = 0x0FE6        // Increments FSR1 after use
   Int16 Target_Address;
   #locate Target_Address = 0x0FE1  // FSR1 address

   Target_Address = &Data[0];       // Assign addres of array to copy
   i=n;
   do
   {
      output_d(Target_Inc);
      while (input(TXE));        //Wait till ready
      output_high(WR);
      output_low(WR);
   }while(--i);
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Apr 23, 2008 8:17 pm     Reply with quote

Hi Neutone, you were just ahead of me. No post on this thread for more than 3 hours and just when I want to post my solution I see you beat me by a few minutes. Crying or Very sad

I came up with the same solution as Neutone.
Address calculation of the array takes up a lot of time and is performed again and again inside the loop. On a PIC18 processor this can be improved a lot by using the Index registers. Set up the Index once before the loop and then reading the data from the POSTINC register will do an automatic post increment on the address pointer.

Code:
// Register defines for PIC18
// Place this at the global level, or in a separate include file with register definitions.
unsigned int16 FSR0;
#locate FSR0=0x0FE9

unsigned char POSTINC0;
#locate POSTINC0=0x0FEE


Code:
  FSR0 =  &Data[0];          // Set start address
  i = n;
  do
  {
    output_d( POSTINC0 );   // output data from array and increment pointer
    while (input(TXE))      //Wait till ready
       ;
    output_high(WR);
    output_low(WR);
  }
  while(--i);


I don't think it can be made faster than this. Tested in MPLAB's simulator it proofed to be about twice as fast as N-squared's version and very close to 1us (at 40MHz).
n-squared



Joined: 03 Oct 2006
Posts: 99

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Wed Apr 23, 2008 10:16 pm     Reply with quote

Hi ckielstra,
You live and learn...
I really like your solution.
I guess it will safely work only in a tight loop where the compiler has no chance of "corrupting" the two registers.
Thanks.
Noam
_________________
Every solution has a problem.
nazoa



Joined: 09 Feb 2007
Posts: 56

View user's profile Send private message

PostPosted: Thu Apr 24, 2008 3:02 am     Reply with quote

Very good. I have tried it and it cuts down my loop timing to 1.2us per byte. This solves my problem.

Although the loop is tight there is a small chance that it can be interrupted by a simple ISR that collects data. I have run the loop many times and I saw it crash once but, of course it is difficult to be sure what caused the crash.

Thanks to all and particularly to Neutone and ckielstra for the suggestions.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Apr 24, 2008 7:19 am     Reply with quote

n-squared wrote:
I guess it will safely work only in a tight loop where the compiler has no chance of "corrupting" the two registers.
The compiler doesn't use the index registers very often but you do have a point. Thinking about it, most array accesses are performed using the first index register so care should be taken.

An easy way to make this method more reliable is to use another index register, there are a total of three (FSR0 to FSR2). I've never seen the compiler use more than 2 index registers at the same time (in memcpy), so using Index register FSR2 should be relative save.

nazoa wrote:
Although the loop is tight there is a small chance that it can be interrupted by a simple ISR that collects data."
Interrupts shouldn't be a problem as the 3 index registers are saved and restored by the CCS interrupt dispatcher.

Note: there is no risk of altering the POSTINCx registers as they are no real physical registers but only another representation of the FSRx registers.
n-squared



Joined: 03 Oct 2006
Posts: 99

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Thu Apr 24, 2008 9:28 am     Reply with quote

Hi ckielstra,

Good point about FSR2.
By the way, CCS XINST and NOXINST fuses but I never see it using the extended instructions. Do you know if the XINST does anything?

Best regards
Noam
_________________
Every solution has a problem.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Apr 24, 2008 9:59 am     Reply with quote

As far as I know does v4.071 not support the Extended Instruction Set (XINST). Some compiler versions have/had this fuse enabled by default and this caused erratic behaviour in several programs. Best is to explicitly set NOXINST for now.
nazoa



Joined: 09 Feb 2007
Posts: 56

View user's profile Send private message

PostPosted: Thu Apr 24, 2008 11:10 am     Reply with quote

I have tried changing to FSR2 and things are looking quite stable now. Not seen a single crash after a few hours of testing. Thanks.
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