Geschwindigkeit von Arduino erhöhen

Poste doch mal das Programm. Wahrscheinlich sind dort die Verzögerungen.

Wenn sich mehrere Programmteile mit delay-Methode behindern, statt dessen millis() verwenden, in einer Variable z.B. "ZeitAlt" die letzte Ausführungszeit speichern. Dann erneut in Aktion treten, wenn Aktuelle Zeit - Zeitalt > Intervall (per if-Abfrage). Für Intervall wählst du einen Wert nach der Formel: für Intervall X/sek = 1000/X. Im Setup zuvor einmalig die Anfangszeit des Sketches in ZeitAlt speichern.

Beispiel: Es soll 50 Aktualisierungen der Anzeige je Sekunde geben. Intervall d.h. die Zeit zwischen 2 Aktualisierungen sollte also 20 msek sein.

ZeitNeu = millis();
if ZeitNeu-ZeitAlt>20{Hier steht der Code für das Led umschalten, am Ende steht: ZeitAlt=ZeitNeu}

ok ein paar teile kann ich mal posten aber für alles ist es etwas zu viel...

schonmal vorweg...
es sind 6 led strips, die sternförmig verdrahtet sind.

für mich intern sehe ich es als reihenverdrahtung und rechne das ganze mit folgenden funktionen in das sternförmige um:

int calculatePartForStar(int pixel)
{
  int tempLength = 0;
  
  for(int i=0; i<HALO_SIZE; i++)
  {
    tempLength += ledLengthArray[i];
    
    if(tempLength >= pixel)
    {
      return i;
    }
  }
}

int calculatePxForStar(int pixel, int part)
{
  int tempLength = 0;
  int tempPixel = 0;
  
  for(int i=0; i<part; i++)
  {
    tempLength += ledLengthArray[i];
  }
  
  tempPixel = pixel - tempLength;
  
  return tempPixel-1;
}

in jedem loop wird dann beispielsweise folgende funktion aufgerufen:

void leftCometSolo()
{
  if(cometIndex-totalLength < endComet)
  {
    cometIndex = cometIndex + cometSpeed;
    
    for(int i=0; i<cometLength; i++)
    {
      paint(cometIndex-i, colors[infoWarningColor][0]-(i*((colors[infoWarningColor][0])/cometLength)), colors[infoWarningColor][1]-(i*((colors[infoWarningColor][1])/cometLength)), colors[infoWarningColor][2]-(i*((colors[infoWarningColor][2])/cometLength)));
    }
    
    for(int i=1; i<=cometSpeed; i++)
    {
      paint(cometIndex-cometLength - (cometSpeed-i), 0,0, 0);
    }
    
    clearOtherLeds(startComet, endComet-cometLength);
  }
}

das zeichnen der pixel erfolgt hierüber:

void paint(int pixelPos, int r, int g, int b)
{
  int part = calculatePartForStar(makeModulo(pixelPos));
  int pixel = calculatePxForStar(makeModulo(pixelPos), part);
  
  strips[part].setPixelColor(pixel, r*brightness/100, g*brightness/100, b*brightness/100);
}

void showStrip()
{
  for(int i=0; i<6; i++)
  {
    strips[i].show();
  }
}

für den überlauf in positiver oder negativer richtung ist dann das makeModulo zuständig...

hier dann noch paar variablendefinitionen:

#include "LPD8806.h"
#include "SPI.h"
#include "SimpleTimer.h"

int dataPin1 = 5;
int clockPin1 = 4;
int dataPin2 = 7;
int clockPin2 = 6;
int dataPin3 = 9;
int clockPin3 = 8;
int dataPin4 = 11;
int clockPin4 = 10;
int dataPin5 = 45;
int clockPin5 = 44;
int dataPin6 = 3;
int clockPin6 = 2;


int stripLengthv = 32;
int stripLengthvr = 16;
int stripLengthhr = 16;
int stripLengthh = 32;
int stripLengthhl = 16;
int stripLengthvl = 16;

LPD8806 strip1 = LPD8806(stripLengthv, dataPin1, clockPin1);
LPD8806 strip2 = LPD8806(stripLengthvr, dataPin2, clockPin2);
LPD8806 strip3 = LPD8806(stripLengthhr, dataPin3, clockPin3);
LPD8806 strip4 = LPD8806(stripLengthh, dataPin4, clockPin4);
LPD8806 strip5 = LPD8806(stripLengthhl, dataPin5, clockPin5);
LPD8806 strip6 = LPD8806(stripLengthvl, dataPin6, clockPin6);

LPD8806 strips[6] = {strip1, strip2, strip3, strip4, strip5, strip6};

#define HALO_SIZE 6
#define LED_PIN 13

und die setup funktion:

void setup()
{
  Serial.flush();
  
  Serial.begin(9600);
  
  pinMode(LED_PIN, OUTPUT);
  
  for(int i=0; i<6; i++)
  {
    strips[i].begin();
    strips[i].show();
  }

  clearAllLeds();
  
  blinkTimerWall.setInterval(100, blinkWall);
  
  Serial.flush();
}

