|
|
View previous topic :: View next topic |
Author |
Message |
danielz85
Joined: 22 Sep 2012 Posts: 37
|
fast int1 array access |
Posted: Fri Jan 25, 2013 9:03 am |
|
|
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
|
|
Posted: Fri Jan 25, 2013 9:53 am |
|
|
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
|
|
Posted: Fri Jan 25, 2013 2:45 pm |
|
|
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
|
|
Posted: Mon Jan 28, 2013 1:20 am |
|
|
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
|
|
Posted: Mon Jan 28, 2013 4:01 am |
|
|
thanks |
|
|
|
|
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
|