FastLED Library- warum Teensy 3.1?

Hallo,

viele FastLED-Projekte verwenden den Teensy 3.1. Warum wird dieser in diesem Zusammenhang gerne verwendet?

Gruß Chris

Weil die ARM Prozessoren viel leistungsfähiger sind. Schneller und vor allem mehr RAM. Und die Teensy Boards sind für diese Leistung recht billig.

Weil pro LED 3 byte Bildspeicher notwendig sind. Bei einem Genuino UNO sind darum bei 2kByte theoretisch nur 680 WS2812 möglich; praktisch sind es viele weniger weil es ja RAM auch für andere Dinge gebraucht werden.

Grüße Uwe

Wie sieht es denn mit Teensy aus im Hinblick auf Mac-Kompatibilität?

Gruß Chris

Chris72622: Wie sieht es denn mit Teensy aus im Hinblick auf Mac-Kombatibilität?

Oh, oh, oh... Ganz schlecht!! MacOS wirst du da drauf nie zum laufen bekommen! ;-)

Andersrum weiß ich nicht. Ich habe nur einen unausgepackten Teensy aber keinen MAC.

Grüße Uwe

Liegt der bei Dir nur rum und vergammelt? :D

Gruß Chris

uwe, so einen hab' ich auch....

Bei mir steht nach dem Kompilieren eines Sketches, welcher ca. 150 LEDs ansteuern soll Folgendes:

Der Sketch verwendet 6.598 Bytes (20%) des Programmspeicherplatzes. Das Maximum sind 32.256 Bytes.
Globale Variablen verwenden 1.396 Bytes (68%) des dynamischen Speichers, 652 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.

Es sollen verschiedenste “Pattern” aufgerufen, parallel berechnet und ineinander gefadet werden können. Momentan habe ich lediglich entsprechende Arrays hierfür angelegt. Ich verwende einen Arduino Pro mini.

Ist aus Eurer Sicht, aufgrund dieser Umstände, für mich der Zeitpunkt gekommen die Plattform (hin zu einem Teensy) zu wechseln?

Gruß Chris

Hier noch der Code:

#include "Bounce2.h"
#include "FastLED.h"

#define DATA_PIN 3      // Manuelle Eingabe!
#define CLOCK_PIN 13    // Manuelle Eingabe!
#define ALL_LEDS 150    // Manuelle Eingabe!
#define NUM_LEDS 150    // Manuelle Eingabe!
#define BRIGHTNESS  64  // Manuelle Eingabe!

// Debugging

#define DEBUG Serial // Debugging

#ifdef DEBUG
#define debug(...) DEBUG.print(__VA_ARGS__)
#define debugln(...) DEBUG.println(__VA_ARGS__)
#define debugbegin(...) DEBUG.begin(__VA_ARGS__)
#else
#define debug(...)
#define debugln(...)
#define debugbegin(...)
#endif

// _Entprellung

#define INPUTMODE INPUT_PULLUP            // INPUT oder INPUT_PULLUP
const byte butPin[] = {                   // Pin-Nummern der angeschlossenen Buttons
  5, 6
};
#define NUMBUTTONS sizeof(butPin)         // Die Anzahl der Tasten durch die Anzahl der Bytes des Arrays butPin ermitteln (wird automatisch definiert)
Bounce debouncer[NUMBUTTONS];             // Mehrere Bounce-Instanzen erstellen

enum {
  NOACTION,
  BUT1PUSH, BUT2PUSH
};

byte buttonAction = BUT1PUSH;             // Gibt an, für welche Einzeltaste eine Aktion ausgelöst wird.

//  PIR-Sensor

const byte pir[] = {2, 3};  // PIR-Sensoren über Pulldown_Widerstand an Pin 2 und 3
const byte pirLed[] = {12, 13};   // PIR LEDs an Pin 12 und 13

// Modes

boolean mode = 0;  // BGD (0) oder Layer (1)

