Hallo,
ausgehend eines Posts unten auf Seite 1 habe ich mir auch Gedanken gemacht über die Performance und nach dem basteln einer Testroutine im Setup-Abschnitt noch etwas Performance rausbekommen.
Somit ist die Anzahl an Sinus-/Cosinusfunktionen je Sekunde von durchschnittlich 65000 auf 130000 gestiegen.
Hier die neue "Fast-Sinus-Cosinus-Funktion" 
const PROGMEM uint16_t SinCosTab[91] =
{0,572,1144,1715,2286,2856,3425,3993,4560,5126,5690,
6252,6813,7371,7927,8481,9032,9580,10126,10668,11207,
11743,12275,12803,13328,13848,14365,14876,15384,15886,16384,
16877,17364,17847,18324,18795,19261,19720,20174,20622,21063,
21498,21926,22348,22763,23170,23571,23965,24351,24730,25102,
25466,25822,26170,26510,26842,27166,27482,27789,28088,28378,
28660,28932,29197,29452,29698,29935,30163,30382,30592,30792,
30983,31164,31336,31499,31651,31795,31928,32052,32166,32270,
32365,32449,32524,32588,32643,32688,32723,32748,32763,32768};
int SinCos(int Winkel, int x, byte Cos){
int winkel=Winkel;
while(Winkel>360)Winkel-=360;
if(Cos)goto GetCos;
GetSin:
Winkel-=90; // subiw Winkel,90
if(Winkel<0)goto GetSC1; // brcs GetSC1
GetCos:
Winkel-=90; // subiw Winkel,90
if(Winkel<0)goto GetSC2; // brcs GetSC2
goto GetSin; // rjmp GetSin
GetSC1:
Winkel+=90; // addi WinkelL,90
goto GetSC3; // rjmp GetSC3
GetSC2:
Winkel=-Winkel; // neg WinkelL
GetSC3:
x=(long)x*(pgm_read_word(SinCosTab+Winkel))<<1>>16;
if(Cos){if(winkel<90 or winkel>270)return x;}
else {if(winkel<180)return x;}
return -x;
}
Bei der Berechnung x*(pgm_read... erzwinge ich den Compiler dazu das er nicht 15 mal (/32768) 4 Register über Carry-Flag nach rechts schiebt sondern das durch <<1 (*2) nur ein mal nach links geschoben wird und mittels >>16 (/65536) ein Register-Swap, sowas wie mov r0,r2 und mov r1,r3 durchgeführt wird.
Ich vermute, das durch ein >>15, wie vorher, der Compiler eine 15ner Schleife gebaut hat in der 4 Register (Long-Byte) Bit für Bit geschoben wurden.
Jedenfalls ist es nun wirklich schnell.
Eine Routine in der mein 32u4 vorher 23ms für 255 Objekte benötigt hat sind es nun 19ms was der Framerate zu gute kommt.
Hier noch das Testtool zum ermitteln der Performance:
#define uintB uint8_t
#define uintW uint16_t
#define uintL uint32_t
TCCR1A = 0;
TCCR1B = (1<<CS11|1<<CS10); // 64 als Prescale-Wert
uintW Winkel=0;
uintW rx=375;
uintB Cos=0;
uintW Tset;
loop:
uintL SinCnt=0;
for(byte n=0;n<4;n++){
cli();
Tset=TCNT1+2;
while(Tset>TCNT1);
TCNT1 = 0;
while(TCNT1<62500){ //entspricht 250ms
uintW x=SinCos(Winkel++,rx,Cos);
while(Winkel>359)Winkel-=360;
SinCnt++;
}
}
sei();
Serial.begin(2500000);
while(!Serial);
if(Cos)Serial.print("Cosinus");
else Serial.print("Sinus");
Serial.print("berechnungen/s: ");
Serial.println(SinCnt);
Serial.end();
goto loop;
In die Variable rx ist der zu "drehende" Wert, Winkel ist klar (0-360), mit Tset wird der Timer1 kalibriert.
Mit Cos bestimmt man ob Sinus (0) oder Cosinus (1).
Der Timer1 bekommt einen Prescaler von 64. 250 T1-Takte entsprechen genau 1ms, 250ms (1/4s) sind dann 62500 T1-Takte und das 4 mal eine Sekunde. SinCnt zählt die Operationen durch.
Vorsicht mit dem sei();. Nicht nach unten verschieben sonst wird es sehr schwer einen 32u4 wieder zu flaschen ^^
MfG
Andi