Go Down

Topic: Geschwindigkeit von Arduino erhöhen (Read 2 times) previous topic - next topic

iamable

Hallo ich habe von einem Kollegen ein Arduino board mit einem LED strip bekommen und programmiere dafür jetzt fleißig animationen.
Ich habe jedoch das Gefühl, dass die eigentlichen 20Mhz nicht genutzt werden, da die Animationen doch recht langsam ablaufen.

Gibt es eine Möglichkeit das board hoch zu takten?

das ganze ist ein arduino mega 2560.

Würde mich über ein paar Tipps echt freuen, da es so nciht besonders zufriedenstellend ist.

Viele Grüße

michael_x

Quote
da die Animationen doch recht langsam ablaufen

Da würde ich erstmal die delays verkleinern.

Es gibt Leute, die behaupten 200 Hz und 100 Hz unterscheiden zu können, aber für rasend schnelle Animationen brauchst du eher 20 Hz
Was das mit einer Arduino Frequenz von 20 MHz (oder auch 16 MHz) zu tun haben soll, weiss ich nicht.

Eine handvoll LED's kannst du immer so schnell ansteuern bis du keine Bewegung mehr siehst.

Liest du dein Animations-Programm von einer SD Karte ?

volvodani

Ich denke eher das es wohl irgdenwo im Programm zu suchen ist. Wie steuerst du denn den Stripe an?
Hast du Programm zum reinhängen hier.
So ist das Leben:
Manchmal bis du das Denkmal, manchmal die Taube!

Tilo233

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}                                                                           

iamable

#4
Sep 05, 2012, 02:30 pm Last Edit: Sep 05, 2012, 02:40 pm by iamable Reason: 1
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:

Code: [Select]
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:

Code: [Select]
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:

Code: [Select]
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:

Code: [Select]
#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:

Code: [Select]
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....

michael_x

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.

volvodani

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
So ist das Leben:
Manchmal bis du das Denkmal, manchmal die Taube!

iamable

@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?

Code: [Select]
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

pylon

Hast Du diese Library mal versucht? http://code.google.com/p/fastspi/

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


Udo Klein

Code: [Select]

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.
Check out my experiments http://blog.blinkenlight.net

iamable

#10
Sep 06, 2012, 10:10 am Last Edit: Sep 06, 2012, 10:34 am by iamable Reason: 1
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

pylon

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


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

Quote
reicht schon ein tauschen der includes aus?


Nein, da dürfte etwas mehr Arbeit anfallen.

Quote
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.

iamable

#12
Sep 06, 2012, 03:45 pm Last Edit: Sep 14, 2012, 04:24 pm by iamable Reason: 1
Quote
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


pylon

Quote
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.

Code: [Select]
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:

Code: [Select]
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.

iamable

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

Go Up