enum {
  BGD,
  LAYER
};

byte bgdPattern = 0;   // 0 = schwarz, 1 = Halloween, 2 = Sylvester, 3 = Partymode
byte layerPattern = 0; // 0 = weiß,    1 = rot,       2 = grün,      3 = blau

// LED-Arrays

CRGB allLeds[ALL_LEDS] = {};
const byte ledOrder[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149};
CRGB realLeds[NUM_LEDS]; // Gemappte RGB-LED Daten

void setup()
{
  delay(500);
  debugbegin(9600);
  for (int i = 0; i < NUMBUTTONS; i++)  // Buttons
  {
    pinMode(butPin[i], INPUTMODE);
    debouncer[i].attach(butPin[i]);
    debouncer[i].interval(10);
  }
  for (byte i = 0; i < 2; i++) // PIR-Sensoren
  {
    pinMode(i, INPUT);
  }
  FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN, BGR>(realLeds, NUM_LEDS);
  set_max_power_in_volts_and_milliamps(5, 12000);
  FastLED.setCorrection(TypicalSMD5050);
  FastLED.setTemperature(WarmFluorescent);
  FastLED.setBrightness(BRIGHTNESS);
  FastLED.clear();  // Alle LEDs ausschalten
  FastLED.show(); // Sämtliche Pixel beschalten
  debugln("System bereit");
}

void loop()
{
  eingabe();        // Taster und Sensoren auswerten
  verarbeitung();   // Farbberechnungen
  ausgabe();        // Verteilung und Ausgabe der Pixel
}

void eingabe()
{
  bounce();   // Tastenentprellung  // ok
  // pirCheck(); // PIR-Sensoren auswerten
}

void bounce()
{
  buttonAction = NOACTION;
  for (byte i = 0; i < NUMBUTTONS; i++)
  {
    debouncer[i].update();   // Status prüfen
    if (debouncer[i].fell()) // Wenn die Taste gedrückt wird
    {
      debug("Button Pin ");
      debugln(butPin[i]);
      buttonAction = i + 1; // Löst buttonAction aus und übergibt diese an den Sketch
    }
  }
}

void pirCheck()
{
  static boolean oldPirState[sizeof(pir)];  // Zuletzt ermittelter Zustand
  static boolean newPirState[sizeof(pir)];  // Aktuell ermittelter Zustand

  for (byte i = 0; i < sizeof(pir); i++)
  {
    newPirState[i] = digitalRead(pir[i]);

    if (newPirState[i] != oldPirState[i])         // Wenn PIR_Zustandswechsel..
    {
      if (newPirState[i])                         // PIR_Zustandswechsel auf 3.3V
      {
        debug("PIR an Pin ");
        debug(pir[i]);
        debugln(" hat Bewegung registriert");
        digitalWrite(pirLed[i], newPirState[i]);  // LED einschalten
      }
      if (!newPirState[i])                        // PIR_Zustandswechsel auf 0V
      {
        digitalWrite(pirLed[i], newPirState[i]);  // LED ausschalten
      }
      oldPirState[i] = newPirState[i];
    }
  }
}

void verarbeitung()
{
  bgdSwitch();  // Wechselt BGD-Pattern
  bgdRun();     // Erzeugt Werte für animierte Pattern
}

void bgdSwitch()
{
  if (buttonAction == BUT1PUSH) // BGD-Taste
  {
    switch (bgdPattern)
    {
      case 0: // schwarz
        for (int i = 0; i < ALL_LEDS; i++)
        {
          allLeds[i] = CRGB(0, 0, 0);
        }
        break;
      case 1: // Halloween
        for (int i = 0; i < ALL_LEDS; i++)
        {
          allLeds[i] = CRGB(255, 0, 0);
        }
        break;
      case 2: // Sylvester
        for (int i = 0; i < ALL_LEDS; i++)
        {
          allLeds[i] = CRGB(0, 255, 0);
        }
        break;
      case 3: // Partymode
        for (int i = 0; i < ALL_LEDS; i++)
        {
          allLeds[i] = CRGB(0, 0, 255);
        }
        break;
    }
  }
}

