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

fast int1 array access

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



Joined: 22 Sep 2012
Posts: 37

View user's profile Send private message

fast int1 array access
PostPosted: Fri Jan 25, 2013 9:03 am     Reply with quote

Hi,
I have an int8 array with N elements.
Inside the main loop, I have some operations which need to complete every 25uSec.
The pseudo-code is as follows:


Code:
Bytes={255,10,128,4}
curByteIndex=0
do
{
   
   if active_interrupt(int_timer1)      //40kHz
        {
           mainLoopCounter++;
       
            for (i=0 ; i<8 ; i++)
                    if (Bytes[curByteIndex].i == 1)        //only if bit is 1
                        perform some operations
       
             perform some operations
             .
             .
             .
             if (mainLoopCounter==10000)
                 curByteIndex++;
             clear_interrupt(int_timer1);
          }
   



For the moment I'm doing this using int1 byte[8] array which I change every time I need to load a new word:




Code:


int TxData[6]={255,255,5,170,14,35};
int TxDataIndex=0;
void setTxByte(int decVal)
{
 
  TxByte[7]=(decVal & 0b00000001);
  TxByte[6]=(decVal & 0b00000010)/2;
  TxByte[5]=(decVal & 0b00000100)/4;
  TxByte[4]=(decVal & 0b00001000)/8;
  TxByte[3]=(decVal & 0b00010000)/16;
  TxByte[2]=(decVal & 0b00100000)/32;
  TxByte[1]=(decVal & 0b01000000)/64;
  TxByte[0]=(decVal & 0b10000000)/128;
  fcnt=TxByte[0]+TxByte[1]+TxByte[2]+TxByte[3]+TxByte[4]+TxByte[5]+TxByte[6]+TxByte[7]+TxByte[8];
}

void main()
{
  while (1)
    {
        if (interrupt_active(INT_TIMER1))
         {
             //perform some operations

              for (freqIndex=0;freqIndex<freqNum;freqIndex++)
                  if (TxByte[freqIndex])
                      //perform some operations

             //perform some operations
         
             if (cnt==22050)
               {
                  setTxByte(TxData[TxDataIndex]);
                  TxDataIndex++;
                  if (TxDataIndex==6)
                     TxDataIndex=0;
                  cnt=0;
.
.
.
}
               }





The problem is that this whole process of loading a new word into TxByte creates timing problems and seems quiet cumbersome and I was wondering what would be the efficient way of performing this operation, maybe even utilizing assembly itself.

thanks,
Daniel
ckielstra



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

View user's profile Send private message

PostPosted: Fri Jan 25, 2013 9:53 am     Reply with quote

First of all, 40kHz repetition rate is very fast for a PIC. You didn't say which PIC you are using and what frequency it is running, but let's assume a PIC18 at 40MHz (about the fastest you can get).
A PIC will execute 1 instruction every 4 clock cycles. So 40MHz == 10 MIPS.
Divide by 40kHz, gives you only 250 instruction cycles. Possible, but requires great attention to coding practices.

It is possible to optimize the setTxByte function. In the first part you are reversing the bit order, for that a better implementation is present in the Code Library.

Next you are calculating the number of bits:
Code:
  fcnt=TxByte[0]+TxByte[1]+TxByte[2]+TxByte[3]+TxByte[4]+TxByte[5]+TxByte[6]+TxByte[7]+TxByte[8];
Takes 5 instructions on a PIC18 for every item, total 40 instructions. Faster is to code like this:
Code:
  fcnt = 0;
  if (TxByte[0]) fcnt++;
  if (TxByte[1]) fcnt++;
  if (TxByte[2]) fcnt++;
  if (TxByte[3]) fcnt++;
  if (TxByte[4]) fcnt++;
  if (TxByte[5]) fcnt++;
  if (TxByte[7]) fcnt++;
Which reduces the number of instructions to 2 for every item, total of 17 instructions.

But, why are you calculating these transmit bytes every time? It seems like the input table is hard coded. You could save a lot of time by calculating the Tx value only once and add this into the TxData table.

It is difficult to give you better advice because I don't understand your code. It would help when you give us more context like what the application is supposed to do.
danielz85



Joined: 22 Sep 2012
Posts: 37

View user's profile Send private message

PostPosted: Fri Jan 25, 2013 2:45 pm     Reply with quote

ckielstra, thank you for the reply,
it was extremely helpful.

I'm working with dsPIC33FJ06GS202 @ 40 MIPS.
I'm producing a signal which has 8 different frequencies around 17kHz, the sampling rate is 44kHz. Like you said, working at this rate is not trivial for the mc, therefore I'm trying to reduce the number of instructions I have. I did use the link you provided and used #bit for my purposes and also loop unrolling.

Here's my code:

Code:
 while(1)
   {
         //wait for main sampling clock to turn on
         if (interrupt_active(INT_TIMER1))
         {
            _write_dac(normSum);
            sum=0;
           
            //create a sum of all relevant sines
           fcnt=0;
           
            if (TxByte_0)
                  {sum+=sine[sineIndex[0]];fcnt++;}
            if (TxByte_1)
                  {sum+=sine[sineIndex[1]];fcnt++;}
            if (TxByte_2)
                  {sum+=sine[sineIndex[2]];fcnt++;}
            if (TxByte_3)
                  {sum+=sine[sineIndex[3]];fcnt++;}
            if (TxByte_4)
                  {sum+=sine[sineIndex[4]];fcnt++;}
            if (TxByte_5)
                  {sum+=sine[sineIndex[5]];fcnt++;}
            if (TxByte_6)
                  {sum+=sine[sineIndex[6]];fcnt++;}
            if (TxByte_7)
                  {sum+=sine[sineIndex[7]];fcnt++;}
           
           normSum = sum/fcnt;   
           
           
               sineIndex[0]+=phaseinc[0];
               if (sineIndex[0]>=sineSize)
                  sineIndex[0]-=sineSize;
               
               sineIndex[1]+=phaseinc[1];
               if (sineIndex[1]>=sineSize)
                  sineIndex[1]-=sineSize;                 
               
               sineIndex[2]+=phaseinc[2];
               if (sineIndex[2]>=sineSize)
                  sineIndex[2]-=sineSize;                 
                 
               sineIndex[3]+=phaseinc[3];
               if (sineIndex[3]>=sineSize)
                  sineIndex[3]-=sineSize;

               sineIndex[4]+=phaseinc[4];
               if (sineIndex[4]>=sineSize)
                  sineIndex[4]-=sineSize;

               sineIndex[5]+=phaseinc[5];
               if (sineIndex[5]>=sineSize)
                  sineIndex[5]-=sineSize;

               sineIndex[6]+=phaseinc[6];
               if (sineIndex[6]>=sineSize)
                  sineIndex[6]-=sineSize;

               sineIndex[7]+=phaseinc[7];
               if (sineIndex[7]>=sineSize)
                  sineIndex[7]-=sineSize;
             
            cnt++;
            if (cnt==40000) //about 1 sec
               {
                  TxByte=TxData[TxDataIndex++];
                 
                  if (TxDataIndex==wordsNum)
                     TxDataIndex=0;
                  cnt=0;
               }
           
            clear_interrupt(INT_TIMER1);

           
      }


In your opinion,
Can I further optimize the code above?
thanks again,
Daniel
ckielstra



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

View user's profile Send private message

PostPosted: Mon Jan 28, 2013 1:20 am     Reply with quote

I don't have a compiler for the dsPIC33 so I can't check the resulting assembly.

Loop unrolling as you did is always a good speed optimization technique.

Have a look at the generated code in the list file (*.lst). Here you can easily see how much assembly code is generated for each line of C. Sometimes you will be surprised by the number of instructions required for a simple C operation. These are candidates for optimization.

Another tip is to run the code in the MPLAB Simulator (free). Set a breakpoint at critical sections and use the Stopwatch function to measure timings.
danielz85



Joined: 22 Sep 2012
Posts: 37

View user's profile Send private message

PostPosted: Mon Jan 28, 2013 4:01 am     Reply with quote

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