der rest dürfte eigentlich nicht viel zur sache tun...hoffe ihr könnt mir helfen

Achso: delays sind außer der eine im loop (delay(2)) keine weiter drin...so ein comet braucht aber locker 2, 3 oder 4 sekunden um die runde von 128 LEDs komplett zu durchlaufen....geht doch sicher schneller oder?

hatte es in der not dann mit 2 und 3 pixel sprüngen in der for schleife versucht aber dann ist die animation sehr hakelig....

Wenn der Rest nichts zur Sache tut, dann sag mal was zu blinkTimerWall. Was bedeuteutet die 100 bei setInterval() ?

Und Serial.Flush(); kannst du auf jeden Fall rausschmeissen.

Er simuliert 6*eine SPI Schnittstelle das sind dann normal "Shiftout" Befehele und dann gehen in jeden "Zweig noch einiges an Daten" Das könnt bei entsprechender Übertragungmenge dann schon sichtbar werden. Kannst du nicht alle an einen SPI Packen und dann mit der physiklische SPI Schnittstelle des Ardus die Strips bedienen?
Gruß
Der Dani

@michael_x: der timer is für ein simples blinken der leds da...is auch nur sehr selten der fall dass es blinken soll

@ volvodani: ui das klingt als wüsstest du was probleme macht...leider weiß ich von diesem ganzen "urschleim" nicht viel....

deshalb mal die frage:

sind das die 6 SPI schnittstellen?

LPD8806 strip1 = LPD8806(stripLengthv, dataPin1, clockPin1);
LPD8806 strip2 = LPD8806(stripLengthvr, dataPin2, clockPin2);
LPD8806 strip3 = LPD8806(stripLengthhr, dataPin3, clockPin3);
LPD8806 strip4 = LPD8806(stripLengthh, dataPin4, clockPin4);
LPD8806 strip5 = LPD8806(stripLengthhl, dataPin5, clockPin5);
LPD8806 strip6 = LPD8806(stripLengthvl, dataPin6, clockPin6);

kann ich diese zu einer SPI packen ohne die strips um löten zu müssen?
steckt nämlich alles schon im gehäuse...macht sich also schwer...
es bleiben also 6 einzelne strips, die sternförmig verdrahtet sind

Hast Du diese Library mal versucht? Google Code Archive - Long-term storage for Google Code Project Hosting.

Die optimiert relativ gut und kommt mit fast allen Strips klar.

der rest dürfte eigentlich nicht viel zur sache tun...hoffe ihr könnt mir helfen

Da wär ich mir nicht so sicher. Im Rest stehen z.B. die Variablendeklarationen und die können falls floats dabei sind einen ganz erheblichen Einfluß auf die Laufzeit haben. Vor allem weil bei einigen Deiner Formeln Divisionen vorkommen. Im Zweifelsfall ist es eine gute Idee alles geeignet vorzuberechnen. Da bei Dir aber nichts nach PWM aussieht würde ich auch die SPI Libraries verdächtigen.

könnt ihr mir eventuell beim umstieg auf die fastSPI schnittstelle helfen?

reicht schon ein tauschen der includes aus?
oder muss im code da noch reichlich angepasst werden?

krieg auch das example der library nicht zum laufen....
hab nen SPI_LPD8806

könnt ihr mir eventuell beim umstieg auf die fastSPI schnittstelle helfen?

Nein, wir haben Deinen Code noch nicht gesehen (zumindest nicht vollständig).

reicht schon ein tauschen der includes aus?

Nein, da dürfte etwas mehr Arbeit anfallen.

krieg auch das example der library nicht zum laufen....

Hast Du NUM_LEDS, PIN und setChipset() angepasst?

Für diese Library müsstest Du wohl auch Deinen Hardware-Aufbau anpassen, und alle 6 Strips in Reihe schalten.

Für diese Library müsstest Du wohl auch Deinen Hardware-Aufbau anpassen, und alle 6 Strips in Reihe schalten.

achso ok na dann fällt das ganze eh aus....ist leider schon alles fest verbaut....

ich lad einfach nochmal das script hoch....vll fällt euch ja noch was auf

achso ok na dann fällt das ganze eh aus....ist leider schon alles fest verbaut....

Von dieser Klasse kannst Du nur eine Instanz brauchen (ist auch schon automatisch vorhanden), der Du einen Pin zuweist, über welchen das Signal geschickt wird. Wenn Du die Strips nicht mehr neu verdrahten kannst, dann fällt diese Möglichkeit wahrscheinlich dahin.

In Deinem Code ist aber noch reichlich Verbesserungspotenzial. In paint() z.B. rufst Du nacheinander calculatePartForStar() und dann calculatePxForStar() auf, die beide über den Strip-Array iterieren. Kombiniere die beiden Funktionen zu einer und Du wirst schon einen deutlichen Geschwindigkeitszuwachs haben.

int makeModulo(int number)
{
  int returnNumber;
  if(number >= 0)
  {
    returnNumber = number%totalLength;
  }
  else
  {
    //modulo für negative zahlen
    int absNumber = abs(number)%totalLength;
    returnNumber = (-absNumber+totalLength)%totalLength;
  }
  
  //Serial.println(returnNumber);
  return returnNumber;
}