void bgdRun() // Erzeugt Werte für animierte Pattern
{
  switch (bgdPattern)
  {
    case 0: // schwarz
      break;
    case 1: // Halloween
      break;
    case 2: // Sylvester
      break;
    case 3: // Partymode
      break;
  }
}

void ausgabe()
{
  ledMapping();   // Pixelmapping
  FastLED.show(); // Sämtliche Pixel beschalten
}

void ledMapping() // Pixelmapping
{
  for (byte k = 0; k < NUM_LEDS; k++)
  {
    realLeds[k] = allLeds[ledOrder[k]];
  }
}

Chris72622: Liegt der bei Dir nur rum und vergammelt? :D

Gruß Chris

Ist für eine 22x18 Matrix vorgesehen. Da fehlt mir noch eine Aluplatte zum montieren der LED und Wärmeabgabe.

Chris72622: Ist aus Eurer Sicht, aufgrund dieser Umstände, für mich der Zeitpunkt gekommen die Plattform (hin zu einem Teensy) zu wechseln?

ja.

Grüße Uwe

Zwei Aspekte, die mir dazu einfallen:

  1. Wenn Du APA102C zusammen mit FastLED und teensy 3.2 einsetzt, wird der 96 MHz teensy "gebremst" auf 48 MHz, wenn ich die Bibliothek richtig interpretiere (das muß nicht so sein). Ich verstehe das so, daß Du mit einem teensy 3.2 die APA102C hinsichtlich Geschwindigkeit der Ansteuerung voll ausnutzt. Man kann also mal probieren, was geht.

  2. Wenn Du so effektiv wie beispielsweise Mark Kriegsman die Möglichkeiten von FastLED einsetzen kannst, dann paßt auch ein eindrucksvolles Programm wie TwinkleFOX auf einen ProMini mit 150 Lichtpunkten dran, das sehe ich jetzt seit Weihnachten. Mark schreibt: "On a basic Arduino Uno or Leonardo, this code can twinkle 300+ pixels smoothly at over 50 updates per seond." Als Anfänger kann ich nicht so effektiv programmieren, muß erst ein paar Fehler- und Lernschleifen durchlaufen. Dann ist es blöd, mit einem Speicherlimit im Nacken arbeiten zu müssen.

Solltest Du letztendlich feststellen, Dein Programm quetscht sich doch noch auf einen Arduino, dann hast Du mit einem teensy aber nach meiner Einschätzung immer noch ein gut konzeptioniertes Board für weitere Ambitionen.

Mit einem teensy auf dem Steckbrett freue ich mich natürlich über andere nette Menschen, die ich mal um einen Rat fragen könnte :)

Hab schon bestellt und mich auch schon ein wenig eingelesen.

Ich freue mich schon darauf, nicht mehr begrenzt zu sein. :)

Gruß Chris

  1. Wenn Du APA102C zusammen mit FastLED und teensy 3.2 einsetzt, wird der 96 MHz teensy "gebremst" auf 48 MHz, wenn ich die Bibliothek richtig interpretiere (das muß nicht so sein).

Wie kommst Du darauf bzw. welchen Sinn sollte das haben?

Wie sieht es denn mit Teensy aus im Hinblick auf Mac-Kompatibilität?

Funktioniert.

Als Anfänger kann ich nicht so effektiv programmieren, muß erst ein paar Fehler- und Lernschleifen durchlaufen. Dann ist es blöd, mit einem Speicherlimit im Nacken arbeiten zu müssen.

Jein. Auf Arduino ist man motiviert, effizient und besser zu programmieren, ein Teensy verführt zum Rumschlampen mit Ressourcen...

Gruß,

Helmuth

Helmuth: Wie kommst Du darauf bzw. welchen Sinn sollte das haben?

Diesen Teil von fastspi.h habe ich so interpretiert:

#if defined(FASTLED_TEENSY3) && (F_CPU > 48000000)
#define DATA_RATE_MHZ(X) (((48000000L / 1000000L) / X))
#define DATA_RATE_KHZ(X) (((48000000L / 1000L) / X))
#else
#define DATA_RATE_MHZ(X) ((F_CPU / 1000000L) / X)
#define DATA_RATE_KHZ(X) ((F_CPU / 1000L) / X)
#endif

Ich verstehe das als Bremse, weil die APA102C sonst nicht hinterherkommen. Falsch verstanden?

Helmuth: Jein. Auf Arduino ist man motiviert, effizient und besser zu programmieren, ein Teensy verführt zum Rumschlampen mit Ressourcen...

Drei Phasen der Entwicklung (als Hobbyprogrammierer!):

  • Schnell mal runtergeschrieben
  • Jetzt will ich, daß es funktioniert!
  • Optimierung

Da kann ein speicherfressendes Hilfsfeld schon mal ganz nützlich sein, blöd, wenn kein Platz da ist. Außerdem hat mich der teensy wegen der 32 Bit interessiert. Die weitgehende Toleranz gegenüber 5V kommt meiner Dusseligkeit entgegen. :)

Chris72622: Ich freue mich schon darauf, nicht mehr begrenzt zu sein. :)

Die Begrenztheit im Kopf ist schwieriger zu beseitigen als die der Hardware, darum mein Spruch: "Wenn ich schon nicht weiß, wie es geht, muß es zumindest mein Werkzeug wissen!" :)

Da wird zwischen dem Teensy 3.0 und 3.1 unterschieden: https://www.pjrc.com/teensy/

So dass es egal ist aber der Prozessor mit 48 oder 72MHz läuft. Oder in anderen Worten. Der Takt wird so gesetzt, als ob der Prozessor maximal 48MHz hätte.

Den CPU Takt kann man so generell nicht ändern. Wie soll das gehen? Da wird nur die Datenrate der LEDs in Abhängigkeit von der CPU Frequenz gesetzt.

Es geht lediglich darum, die SPI Bus-Geschwindigkeit zu drosseln! Das hat nichts mit dem F_CPU Takt zu tun. Auf einem Atmega ist die SPI Geschwindigkeit maximal F_CPU/2. Somit beim zb Uno bei 8MHz.

ARM Prozessoren sind deutlich schneller. Die APA kann man aber dann auch nicht mehr mit F_CPU/2 ansteuern. Eine genaue Grenze gibt es laut DB der APAs nicht. Mit 8MHz kann man die APAs noch stabil betreiben, höher selber nicht getestet. Das entspricht ~10x schneller als alle WS2812b Leds.

Bin aber auch der Meinung, ein Teensy hier einzusetzen ist falsch, nur weil man so schlechteren Code schreiben kann. Das ganze sollte durchaus auf einem 328p machbar sein! Man lernt wenig, optimierte Algorithmen anzuwenden. Was Stefan (Helmuth) mit seinen Strips macht, ist schon einige Stufen höher und sicherlich deutlich aufwendig, da kommt ihm der höhere Datendurchsatz sicher zu gute.

So dass es egal ist aber der Prozessor mit 48 oder 72MHz läuft. Oder in anderen Worten. Der Takt wird so gesetzt, als ob der Prozessor maximal 48MHz hätte.

2 Anmerkungen: Die Geschwindigkeit des Prozessors wird in der IDE festgelegt. Normalerweise nimmt man (den “Übertakt” von) 96 MHz. Gab noch nie Probleme und der Prozessor bleibt handwarm.

Die SPI Geschwindigkeit ist unabhängig davon einstellbar. Der zitierte Codeauschnitt zeigt die “Preset-Einstellung”, welche genommen wird, wenn nicht anderweitig spezifiziert.