dies lässt sich kürzer und schneller so schreiben:

number%totalLength;

Der Computer nimmt immer das Vorzeichen des Teiler für das Resultat, was Du mit Deiner komplizierten Berechnung auch machst.

Ein kurze Überlegung zur Geschwindigkeit, die erreicht werden kann: Du hast 128 LEDs mit 3 Farben = 3072 Bits, die bei jedem showStrip() herausgepulst werden müssen. Im besten Fall kannst Du sie mit ca. 300kHz ausgeben, was einer Update-Frequenz von ca. 100 Hz entspricht (unter optimalen Bedingungen). Dies erreichst Du höchstens, wenn Du sonst keine Berechnungen machen musst. Die Optimierung des restlichen Codes könnte sich also durchaus lohnen.

hallo,

also der erste tipp hat nciht wirklich merklich viel verbessert. aber war nen versuch wert...aber sind ja eh nur 6 schleifendurchläufe pro funktion
er rennt ja nicht alle pixel einzeln durch sondern nur die strips

der zweite tipp mit dem modulo funktioniert so leider nicht...deshalb hab ich mir ja diese funktion geschrieben
diese funktion soll sicherstellen, dass ich bei negativen zahlen trotzdem noch im kreislauf 0 bis totalLength bleibe
keine ahnung warum der normale modulo mir sowas nicht liefert....

Beispiel:

Normal: -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9

Mod 4 : 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1

und warum hast du überhaupt negative Zahlen ?

** **unsigned** **
löst viele Pseudo-Probleme, wenn die Daten logisch gesehen nur im Bereich {0, 1, ...} sind.
Und wenn dein Ergebnis modulo (0 .. len) sein soll, ist der Ausgangswert das eigentlich auch, oder kann zumindest so interprtiert werden, oder ?

weil ich zum beispiel bei cometRight den index runter zähle
beim runter zählen von 0 soll er dann auf das strip ende springen

aber ich glaube auch nicht, dass mir die makemodulo funktion derart viel performance raubt...
ich persönlich habe die vermutung, dass es die clearOtherLeds funktion ist, die bei jedem durchlauf im comet aufgerufen wird
clearOtherLeds durchläuft unter umständen einen menge leds...

aber ich glaube auch nicht, dass mir die makemodulo funktion derart viel performance raubt...

Ich auch nicht, aber mit vielen Optimierungen erreichst Du in der Summe auch etwas grösseres.

also der erste tipp hat nciht wirklich merklich viel verbessert. aber war nen versuch wert...aber sind ja eh nur 6 schleifendurchläufe pro funktion
er rennt ja nicht alle pixel einzeln durch sondern nur die strips

Ja, es sind schon nur 6 Durchläufe, aber Du rufst das bei jedem paint() auf und die paint()-Funktion ist wahrscheinlich die am häufigsten aufgerufene Funktion in Deinem Sketch. Somit ist das durchaus relevant. Poste mal die verbesserte Version.

Ich würde die clearOtherLeds()-Funktion komplett eliminieren und gleich clearAllLeds() aufrufen (natürlich vor dem Setzen der anderen Leds), bei dieser Funktion aber den Aufruf von showStrip() entfernen und nur an jenen Ort wieder einzufügen, wo es wirklich gebraucht wird.

hallo entschuldigt die lange pause...bin mit dem kram gerade ziemlich im stress

hier nun die verbesserte paint samt umrechnung auf die sternförmige verdrahtung:

void paint(int pixelPos, int r, int g, int b)
{
  calculatePxForStar(pixelPos);
  
  strips[aktPart].setPixelColor(aktPixel, r*brightness/100, g*brightness/100, b*brightness/100);
}
void calculatePxForStar(int pixel)
{
  int tempLength = 0;
  //int tempPixel = pixel%totalLength;
  int tempPixel = makeModulo(pixel);
  
  for(int i=0; i<HALO_SIZE; i++)
  {
    tempLength += ledLengthArray[i];
    
    if(tempLength >= tempPixel)
    {
      aktPart = i;
      aktPixel = tempPixel - (tempLength - ledLengthArray[i]) - 1;
      
      break;
    }
  }
}

den zweiten tipp von dir werde ich nächste woche mal probieren wenn es an die optimierung geht...gerade muss erstmal alles funktionieren....tut es aber zum glück auch schon fast :wink:

ich meld mich dann nochmal....da geht noch was ^^

es hat mir einfach keien ruhe gelassen.....

ich habe das weglassen der clearOtherLeds jetzt einmal versucht....hat einiges an speed gebracht....ich schätze mal 10-20% etwa....das is schonmal gut...vielen vielen dank schonmal...wenn noch weitere solcher dinge auffallen wär das echt genial....

Kannst Du Deinen ganzen Code nochmals posten? Ich verliere sonst den Überblick, welcher Code gerade aktuell ist.

jap wird gemacht.

clearOtherLeds() ist aber noch nicht überall draußen....bisher nur in leftCometSolo() und ricgtCometSolo()
den rest ziehe ich am montag nach