Man kann das auch selbst einstellen, hier z.B. auf 12 MHz :

void setup() { 
        FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN, RGB, DATA_RATE_MHZ(12)>(leds, NUM_LEDS);
}

Ich habe wenige APAs mit superkurzen Kabeln testweise schon erfolgreich mit 20 MHz betrieben, Daniel schrieb mal was von 24 MHz.

Bei längeren LED Ketten (>50 LEDs) hat sich 8 MHz als robuster Standardwert, der garantiert immer geht, gezeigt.

Bei allem, was schneller wird, muss man experimentieren, bis es zuverlässig funktioniert. Stichwort Impendanzanpassung des Kabels (Reihenwiderstand), verdrillte Adern, geschirmtes Kabel, usw. Bei der Qualität der Strips gibt es auch Unterschiede - aber das merkt man erst nach dem Kauf.

Beste Grüße,

Helmuth

Wenn ich mich dann mal selbst zitieren darf:

agmue: 1. Wenn Du APA102C zusammen mit FastLED und teensy 3.2 einsetzt, wird der 96 MHz teensy "gebremst" auf 48 MHz, wenn ich die Bibliothek richtig interpretiere (das muß nicht so sein). Ich verstehe das so, daß Du mit einem teensy 3.2 die APA102C hinsichtlich Geschwindigkeit der Ansteuerung voll ausnutzt. Man kann also mal probieren, was geht.

Das präzisiere ich dann auf "Die Datenrate des teensy kann gegenüber den angeschlossenen LEDs reduziert werden." Was den Umkehrschluß "Man kann also mal probieren, was geht." bestätigt. Chris, das hatte ich gemeint, schließlich ist unser Forscherdrang doch eine unserer Triebfedern!

Danke allen für die Präzisierungen!

Dann habe ich den Satz

wird der 96 MHz teensy "gebremst" auf 48 MHz

missverstanden, da so bei mir der Eindruck entstand, dass Du sagst, der Teensy selbst würde "gebremst" - was unzutreffend ist. ;)

Das präzisiere ich dann auf "Die Datenrate des teensy kann gegenüber den angeschlossenen LEDs reduziert werden."

Ja. Ich präzisiere: Die SPI Geschwindigkeit wird eingestellt.

Was den Umkehrschluß "Man kann also mal probieren, was geht." bestätigt.

Volle Zustimmung!

Gruß,

Helmuth

Helmuth:
… da so bei mir der Eindruck entstand, dass Du sagst, der Teensy selbst würde “gebremst” - was unzutreffend ist. :wink:

Ich gestehe, das bewußt schwammig formuliert zu haben, da ich mir nicht sicher war und für mich die Schlußfolgerung im Vordergrund stand. Insgeheim hatte ich auf eine Präzisierung gehofft :wink:

Helmuth:
Ja. Ich präzisiere: Die SPI Geschwindigkeit wird eingestellt.

Ich hoffe Chris ist einverstanden, wenn ich dazu noch eine Frage stelle: Muß man in diesem Zusammenhang noch zwischen Soft- und Hard-SPI unterscheiden?

Ich zitiere aus FirstLight.ino:

// Use if you want to force the software SPI subsystem to be used for some reason (generally, you don't)
// #define FASTLED_FORCE_SOFTWARE_SPI 
// Data pin that led data will be written out over
#define DATA_PIN 3

// Clock pin only needed for SPI based chipsets when not using hardware SPI
//#define CLOCK_PIN 8 
...
      // FastLED.addLeds<APA102, RGB>(leds, NUM_LEDS); 
      // FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);

Hard-SPI verorte ich beim UNO bei Pin 13 und 11, wozu brauche ich dann Pin3 und 8? Und wenn die SPI-Datenrate reduziert wird, gilt das dann für Soft- und Hard-SPI gleichermaßen?

Es funktioniert prima bei mir auf ProMini, Nano und Teensy, verstanden habe ich es aber leider noch nicht so richtig.