Guten Morgen,
ich möchte LED-Strips und einen Fernbedienungsempfänger gleichzeitig an
einem AVR-Controller betreiben. Das Rausschreiben der Daten an die
LED-Strips ist zeitkritisch und muss deshalb unter Interrupt-Sperre
passieren. Je länger der Strip, desto länger die Sperre. Wenn man jetzt
einen flüssigen Helligkeitsübergang möchte (Update alle 20ms) und 300
LEDs hat, ist man schon einen beträchtlichen Anteil der Rechenzeit in
Interrupt-Sperre unterwegs. Das beeinträchtigt natürlich die Auswertung
einer IR-Fernbedienung, die ja auch auf Interrupts und Zeitmessung
basiert. Kennt jemand dieses Problem und eine elegante Lösung dafür ?
Mein bisheriger Ansatz: Die IR-Auswertung erkennt immer noch dass etwas
gesendet wurde. Nur nicht mehr was das genau war. Daraufhin würde ich
die Ausgabe der LED-Strips verzögern bis ich einen gültigen Befehl von
der Fernbedienung empfange (Fernbedienung wiederholt alle ca. 100ms
solange eine Taste gedrückt ist) oder ein Timeout abgelaufen ist.
Aktuelles Problem ist, dass die Interruptsperre meist mitten in einer
IR-Message vorbei ist und die Auswertung dann nicht das erste Byte als
erstes sieht und mit der Bytezählung durcheinander kommt. Die
Synchronisation findet sie dann auch nicht mehr, bis die Taste
losgelassen wurde. Dann müsste man also immer 2x drücken und den
LED-Strip entsprechend lange pausieren. Das ist nicht mehr komfortabel.
Ich müsste also die IR-Auswertung entsprechend anpassen, dass sie bei
der Byte-Zählung flexibler ist.
Bevor ich mir die Arbeit mache wie gesagt: Kennt jemand eine einfachere
Lösung ? Vielen Dank im Voraus !
Sven G. schrieb:> Kennt jemand eine einfachere Lösung ?
Multitasking, Multicore/Mulutiprozessor ...
Verrate bloß keine Detais zum Timing der LED Ansteuerung und des
IR-Signals.
Sven G. schrieb:> Anteil der Rechenzeit in> Interrupt-Sperre unterwegs.
Dann lass den Interrupt nicht sperren ... Wenn du deiner ISR-Funktion
als zweiten Parameter ISR_NOBLOCK mitgibst, ist der erste Befehl in
deiner ISR ein "sei", der die Interrupts wieder aktiviert.
Du musst nur auf deinen Stack aufpassen, dass der nicht überläuft, soll
heißen, die ISRs dürfen nicht zu lange brauchen.
Ich vermute, du verwendest IRMP?
Dann richte dir einen Timer-Interrupt mit sowas 15kHz ein, in dem die
IRMP-Interrupt-Funktion aufgerufen wird.
Der Rest mit den RGB-LEDs dürfte dann per Timer in einer anderen
Interrupt-Funktion passieren.
So hatte ich es gemacht und bei mir gab es dann keine Probleme :)
Hallo Mampf,
vielen Dank für die Antwort. Ich habe es noch nicht ganz verstanden. Ich
weiß auch nicht, ob ich mich klar ausgedrückt habe:
Die LED-Strip-Ausgabe verwendet selbst keine ISR, sie sperrt nur die
Interrupts, weil sie aufgrund der Timing-Anforderung nicht unterbrochen
werden darf. Ich habe schon ausprobiert die Interruptsperre einfach
wegzulassen, dann zeigt der LED-Strip aber Blödsinn an. Geht also nicht.
IRMP verwende ich nicht. Ich verwende eine sehr kleine Library, die aus
einem Lernroboter-Projekt stammt (Ringo Robot). Die benutzt
Timer/Counter1 zur Zeitmessung. Da ich sehr viele LEDs ansteuern möchte
brauche ich einen großen Teil des RAMs für das Muster. Daher möchte ich
mit Code so sparsam wie möglich sein.
Hallo Wolfgang,
vielen Dank. ;-)
Gruß
Sven
Sven G. schrieb:> Die LED-Strip-Ausgabe verwendet selbst keine ISR, sie sperrt nur die> Interrupts, weil sie aufgrund der Timing-Anforderung nicht unterbrochen> werden darf. Ich habe schon ausprobiert die Interruptsperre einfach> wegzulassen, dann zeigt der LED-Strip aber Blödsinn an. Geht also nicht.
Hmm, in diesem Fall wäre es sinnvoll den Code zu posten, da es einige
Möglichkeiten gibt, wie du das implementiert haben könntest.
Die Alternative ist, wir ziehen dir das Stück für Stück aus der Nase ;-)
Glaub, Code posten ist einfacher.
Manche Leute verstehe ich nicht: Reißen hier den große Thread auf mit
der Feststellung, dass es nicht anders geht, so aber nicht funktioniert
und dann kommen keine Fakten (Programm, Typenbezeichnungen,
IR-Protokoll), damit sich ja kein anderer ein Bild oder gar konkrete
Vorschläge zur Lösung machen kann.
Ich erwarte nicht, dass sich jemand ein Bein für mich ausreißt. Ich habe
lediglich gefragt, ob jemand schon mal ein LED-Strip+AVR+IR-Empfänger
betrieben und damit Erfahrung hat. Ganz einfach. Von dir, Wolfgang,
erwarte ich gar nichts, soviel Erfahrung habe ich mit diesem Forum.
Ich verwende Adafruit NeoPixel RGBW-LEDs mit 800kHz Datentakt. Das
Protokoll ist ein 1-Drahl-Protokoll ähnlich dem im Datenblatt zu WS2812,
WS2811 oder SK6812 beschrieben. Nur mit 32Bit statt 24Bit pro Modul.
Der Code, der die Daten rausschickt sieht so aus...
https://github.com/adafruit/Adafruit_NeoPixel/blob/master/Adafruit_NeoPixel.cpp
Das IR-Protokoll weiß ich gerade nicht und kann ich auch vor Übermorgen
nicht in Erfahrung bringen. Die sind doch aber alle ähnlich und werden
alle das gleiche Problem haben, dass man zeitliche Abstände zwischen
Signalflanken bestimmen muss und daher der Interrupt nicht längere Zeit
gesperrt sein darf.
Bevor jemand für Wolfgang nochmal antwortet probiere ich es lieber
selbst nochmal. Vielen Dank schon mal an die anderen für die
konstruktiven Hinweise.
Gruß
Sven
Sowohl IRMP als auch die WS2812- bzw. SK6812-LED-Ansteuerung im
RGBW-Mode (nichts anderes sind Deine "Neopixel") laufen hervorragend
zusammen auf z.B. einem STM32F103. Siehe auch WordClock mit WS2812,
wo beides zusammen eingesetzt wird - neben vielem mehr.
Dabei werden die LEDs per DMA beschickt und der STM32 langweilt sich zu
Tode.
Sven G. schrieb:> Bevor jemand für Wolfgang nochmal antwortet ...
Ich frage mich ernsthaft, warum solche Infos nicht im ersten Posting
auftauchen, sondern erst einmal sechs Postings mit Rätselraten und
Nebelstochern kommen müssen ...
Sven G. schrieb:> Ich verwende Adafruit NeoPixel RGBW-LEDs mit 800kHz Datentakt. Das> Protokoll ist ein 1-Drahl-Protokoll ähnlich dem im Datenblatt zu WS2812,> WS2811 oder SK6812 beschrieben. Nur mit 32Bit statt 24Bit pro Modul.> Der Code, der die Daten rausschickt sieht so aus...> https://github.com/adafruit/Adafruit_NeoPixel/blob/master/Adafruit_NeoPixel.cpp
Ach du schei*e ... Ich hab mir gerade das Protokoll angeschaut ... Das
ist ein asynchrones Protokoll mit harten Echtzeitanforderungen (Timing
+/-150ns) ...
Und der Code dazu ... Völliger Wahnsinn.
Ich würde sagen IR und LEDs beschreiben gleichzeitig kannst du vergessen
... *edit*: Gerade gesehen, bei einem Low-Pegel von 80µs machen die LEDs
einen Reset.
Wer hat sich denn den kranken Mist ausgedacht ?
Frank M. schrieb:> Dabei werden die LEDs per DMA beschickt und der STM32 langweilt sich zu> Tode.
Ja, das ist auch die einzige Lösung, die mir einfällt.
Ich würde bei zeitkritischen Sachen einen APA102 LED Strip verwenden.
Der versteht SPI und das auch noch deutlich fixer als ein WS2812.
Zumal SPI Übertragung vom AVR von der Hardware aus unterstützt wird...
Mampf F. schrieb:> Frank M. schrieb:>> Dabei werden die LEDs per DMA beschickt und der STM32 langweilt sich zu>> Tode.>> Ja, das ist auch die einzige Lösung, die mir einfällt.
Wenn man noch berücksichtigt, dass man die STM32F103 bei eBay als
kleines aber feines Board für unter 2 EUR bekommt - mit 64 KB Flash und
20 KB RAM, dann will man keinen AVR mehr anpacken, jedenfalls nicht für
so eine Aufgabe.
https://www.ebay.de/itm/1-2-5-10Stks-STM32F103C8T6-ARM-STM32-Minimum-System-Development-Board-Module-New/272425764978
EDIT:
Der TO könnte noch APA102-LEDs verwenden. Die werden über SPI gesteuert
und man kann selbst das Übertragungstempo bestimmen. Man wird jedenfalls
bzgl. Timing nicht fremdbestimmt. Aber ob es die auch in RGBW statt
lediglich RGB gibt, weiß ich nicht.
Mampf F. schrieb:> *edit*: Gerade gesehen, bei einem Low-Pegel von 80µs machen die LEDs> einen Reset.
Die machen keinen Reset, sondern stellen nach 80µs Ruhe den Ihnen
zugewiesenen RGB(W)-Wert dar, damit dann alle LEDs gleichzeitig die
übertragenen Werte darstellen. Die Länge des Ruhepegels ist übrigens
verschieden und kann von 50µs bis 120µs variieren - je nach Ausführung.
@ Sven G. (captainalbern)
>ich möchte LED-Strips und einen Fernbedienungsempfänger gleichzeitig an>einem AVR-Controller betreiben.
Machbar.
> Das Rausschreiben der Daten an die>LED-Strips ist zeitkritisch und muss deshalb unter Interrupt-Sperre>passieren.
Kann sein, muß nicht, man kann es ggf. auch clever mit SPI machen.
> Je länger der Strip, desto länger die Sperre.
Nö. Man kann auch zwischen den einzelnen Bytes mal KURZ was anderes
machen.
>Wenn man jetzt>einen flüssigen Helligkeitsübergang möchte (Update alle 20ms) und 300>LEDs hat, ist man schon einen beträchtlichen Anteil der Rechenzeit in>Interrupt-Sperre unterwegs.
Nö, du bist in einer konzeptionellen Sackgasse.
> Das beeinträchtigt natürlich die Auswertung>einer IR-Fernbedienung, die ja auch auf Interrupts und Zeitmessung>basiert.
Das kann man ggf. clever verschachteln, was so oder so der Grundgedanke
von kooperativem Multitasking ist.
>Mein bisheriger Ansatz: Die IR-Auswertung erkennt immer noch dass etwas>gesendet wurde. Nur nicht mehr was das genau war. Daraufhin würde ich>die Ausgabe der LED-Strips verzögern bis ich einen gültigen Befehl von>der Fernbedienung empfange (Fernbedienung wiederholt alle ca. 100ms>solange eine Taste gedrückt ist) oder ein Timeout abgelaufen ist.
Ziemlicher Murks. IR-Dekodierung ist doch eher langsam, so im Bereich
von 1kBit/s. Das kann man relativ einfach mit der LED-Ansteuerung muxen.
>LED-Strip entsprechend lange pausieren. Das ist nicht mehr komfortabel.
In der Tat.
>Ich müsste also die IR-Auswertung entsprechend anpassen, dass sie bei>der Byte-Zählung flexibler ist.
Scheint so.
>Bevor ich mir die Arbeit mache wie gesagt: Kennt jemand eine einfachere>Lösung ? Vielen Dank im Voraus !
Kauf dir was fertiges bei Conrad, Pollin oder Perl. ;-)
Wenn du aber kein Konsumerweichei bist, klemmst du dich dahinter und
löst das Problem ELEGANT!
Und JA, das geht auch mit einem "kleinen" AVR nicht allzuschwer. Fette
32 Bitter mit DMA und anderen Geschützen braucht man da nicht wirklich.
Brain 2.0 ist immer noch up to date!
@Sven G. (captainalbern)
>wegzulassen, dann zeigt der LED-Strip aber Blödsinn an. Geht also nicht.
SO einfach geht es nicht. Aber es geht. Siehe mein vorheriger Beitrag.
>IRMP verwende ich nicht. Ich verwende eine sehr kleine Library, die aus>einem Lernroboter-Projekt stammt (Ringo Robot). Die benutzt>Timer/Counter1 zur Zeitmessung.
Auch das kann man anpassen.
>Da ich sehr viele LEDs ansteuern möchte>brauche ich einen großen Teil des RAMs für das Muster. Daher möchte ich>mit Code so sparsam wie möglich sein.
Jaja, spare jederzeit, dann hast du immer Not. Mein Gott, hat der
Bastler von heute nicht mal drei Euro für einen ausreichend großen uC
mit ausreichend RAM?
Mampf F. schrieb:> Ach du schei*e ... Ich hab mir gerade das Protokoll angeschaut ... Das> ist ein asynchrones Protokoll mit harten Echtzeitanforderungen (Timing> +/-150ns) ...
2 Bit der LED-Daten dauern 2.4µs (8 Bit á 0.3µs), d.h. wenn man die als
8Bit mit SPI bei 3.33MHz Clk raustackert, hat man zum Bereitlegen der
Daten, Gucken nach dem IR-Empfängerpin und Warten auf fertige
SPI-Übertragung 2,4µs Zeit. Nicht die Welt, aber mit Assembler bei einem
µC, der nicht gerade mit 1MHz dahinschleicht, sind das schon ein paar
Takte.
Die IR-Auswertung muss dann nach dem LED-Telegramm erfolgen.
@ Mampf F. (mampf)
>Ach du schei*e ... Ich hab mir gerade das Protokoll angeschaut ... Das>ist ein asynchrones Protokoll mit harten Echtzeitanforderungen (Timing>+/-150ns) ...
So what!
>Und der Code dazu ... Völliger Wahnsinn.
Keine Ahung.
>Ich würde sagen IR und LEDs beschreiben gleichzeitig kannst du vergessen>... *edit*: Gerade gesehen, bei einem Low-Pegel von 80µs machen die LEDs>einen Reset.
Ja und? Dann lass halt nen High-Pegel stehen.
>> Dabei werden die LEDs per DMA beschickt und der STM32 langweilt sich zu>> Tode.>Ja, das ist auch die einzige Lösung, die mir einfällt.
Es gibt so gut wie IMMER mehrere Lösungen, ganz egal wie gut oder
schlecht die auch sein mögen.
Falk B. schrieb:>> Das Rausschreiben der Daten an die>>LED-Strips ist zeitkritisch und muss deshalb unter Interrupt-Sperre>>passieren.>> Kann sein, muß nicht, man kann es ggf. auch clever mit SPI machen.
Hatte ich vorher mal durchgerechnet ... SPI müsste auf 20MHz laufen und
um die Toleranz von +/-150ns einzuhalten, hätte man 3 Taktzyklen Zeit
eine neue SPI-Übertragung zu starten - bei einem AVR mit 20MHz.
DMA hat der AVR ja leider nicht.
Falk B. schrieb:>>Ich würde sagen IR und LEDs beschreiben gleichzeitig kannst du vergessen>>... *edit*: Gerade gesehen, bei einem Low-Pegel von 80µs machen die LEDs>>einen Reset.>> Ja und? Dann lass halt nen High-Pegel stehen.
Lies bitte das Datenblatt, damit du weißt, was dann passiert ;-)
Falk B. schrieb:>>Ja, das ist auch die einzige Lösung, die mir einfällt.>> Es gibt so gut wie IMMER mehrere Lösungen, ganz egal wie gut oder> schlecht die auch sein mögen.
Wenn dir andere Lösungen einfallen, immer her damit - der TE wäre
sicherlich hoch erfreut.
Wolfgang schrieb:> 2 Bit der LED-Daten dauern 2.4µs (8 Bit á 0.3µs)
Wie kommst du darauf?
Hatte für Low- und High-Data 0,3µs und 0,95µs gelesen ... Die Daten
werden wohl in der Länge der High-Low-Pegel kodiert und anscheinend auch
noch abwechseln mal High mal Low ... Der kleinste gemeinsame Teiler
wären 0,05µs und der Clock damit 20MHz.
Kann sein, dass ich mir irre, aber so hatte ich es im Datenblatt
verstanden.
Mampf F. schrieb:> Kann sein, dass ich mir irre, aber so hatte ich es im Datenblatt> verstanden.
Nein, du irrst nicht. Und die anderen beiden sollten die Dinger erstmal
selbst programmieren.
Falk B. schrieb:> Keine Ahung.
Ich denke mal, da fehlt ein 'n' in der Mitte. Leider ist das die einzige
richtige Aussage in deinen Beiträgen. Wenn ich deine sonstigen Beiträge
auch durchaus zu schätzen weiß, aber bei den Neopixel-Leds liegt du
nicht zum ersten Mal völlig daneben.
@Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
>Nein, du irrst nicht. Und die anderen beiden sollten die Dinger erstmal>selbst programmieren.
Ja, aber.
>> Keine Ahung.>Ich denke mal, da fehlt ein 'n' in der Mitte.
Hier hast du dein 'n' für 300 Euro. Maren, dreh mal um (also das n meine
ich)
>Leider ist das die einzige>richtige Aussage in deinen Beiträgen. Wenn ich deine sonstigen Beiträge>auch durchaus zu schätzen weiß, aber bei den Neopixel-Leds liegt du>nicht zum ersten Mal völlig daneben.
Kann sein, muß nicht. Ich sehe das eher sportlich. Der OP geht mit einem
"OMG, geht alles gar nicht" ins Rennen. Ich sage, wo ein Wille, Know How
und Sportsgeist vorhanden ist, findet man auch dafür eine Lösung.
Ob man die wilden Stunts mit Inline-Assembler wie in der oben genannten
Bibliothek machen muss, nur damit es Arduino-Style nach außen ist, sei
dahingestellt.
Reden wir hiervon?
https://www.adafruit.com/product/1376Gähn
Die Daten werden pulsbreitenmoduliert mit 800kHz / 1,25us rausgetaktet,
zwischen den LEDs darf nicht mehr als 50us Pause sein, damit es keinen
Reset bzw. Latch-Befehl gibt. 50us sind eine EWIGKEIT! Man muss ja nicht
das gesamte IR-Protokoll in 50us dekodieren, es reicht wenn man ein
Sample des IR-Empfängers speichert.
Gehen wir mal sportlich von 100 LEDs aus, so dauert deren Ansteuerung
1250 us, ein Witz. Wenn wir also alle 10 LEDs (=12,5us / 80kHz) ein
Sample nehmen, ist das mehr als ausreichend. Da wir ja nicht dauerhaft
nur LEDs ansteuern, sondern mal sportlich von 100 Hz Updaterate
ausgehen, bleiben noch ca. 8,5ms übrig, um dann die Dekodierung der
IR-Daten vorzunehmen. In wie weit die Software des IR-Dekoders dafür
schon ausgelegt ist, weiß ich nicht.
Das Ganze macht man spielend in reinem C ohne eine Zeile Inline
Assembler, sinnvollerweise natürlich mit dem SPI oder UART im SPI-Mode
oder USI, je nach Verfügbarkeit.
Will jemand dagegen wetten?
Die minimale Pulsbreite von 0,35us entspricht 2,8 MHz. Da das SPI vom
AVR mindestens mit Teilerfaktor 2 arbeitet, braucht man halt ~5,7 MHz.
Bei den Arduino-üblichen 16 MHz wird es etwas krumm mit dem
Teilerfaktor, sollte laut Datenblatt aber auch noch gehen!
16 MHz / 4 = 4 MHz / 250ns (liegt in den +/-150ns drin)
Ok, ist nicht optimal in bezug auf die verbleibenden Toleranzen. Also
den Quarz auf 12 MHz umlöten.
Mampf F. schrieb:> Wolfgang schrieb:>> 2 Bit der LED-Daten dauern 2.4µs (8 Bit á 0.3µs)>> Wie kommst du darauf?
Ich war von Timing der SK6812 RGBW Chips[1] ausgegangen, i.e. 0-Bit als
0.3µs High + 0.9µs Low und 1-Bit als 0.6µs High + 0.6µs Low. Dann könnte
man das Bitmuster über SPI mit 0.3µs-Takt und 4 SPI-Bits pro LED-Bit
generieren. Ob das auf einem AVR mit 16MHz in Assembler genug Freiraum
schafft, müsste man probieren.
[1]
https://cdn-shop.adafruit.com/product-files/2757/p2757_SK6812RGBW_REV01.pdf
Der TO bekommt es ja irgendwie nicht fertig, zu seinen Chips mal das
Datenblatt rüberwachsen zu lassen.
Wenn er was anderes braucht - nur her damit.
Vielen vielen Dank soweit. Ich bitte es zu entschuldigen, wenn ich mich
erst mal nicht mehr melde. Ich muss erst ausprobieren.
IRMP kannte ich nicht. Ich habe mir inzwischen den Artikel dazu
durchgelesen und daraufhin Mampf's 1. Kommentar mit der 15kHz-Routine
jetzt verstanden. Wenn es tatsächlich möglich ist, zwischen den
einzelnen LEDs kurze Pausen zu machen und die Timing-Anforderungen nur
innerhalb der 32Bit für ein LED-Modul gelten, könnte man da evtl. was
multiplexen.
Ich bedanke mich und gucke, wie ich damit weiterkomme.
PS: Nach dem Code der IR-Auswertung und der Beschreibung im IRMP-Artikel
könnte es ein NEC-Code sein. Auf jeden Fall 38kHz, 1-Start-Bit, 32Bit
Daten (Adresse, invertierte Adresse, Datenbyte, invertiertes Datenbyte).
Falls es ein Stopp-Bit gibt ignoriert es der Code.
Falk B. schrieb:> Ich sage, wo ein Wille, Know How> und Sportsgeist vorhanden ist, findet man auch dafür eine Lösung.
Vollkommen richtig.
Falk B. schrieb:> Ob man die wilden Stunts mit Inline-Assembler wie in der oben genannten> Bibliothek machen muss, nur damit es Arduino-Style nach außen ist, sei> dahingestellt.
Natürlich nicht.
1
#define WsOut() do\
2
{\
3
unsigned int ledind = 0;\
4
unsigned char colorind = 1;\
5
unsigned char data = 0;\
6
\
7
unsigned char* wsled = (unsigned char*)WsLed;\
8
\
9
while(ledind < (WS_N * 3))\
10
{\
11
data = wsled[ledind + colorind--];\
12
for(unsigned char nInd = 0; nInd < 8; nInd++)\
13
{\
14
if(data & (1 << 7))\
15
{\
16
WS_TOGGLE;\
17
HighDelay();\
18
WS_TOGGLE;\
19
}\
20
else\
21
{\
22
WS_TOGGLE;\
23
LowDelay();\
24
WS_TOGGLE;\
25
}\
26
data <<= 1;\
27
LoopDelay();\
28
}\
29
if(colorind == 1) ledind += 3;\
30
else if(colorind == 255) colorind = 2;\
31
\
32
}\
33
\
34
}while(0)
Die Delays sind je nach Controllertakt(>=6MHz) 0 - 7 NOPs. Das ist die
Zeit, die für anderes zur Verfügung steht. WS_TOGGLE ist mit dem
Schreibzugriff aufs PIN-Register realisiert.
Das Gewürge mit colorind ist dem Umstand geschuldet, daß ich die
Farbwerte in der Reihenfolge RGB eingeben will und die Leds sie anders
haben wollen.
Beim besten Willen: Wo willst du da noch was einbauen? Denn das Tolle
ist, daß auch nur kleine Abweichungen, also ein NOP zuviel oder zu
wenig, die Dinger zum wilden oder auch nur gelegentlichen Blinken
bringen. Schon das WS_TOGGLE, welches man normalerweise jeweils vor oder
hinter die if/else stellen würde, verhagelt dir bei manchen Taktraten
das Timing.
Sven G. schrieb:> PS: Nach dem Code der IR-Auswertung und der Beschreibung im IRMP-Artikel> könnte es ein NEC-Code sein.
Ja, sieht so aus. Über 90% aller herumschwirrenden Fernbedienungen
nutzen heutzutage den NEC-Code.
Es gäbe vielleicht noch folgende Alternative:
IRMP auf ATTiny45 und Rausschreiben der empfangenen Codes per
Software-Uart an Deinen verwendeten µC. Wenn Du auf die Übertragung der
Geräteadresse verzichtest und das schon im ATTiny prüfst, ob sie zu
Deiner Fernbedinung passt, reicht ein Byte zur Übertragung des
IR-Kommandos. Dieses kannst Du dann bequem zwischen den LED-Frames, die
Du verschickst, auf Deinem UART einlesen und entsprechend verarbeiten.
Falk B. schrieb:> Ob man die wilden Stunts mit Inline-Assembler wie in der oben genannten> Bibliothek machen muss, nur damit es Arduino-Style nach außen ist, sei> dahingestellt.
Bei dem Protokol muss man wohl zumindest Assembler verwenden und die
Zyklen abzählen, wenn man keine Hardware-Unterstützung hat.
Also hier die Problemlösung:
300 LEDs mit je 32Bit @ 1,25µs pro Bit (1,25µs LO, 1,3µs HI) bräuchten
dann in etwa 12ms insgesamt.
Pro LED - das wäre dann quasi eine Atomare Einheit, die man nicht
unterbrechen kann - wären das 40µs
- Timer einrichten mit zB 10kHz (IRMP zB verwendet mindestens 10kHz für
den IR-Sampler) = 100µs
- In jedem Timeraufruf die Daten für 2 LEDs senden (80µs)
- Nach dem Daten schreiben den IR-Sampler aufrufen (maximal 20µs oder ca
400 Taktzyklen bei 20MHz AVR).
- etwas Overhead kommt vlt noch hinzu, aber die gehen halt dann von den
400 Taktzyklen weg.
Die 20µs für den IR-Sampler sind noch unterhalb der 80µs Reset-Time der
LEDs, passt also.
Und der IR-Sampler wird mit ziemlich konstanten 10kHz aufgerufen.
Die Refresh-Zeit ist damit dann ziemlich genau 15ms und innerhalb der
20ms, die der TE anstrepte.
Voila, Problem gelöst :)
@ Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
>Natürlich nicht.> #define WsOut() do\
Auch herje, ein Monster-Makro. Auch das braucht man hier nicht wirklich.
>Die Delays sind je nach Controllertakt(>=6MHz) 0 - 7 NOPs. Das ist die>Zeit, die für anderes zur Verfügung steht. WS_TOGGLE ist mit dem>Schreibzugriff aufs PIN-Register realisiert.
Schon klar.
>Beim besten Willen: Wo willst du da noch was einbauen?
Zwischen den einzelnen LED-Paketen, dort hat man bis zu 50us Zeit.
Schrieb ich bereits mehrfach.
>Denn das Tolle>ist, daß auch nur kleine Abweichungen, also ein NOP zuviel oder zu>wenig, die Dinger zum wilden oder auch nur gelegentlichen Blinken>bringen.
Dann haben sie entweder ihr Datenblatt nicht gelesen oder du einen
Fehler gemacht. Was ist wohl wahrscheinlicher?
> Schon das WS_TOGGLE, welches man normalerweise jeweils vor oder>hinter die if/else stellen würde, verhagelt dir bei manchen Taktraten>das Timing.
Wer das mit einem beliebigen Takt per Bitbanging machen will, bitte
schön. Kriegt man hin, ist aber auch eher ein Makro-Krampf. Aber das ist
doch gar nicht zwingend nötig. SPI/UART, fertig.
@ Frank M. (ukw) (Moderator)
>IRMP auf ATTiny45 und Rausschreiben der empfangenen Codes per>Software-Uart
Kann man machen, ist aber nicht nötig. Auch wenn der AVR nur ein guter,
alter 8-Bitter ist, kriegt der das hin.
Falk B. schrieb:> SPI/UART, fertig.
Kauf dir einen Streifen, programmier die Dinger und dann zeig, was du
hast. In der Zwischenzeit unterhalte ich mich mit dem Papst über, na du
weißt schon was.
@Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
>> SPI/UART, fertig.>Kauf dir einen Streifen, programmier die Dinger und dann zeig, was du>hast.
Deal. Wo gibt's die zu kaufen, außer in den USA?
Falk B. schrieb:> Zwischen den einzelnen LED-Paketen, dort hat man bis zu 50us Zeit.
Mit einem LED-Paket meinst Du die Daten für eine LED, richtig?
Um 24 Bit (1 Bit = 1.25µs) für eine LED zu übertragen, bist Du dann ca.
30 µs taub auf dem IR-Receiver. Bei 32 Bit für eine RGBW-SK6812-LED, wie
sie der TO verwendet, sind es ca. 38µs (hier: 1 Bit = 1.2µs).
Das heisst, Du hast bei empfangenen IR-Daten einen Fehler beim Messen
der IR-Flanken von 38µs.
Wenn man sich das NEC-Protokoll anschaut:
0-Bit 560µs Puls, 560µs Pause
1-Bit 560µs Puls, 1690µs Pause
kann das hier konkret, wo sich die Pausen für 1-Bit und 0-Bit erheblich
unterscheiden, tatsächlich funktionieren. Denn 560µs sind von den 1690µs
noch meilenweit entfernt, so dass man einen großen Toleranzbereich (von
ca. 50%) für die gemessenen Zeiten ansetzen kann.
Allerdings schätze ich, dass sich die Übertragungszeit für den ganzen
LED-Frame von 400 LEDs ungefähr verdoppelt. Aus 400 * 36µs = 14,4ms
werden dann so ca. 28 ms. Naja, damit kann man wahrscheinlich leben.
EDIT:
Könnte tatsächlich auch mit IRMP noch funktionieren, man muss lediglich
den Timer-Interrupt, der für IRMP zuständig ist, während der Übertragung
der Daten für eine LED abschalten. IRMP arbeitet beim NEC-Protokoll mit
einer Toleranz von 40%, wenn ich das richtig in Erinnerung habe.
... eine Lösung mit einem zusätzlichem µc der auf die IR Kommandos
lauscht wurde glaube ich schon vorgetragen, wenn man es wirklich nicht
anders hinbekommen sollte ist das wohl die einfachste und angenehmste
Lösung.
Wenn man möchte könnte man dem IR µc einen Puffer verpassen für die
empfangenen Kommandos und der LED steuernde µc gibt dann entsprechend
die Übertragung zwischen den beiden µc frei, wenn genug Zeit dafür ist.
Oder der IR µc "fragt" halt periodisch den LED µc ob er ein neues
Kommando an ihn senden darf, schon recht simpel.
Frank M. schrieb:> Falk B. schrieb:>> Zwischen den einzelnen LED-Paketen, dort hat man bis zu 50us Zeit.>> Mit einem LED-Paket meinst Du die Daten für eine LED, richtig?
Wenn er das wirklich so meint, leuchtet nur die erste.
Frank M. schrieb:> Um 24 Bit (1 Bit = 1.25µs) für eine LED zu übertragen, bist Du dann ca.> 30 µs taub auf dem IR-Receiver. Bei 32 Bit für eine RGBW-SK6812-LED, wie> sie der TO verwendet, sind es ca. 38µs (hier: 1 Bit = 1.2µs).>> Das heisst, Du hast bei empfangenen IR-Daten einen Fehler beim Messen> der IR-Flanken von 38µs.
Die Daten für alle Leds müssen in einem Rutsch gesendet werden. Die
Dinger warten nicht, bis die 50µs zuende sind. Das ist die Mindestzeit,
die eingehalten werden muß, bevor der nächste Frame kommt, damit die
letzte, also in diesem Fall die dreihundertste, das auch noch mitkriegt.
Diese LED-Streifen sind keine synchronen Schieberegister, sondern
digitale Eimerketten.
Thomas E. schrieb:> Die Daten für alle Leds müssen in einem Rutsch gesendet werden. Die> Dinger warten nicht, bis die 50µs zuende sind.
Doch, warten sie. Solange die 50µs nicht überschritten werden, geben sie
die Daten an die nächste LED weiter.
@Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
>>> Zwischen den einzelnen LED-Paketen, dort hat man bis zu 50us Zeit.>>>> Mit einem LED-Paket meinst Du die Daten für eine LED, richtig?>Wenn er das wirklich so meint, leuchtet nur die erste.
Nö.
>> Das heisst, Du hast bei empfangenen IR-Daten einen Fehler beim Messen>> der IR-Flanken von 38µs.>Die Daten für alle Leds müssen in einem Rutsch gesendet werden. Die>Dinger warten nicht, bis die 50µs zuende sind.
Das sollten sie aber. Oder das Datenblatt stimmt nicht.
> Das ist die Mindestzeit,>die eingehalten werden muß, bevor der nächste Frame kommt, damit die>letzte, also in diesem Fall die dreihundertste, das auch noch mitkriegt.>Diese LED-Streifen sind keine synchronen Schieberegister, sondern>digitale Eimerketten.
Naja, es ist schon ein wenig ein Hack ala OneWire, nur deutlich
schneller.
Falk B. schrieb:> Das sollten sie aber. Oder das Datenblatt stimmt nicht.
Das Ding kommt aus China. Da kann das mal passieren.
Irgendwer muss den LED-Controllerchen doch sagen, dass ein neues
Datenbit kommt und das kann eigentlich nur die steigende Flanke sein.
Sonst wäre keine Synchronisation möglich und bei vielen LEDs liefe einem
das Timing weg.
Ihr Lieben !
Ich bin sowas von begeistert ! Ich habe leider zwei Tage warten müssen,
bevor ich es ausprobieren konnte, aber es funktioniert auf Anhieb.
Vielen Dank für die Inspiration !
Folgendermaßen:
Ich habe in die Assemblerschleife, die die Daten an die LEDs rausschickt
einfach vor dem Rücksprung an den Anfang ein sei; eingefügt und am
Anfang ein cli;. Damit sind für einen kurzen Augenblock die Interrupts
freigegeben. Wenn jetzt zwischendurch ein Interrupt ausgelöst wird,
wartet der in der Hardware bis er dran ist und nutzt dann diese kurze
Zeit direkt aus. Die dadurch entstehende Verzögerung ist so gering, dass
das IR-Signal noch gut ausgewertet werden kann. Die von mir verwendete
IR-Auswertung verwendet allerdings keinen regelmäßigen Interrupt wie
IRMP das tut, sondern lässt den Interrupt vom Flankenwechsel am
Empfänger auslösen. Nochmal vielen Dank an Mampf für die Idee mit dem
Multiplexing. Ich habe gezweifelt, dass ich das hinkriege und nie
gedacht, dass das SO einfach ist.
Auszug aus dem Veränderten Code (Quelle: Adafruit)
1
"head20:" "\n\t" // Clk Pseudocode (T = 0)
2
"cli;" "\n\t" // Änderung 1
3
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
4
"sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128)
5
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4)
6
"dec %[bit]" "\n\t" // 1 bit-- (T = 5)
7
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7)
8
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8)
Sven G. schrieb:> Ich bin sowas von begeistert !
Prima
> Die dadurch entstehende Verzögerung ist so gering, dass> das IR-Signal noch gut ausgewertet werden kann.
Interessant wäre jetzt noch zu wissen, wie lange bei einem Interrupt die
Ausgabe an die LEDs maximal verzögert wird.
Wolfgang schrieb:>> Die dadurch entstehende Verzögerung ist so gering, dass>> das IR-Signal noch gut ausgewertet werden kann.>> Interessant wäre jetzt noch zu wissen, wie lange bei einem Interrupt die> Ausgabe an die LEDs maximal verzögert wird.
Soweit ich das verstanden habe, ist das egal ... Die LEDs dürfen nur
nicht länger als 80µs ein LOW-Signal erhalten.
80µs ist eine lange Zeit, in der viel gemacht werden kann - der
IR-Interrupt wird diese bestimmt nicht aufbrauchen.
Die Lösung vom TE finde ich gut!
Daran hatte ich nicht gedacht, dass der Interrupt gespeicher und dann
ausgeführt wird, sobald die Interrupts wieder aktiviert werden.
Die maximal 40µs Verzögerung dürften dem IR-Dekoder dann kaum stören.
Mampf F. schrieb:> Soweit ich das verstanden habe, ist das egal ... Die LEDs dürfen nur> nicht länger als 80µs ein LOW-Signal erhalten.
Ich bin auch dieser Meinung, obwohl das den Angaben im Datenblatt
widerspricht. Deshalb wäre es IMHO gut zu wissen wie weit die
IR-Interruptroutine von Sven diesen 0-Pegel ungestraft verlängert.
Ich habe leider keine von den LEDs hier, um mal das Streching der
0-Phase auszureizen.
Ich werde bei Gelegenheit mal die Zeit in der IR-Routine messen.
Den kompletten Code der IR-Routine wollte ich hier nicht her kopieren
und ich habe auch gerade keinen konkreten Link dahin gefunden. Er stammt
auf jeden Fall von http://www.plumgeek.com/ und gehört zu einem
Lernroboter Ringo2. Der Originalcode ist nur für 8MHz und braucht für
16MHz µC eine kleine Änderung in der Zeitmessung (>>1).
Dass der Interrupt in der Hardware wartet, hatte ich glaube ich mal
irgendwo gelesen, war mir aber nicht mehr sicher. Aber dass es jetzt
reibungslos funktioniert spricht dafür, dass das stimmt.
Sven G. schrieb:> Damit sind für einen kurzen Augenblock die Interrupts> freigegeben.
Besser fährt man i.d.R. mit der umgekehrten Logik:
Die IRQ für die nötige Zeit sperren, sonst freigeben.
Nicht alle IR-Protokolle verkraften 80µs Framing-Error.
@batman: Das ist schon klar. Aber es ging doch jetzt gerade darum, aus
einem leistungsschwachen µC ein Protokoll mit harten Timinganforderungen
rauszuquetschen und dafür braucht man eine lange Interruptsperre. Jetzt
haben wir offenbar eine Stelle im Protokoll gefunden, wo die
Timinganforderung lockerer ist und nutzen die für den Interrupt. Das von
mir verwendete IR-Protokoll kann die kurze Verzögerung gut verkraften.
Wenn es für andere nicht reicht muss man da wohl trickreicher sein oder
aber gleich einen anderen µC verwenden, wie oben andere schon
vorgeschlagen haben.
Da ich sehr gern so lange wie möglich bei Bekanntem bleibe, bin ich froh
dass das nochmal funktioniert.
Es sollte natürlich Augenblick heißen. ;-)
@Mampf unterwegs (Gast)
>Pragmatische Einstellung, finde ich gut :)
Jain. Der OP hat auch eine gute Portion Glück, daß es hier so einfach
funktioniert. Wenn man sicher sein will, muss man zumindest mal
durchmessen, wie lange die ISR braucht und wieviel Reserve noch zu den
offiziellen 50us Maximalpause vorhanden ist.
Sven G. schrieb:> Jetzt haben wir offenbar eine Stelle im Protokoll gefunden, wo die> Timinganforderung lockerer ist und nutzen die für den Interrupt.
Man kann es auch ganz klar so formulieren: Das Datenblatt der LEDs ist
bzgl. der Dauer des Zeitfensters für die Low-Phase falsch.
Meine Vermutung: Die angegebenen Werte z.B. beim SK6812 für T0L und T1L
sind Minimalwerte und die Toleranzangaben ("±0.15μs") sind in dieser
Form Unfug. Die maximale Dauer der Low-Phase ist durch die Schwelle
von 80µs für Trst (Reset/Latch?) begrenzt.
@Wolfgang (Gast)
>Man kann es auch ganz klar so formulieren: Das Datenblatt der LEDs ist>bzgl. der Dauer des Zeitfensters für die Low-Phase falsch.>Meine Vermutung: Die angegebenen Werte z.B. beim SK6812 für T0L und T1L>sind Minimalwerte und die Toleranzangaben ("±0.15μs") sind in dieser>Form Unfug. Die maximale Dauer der Low-Phase ist durch die Schwelle>von 80µs für Trst (Reset/Latch?) begrenzt.
Das würde ich auch vermuten. Die Dekodierung erfolgt einfach über 2
retriggerbare Monoflops. Das erste mißt die Pulsdauer von
350/700ns, das 2. die Resetdauer von 50us.
Die 50µs Zeit hat man ja nicht nur nach einem bestimmten sondern nach
jedem LED-Bit. Bei einem 20MHz µC entspricht das 1000 Takten Zeit. Da
sehe ich die "harten Timinganforderungen" nicht wirklich.
Wolfgang schrieb:> Man kann es auch ganz klar so formulieren: Das Datenblatt der LEDs ist> bzgl. der Dauer des Zeitfensters für die Low-Phase falsch.
Im mc.net Artikel steht für die WS2812 das gleiche ... Allerdings wird
dort geschrieben, dass meistens schon 5us ausreichen für einen Reset
anstatt 50us ... :)
Falk B. schrieb:> @Mampf unterwegs (Gast)>>>Pragmatische Einstellung, finde ich gut :)>> Jain. Der OP hat auch eine gute Portion Glück, daß es hier so einfach> funktioniert. Wenn man sicher sein will, muss man zumindest mal> durchmessen, wie lange die ISR braucht und wieviel Reserve noch zu den> offiziellen 50us Maximalpause vorhanden ist.
Aus Interesse habe ich mir vor einiger Zeit mal den vom AVR-GCC
erstellten Assembler Code (zu finden in der *.LSS Datei im
Kopilerordner) für eine ISR angesehen...
Je nach Optimierung des Compilers kann man für das Pushen / Pullen der
uC Register auf den Stack etwas 50 Takte als Overhead rechnen, d.h. bei
16Mhz macht das gut 3,1us zusätzlich zum eigentlichen Code in der
ISR.... Sollte also noch satt im Toleranzbereich der WS2812 Chips liegen
@Reiner_Gast (Gast)
>> durchmessen, wie lange die ISR braucht und wieviel Reserve noch zu den>> offiziellen 50us Maximalpause vorhanden ist.>Aus Interesse habe ich mir vor einiger Zeit mal den vom AVR-GCC>erstellten Assembler Code (zu finden in der *.LSS Datei im>Kopilerordner) für eine ISR angesehen...
Und was hast du gesehen? Wieviele Takte wurden benötigt?
>Je nach Optimierung des Compilers kann man für das Pushen / Pullen der>uC Register auf den Stack etwas 50 Takte als Overhead rechnen, d.h. bei>16Mhz macht das gut 3,1us zusätzlich zum eigentlichen Code in der>ISR.... Sollte also noch satt im Toleranzbereich der WS2812 Chips liegen
???
Ich sehe keine Angabe zur ISR-Laufzeit. Die besteht ja nicht nur aus
deinen ca. 50 Takten für push/pop.
Falk B. schrieb:> @Reiner_Gast (Gast)>>>> durchmessen, wie lange die ISR braucht und wieviel Reserve noch zu den>>> offiziellen 50us Maximalpause vorhanden ist.>>>Aus Interesse habe ich mir vor einiger Zeit mal den vom AVR-GCC>>erstellten Assembler Code (zu finden in der *.LSS Datei im>>Kopilerordner) für eine ISR angesehen...>> Und was hast du gesehen? Wieviele Takte wurden benötigt?>>>Je nach Optimierung des Compilers kann man für das Pushen / Pullen der>>uC Register auf den Stack etwas 50 Takte als Overhead rechnen, d.h. bei>>16Mhz macht das gut 3,1us zusätzlich zum eigentlichen Code in der>>ISR.... Sollte also noch satt im Toleranzbereich der WS2812 Chips liegen>> ???>> Ich sehe keine Angabe zur ISR-Laufzeit. Die besteht ja nicht nur aus> deinen ca. 50 Takten für push/pop.
Ja, was weiß denn ich, ich kenne auch nicht den Code jeder ISR auf
dieser Welt... Das kann nur der Programmierer sagen, wenn er schaut, was
der Compiler daraus macht (siehe LSS Datei)
Wie ich geschrieben kann mal als zusätzlichen der Overhead ca 50 Takte
zum eigentlichen Code innherhalb der ISR rechnen
@batman (Gast)
>Man kann auch gleich Assembler schreiben.
Kann man, will man meistens aber nicht.
>Für eine ISR müssen nicht zwingend 50 Register gepusht werden, wenn>überhaupt welche.
Niemand redet von 50 Registern, sondern bestenfalls von 50 TAKTEN! Aber
naja, wir wissen ja vom wem dieser Beitrag kommt.
batman schrieb:> Man kann auch gleich Assembler schreiben.> Für eine ISR müssen nicht zwingend 50 Register gepusht werden, wenn> überhaupt welche.
50 Take != 50 Register....
Schau mal ins Datenblatt von z.B. dem ATMega328 (Kapitel 37)... Da
"kostet" ein PUSH oder ein PULL eines Registers jeweils 2 Takte
Bei 50 Takte macht das 25 Takte für den Eintritt in die ISR... Und 25
Takte für das Wiederherstellen der uC Umgebung... das ganze nochmal
geteilt durch die 2 Takte pro Befehl...
Einfluss hat darauf auch, welche Compiler Optimierung eingeschaltet ist
bzw. wie viele der Register in der ISR tatsächlich benutzt werden (weil
nur die vorher gesichert werden)
Mampf unterwegs schrieb:> Im mc.net Artikel steht für die WS2812 das gleiche ... Allerdings wird> dort geschrieben, dass meistens schon 5us ausreichen für einen Reset> anstatt 50us ... :)
Das halte ich für ein Gerücht. Neuerdings bekommt man bei eBay eher
WS2812-LEDs, die eine Mindestzeit von 250µs(!) brauchen, bevor die
Daten ausgegeben werden ("Latch"). Wahrscheinlich liegt das an den neu
eingeführten WS2813-LEDs, welche auch bei Defekt noch das Signal über
einen "Bypass" an die nächste LED weitergeben. Diese brauchen "ganz
offiziell" (s. Datenblatt) diese 250µs.
Aber man muss nicht meinen, dass die Chinesen diese "neuen" WS28212 als
solche deklarieren. Ich habe das vor ca. einem halben Jahr nur durch
Trial- and Error herausgefunden, wo ich von den neuen WS2813 noch nichts
wusste.
EDIT:
Siehe auch https://www.elecrow.com/blog/ws2813-vs-ws2812/
Frank M. schrieb:> Das halte ich für ein Gerücht.
Ich nicht.
Ich habe gerade nagelneue SK6812 mit RGBW auf dem Tisch. Die benehmen
sich zwar deutlich manierlicher als WS2812b, resetten aber dennoch nicht
erst nach den im Datenblatt angegebenen 80µs, sondern nach 40µs.
Aber vielleicht bin ich ja nur wieder zu blöd, das Datenblatt zu lesen
oder mein Monstermakro ist schuld.
Thomas E. schrieb:> Frank M. schrieb:> Das halte ich für ein Gerücht.>> Ich nicht.>> Ich habe gerade nagelneue SK6812 mit RGBW auf dem Tisch.
SK6812 != WS2812
Mampf unterwegs schrieb:> Im mc.net Artikel steht für die WS2812 das gleiche ... Allerdings wird> dort geschrieben, dass meistens schon 5us ausreichen für einen Reset> anstatt 50us ... :)
Immerhin ist im Datenblatt der WS2813 jetzt angegeben, dass die
Low-Phase vom Signal bis zu 100 Mikrosekunden lang sein darf. Reset ist
dort mit >300µs angegeben.
Das hört sich schon anders an als 0.9µs/0.6μs ±0.15μs bei den SK6812
bzw. 0.8us/0.6µs ±150ns bei den WS2812.
http://www.normandled.com/upload/201605/WS2813%20LED%20Datasheet.pdf
Frank M. schrieb:> Das halte ich für ein Gerücht
ich habe ja deine IRMP in "meine" wordclock mit 114 ws2812b LEDs
eingebaut und keine Probleme, sind aber nur um 3ms für die LEDs das
rauszutakten.
Meine wordclock24 mit 296 LEDs ist leider auf dem Rückweg kaputt
gegangen sonst hätte ich da weiter messen und probieren können.
Dort braucht das raustakten ca. 9ms.
Du bist ja zum STM gewechselt ich vom ATmega328p zum ATmega1284p und
immer noch optimistisch das ich es schaffe.
Wie regelst du das beim STM OK per DMA für die LEDs, aber läuft der DMA
unabhängig vom IRQ?
Frank M. schrieb:> SK6812 != WS2812
Ach, sag nicht sowas. Ist aber das gleiche Prinzip, inklusive dem
RG-Dreher und ein weiteres Indiz dafür, daß diese Neopixels sich einen
Scheiß an die Angaben im Datenblatt halten.
Thomas E. schrieb:> daß diese Neopixels sich einen Scheiß an die Angaben im Datenblatt> halten.
Da gebe ich Dir recht. Allerdings muss man da auch fragen: Welches
Datenblatt kann man da als verbindlich betrachten, wenn man irgendwelche
WS2812 oder SK6812 in China bestellt. Von den Datenblättern schwirren
zig Varianten im Internet rum.
Joachim B. schrieb:> Wie regelst du das beim STM OK per DMA für die LEDs, aber läuft der DMA> unabhängig vom IRQ?
Ja, der DMA läuft komplett unabhängig vom Rest. Da kannst Du den STM32
mit IRQs malträtieren, wie Du willst: Die Übertragung auf die LEDs läuft
einfach stoisch durch.
Für den DMA-Transfer übergibst Du einfach einen Pointer auf einen Buffer
und die Länge. Danach hast Du nichts mehr damit zu tun. Das ist die
einfache, aber relativ RAM-intensive Lösung.
Seit über einem Jahr benutzt die WordClock mit WS2812 jedoch eine
etwas raffiniertere Kombination von DMA und DMA-Interrupt. Damit
reduziert sich der nötige RAM-Bedarf auf einen Bruchteil. Im
DMA-Interrupt werden die nötigen Daten on-the-fly aus den noch zu
übertragenen RGB-Werten berechnet und dann laufend nachgeliefert. Der
DMA-Buffer hat hier keinen Anfang und kein Ende, sondern ist ein
Ringbuffer.
Mit dieser Optimierung konnte ich die Pausen zwischen zwei
Animationsframes für knapp 400 LEDs derart minimieren, dass das
"Fehlverhalten" neuerer WS2812, die nun mehr als 250µs statt 50µs Pause
für den Reset brauchen, erst aufgefallen ist. Statt dann vorne am Anfang
der Stripes weiterzumachen, wurden die Daten des zweiten Frames
plötzlich am Ende des Stripes bitweise rausgekippt. Das bemerkte ich auf
der Suche nach den verlorenen LED-Daten erst, als ich nach den 400 LEDs
noch ein paar weitere LED an den Streifen hing. Die fingen dann
plötzlich an zu leuchten. Dieser Effekt war erst weg, als ich die 50µs
Pause schrittweise bis auf 250µs erhöhte. Mittlerweile arbeitet die
WordClock mit einer Pause von sogar 280µs, um auf der sicheren Seite zu
sein.
P.S.
Die Wordclock24h hat nicht exakt 400 LEDs, sondern inkl. Ambilight
zwischen 349 und 409 LEDs - je nach Ausführung.
Frank M. schrieb:> Für den DMA-Transfer übergibst Du einfach einen Pointer auf einen Buffer> und die Länge. Danach hast Du nichts mehr damit zu tun. Das ist die> einfache, aber relativ RAM-intensive Lösung.
Und der serialisiert und transferiert die Daten über den Port zu den
LEDs?
batman schrieb:> Und der serialisiert und transferiert die Daten über den Port zu den> LEDs?
Jepp. Du musst die rohen RGB-Daten natürlich vorher noch ein wenig
"aufarbeiten". Normalerweise lässt Du den DMA-Transfer per HW-Timer
steuern, dann hast Du einen definierten DMA-Takt, der rein durch HW
gesteuert wird und um den Du Dich nicht kümmern musst. Dafür musst Du
die 0en und 1en vorher so im DMA-Buffer platzieren, dass sie den Zeiten
T0H, T0L, T1H und T1L entsprechen. Du blähst Deine Daten dadurch von
24Bit pro LED Rohdaten mal schnell auf einen satten 8K-DMA-Buffer auf -
je nach Anzahl der LEDs. Das war die simple Methode.
Jetzt zu der eleganten:
Wenn Du den DMA-Buffer so dimensionierst, dass er gerade die Daten für 2
LEDs halten kann, Du diesen dann als "Circular buffer" für DMA
definierst, kommst Du mit weniger als 100 Bytes fürs RAM aus, *egal
wieviele* LEDs Du am Streifen hast. Immer, wenn eine Hälfte des
DMA-Buffers (also für eine LED) bereits übertragen ist, lieferst Du die
Daten für die übernächste LED nach, während der DMA-Transfer gerade die
Daten für die nächste LED raustaktet.
Zusammen mit einem Double-Buffer für den nächsten 400er Frame kannst Du
bereits die Daten für den nächsten Animationsframe berechnen, während
die DMA immer noch am ersten Frame knabbert. Du bist also insgesamt viel
schneller als die LEDs überhaupt verkraften könnten.
Mit DMA macht das so richtig Spaß :-)
So, da bin ich mal wieder. Ich hab mir mal 5m LED-Streifen mit 60Stück/m
= 300 Stück bestellt. Wenn man dafür nicht mal 40 Euro bezahlt, ist das
irgendwie spottbillig 8-0. Es sind WS2812B, die haben 4 Pins und leider
auch nicht ihr Datenblatt gelesen 8-(. Denn die dort genannte Resetzeit
von >50us sind real nur 5us, wie es auch schon im Artikel
WS2812 Ansteuerung geschrieben steht. Hat da der Chinese einen
Dezimalpunkt vergessen? Das penible Einhalten der HIGH/LOW Zeiten ist
nicht nötig? Dachte ich am Anfang! Nach ersten, schnellen Erfolgen an
der LED-Front kam irgendwann die Ernüchterung! Man kann die LEDs zwar
ansteuern, aber die Farben stimmen keine Sekunde! Hää? Sind die High/LOW
Zeiten wirklich SOOO eng? Scheint so. Also mal fix nen Crashkurs "Wie
binde ich Assemblerfunktionen in C ein" und ein paar Stunden später dann
die taktgenaue Ansteuerung in Software. Jetzt passen die Farben exakt.
Hmmm. Damit ist SPI zumindest raus! Warum?
Bei diesem Test musste ich feststellen, daß das SPI vom ATmega 2560
nicht so ganz schnell ist. D.h. man kann nicht lückenlos hintereinander
Daten senden, auch wenn man die Schleife zur Datenausgabe mit nop()
taktgenau optimiert. Es bleibt immer eine minimale Lücke von ca. 300ns
(5 CPU-Takte), welche nicht unterschritten werden kann. Eine weitere
Merkwürdigkeit ist, daß man das Bit CPHA im Register SPCR setzen muss,
damit MOSI am Ende der Datenausgabe auf LOW bleibt! Setzt man es nicht,
geht es immer auf HIGH! Das hab ich bisher bei keinem SPI gesehen, auch
nicht auf anderen AVRs. Bug oder Feature?
Also doch Assembler und Bitbanging. Naja, wenns halt nicht anders geht.
Der Vorteil dieser Funktion ist zumindest, daß man sie auf jeden
beliebigen Portpin anwenden kann. Mit den passenden Arduino-Wrappern
geht das sogar im Arduini-Style. Hab ich jetzt aber nicht gemacht. Die
Low Pulse sind 6 CPU-Takte lang, macht bei 16 MHz = 375ns, die langen
Pulse exakt doppelt so lang. Passt. Doch was machen wir jetzt mit den
doch arg knappen 5us, welche maximal als Pause zulässig sind? 5us sind
nicht wirklich viel Zeit, auch nicht bei 16 MHz CPU-Takt. Wir nehmen die
sportliche Herausforderung an!
Der IRMP basiert darauf, daß das Signal vom IR-Empfänger mit 10-20kHz
abgetastet und dann dekodiert wird. Sagen wir 16 kHz, das sind 62,5us
Periodendauer. Wenn gleich die Auswertung schnell ist, so sind 5us recht
knapp. Wir wollen also nicht die Dekodierung in Echtzeit im
Timer-Interrupt machen, wie es IRMP standardmäßig macht. Anstelle dessen
werden nur die Informationen der Abtastung gespeichert und später zur
günstigen Zeit ausgewertet. D.h. der Timerinterrupt liest nur das
IR-Data Signal und speichert es in einem Array. Sozusagen ein
Logikanalysator mit 1 Bit. So weit, so gut.
Aber trotzdem ist das so eine Sache. 5us sind für eine echt kurze ISR
incl. Hin- und Rücksprung zwar machbar, auch in C, aber es bleibt ein
relativ großer Overhead an CPU-Last, welcher eher ungünstig ist. Mit den
hier verwendeten FIFO-Funktionen wird die Zeit zu lang, wie man im
Screenshots Timing_ISR_short und Timing_ISR_long.png sieht. Selbst der
kurze Durchlauf ohne FIFO-Zugriff reißt eine 6.4us Lücke, der lange mit
FIFO-Zugriff ca. 8,7us. Man sieht auch, daß der Testpuls SYNC, welcher
im C ganz am Anfang und Ende der ISR steht, deutlich kürzer ist. Die
restliche Zeit ist nicht meßbar und wird zum An/Abspringen der ISR sowie
Register sichern/wiederherstellen benötigt! Das sieht man auch recht gut
im *.lss File im Unterordner default.
1
ISR(COMPA_VECT) {
2
328: 1f 92 push r1
3
32a: 0f 92 push r0
4
32c: 0f b6 in r0, 0x3f ; 63
5
32e: 0f 92 push r0
6
330: 0b b6 in r0, 0x3b ; 59
7
332: 0f 92 push r0
8
334: 11 24 eor r1, r1
9
336: 2f 93 push r18
10
338: 8f 93 push r24
11
33a: 9f 93 push r25
12
33c: ef 93 push r30
13
33e: ff 93 push r31
Satte 9xpush + 3 einfache Befehle + 4 Takte zum ISR-EinSsprung macht mal
locker 25 Takte! Das Gleiche beim Beenden!
Darum wählen wir einen etwas unorthodoxen Ansatz. Während der
Übertragung der LED-Daten werden die Interrupts global gesperrt (I-Bit
der CPU = 0). Nach jedem Byte wird allerdings geprüft, ob das
Interruptflag des Timers, welcher ja weiter läuft, schon gesetzt ist.
Denn das passiert immer, egal ob der Interrupt freigegeben ist oder
nicht! Man kann den Timer somit auch im Abfragebetrieb, neudeutsch
"Polling" betreiben. Und genau das tun wir hier. Ist das Timerflag
gesetzt, führen wir die Aktion der Timer-ISR direkt vor Ort aus. Das
spart das Hin- und Rückspringen sowie Register sichern. Das verschafft
uns wertvolle CPU-Zeit, die man im Falle einer komplexeren Operation gut
gebrauchen kann. Das Ganze packen wir in eine 2. Assemblerfunktion, die
neben der LED-Datenausgabe auch noch die IR-Daten abtastet und im FIFO
speichert. Weil während der Interruptsperre auch der Softwarezähler in
der ISR nicht weiter läuft, wird das auch in der Assemblerfunktion mit
erledigt, damit stimmt das Gesamttiming wieder.
Die übertragung der LED-Daten dauert 1,2us/Bit * 24Bit/LED * 300LED =
8640us. Bei 16 kHz Abtastfrequenz sind das ca. 138 Samples. Runden wir
das mal großzügig auf 256 Samples = 32 Bytes auf. Dieser werden als
FIFO benutzt. D.h. während die Timer-ISR mit 16 kHz neue Daten
aufnimmt, werden die bereit vorhandenen Daten in den IRMP gefüttert und
verarbeitet. Das FIFO ist ein wenig vereinfacht, es gibt keine
Echtzeitprüfung auf Überlauf. Es wird nur am Anfang der LED-Übertragung
geprüft, ob genügend Platz im FIFO ist. Wenn nicht, war die Dekodierung
zu langsam und es kann ein Fehler signalisiert werden. Im Beispiel ist
de FIFO sogar 64 Bytes groß. Warum? Weil die UART-Ausgabe mit 9600 Baud
ziemlich langsam ist, ein Zeichen dauert mehr als 1ms! So lang ist auch
ca. ein Bit der IR-Übertragung! Wenn gleich der Interrupt während der
UART-Ausgabe weiter läuft und Daten sammelt, werden diese nicht
ausgewertet! Wenn also zu lange Strings per UART ausgegeben werden, wird
irgendwann mal der FIFO überlaufen. Abhilfte schaffen hier eine deutlich
höhere Baudrate, ein größeres FIFO oder eine UART-Ausgabe mit
Interrupts.
Das Update der LED-Kette erfolgt im 20ms Raster, d.h. es bleiben ca.
11,5ms für die IR-Dekodierung und andere Dinge übrig. Das ist mehr als
genug. Die Steuerung der 3 Testprogramme sowie deren Geschwindigkeit
erfolgt über die empfangenen IR-Codes meiner Fernseherfernbedienung, die
entgegen den Aussagen im Artikel IRMP noch mit RC5 Code arbeitet ;-)
Mittels der Lautstärketasten (+/-) kann man die Geschwindigkeit
einstellen, mittels der Programmwahltasten (+/-) das Testprogramm. Mit
der POWER Taste kann man die LEDs dunkel schalten. Es werden nur die
Codes der ersten Betätigung ausgewertet, die nachfolgenden bei
gehaltener Taste werden ignoriert. Das kann man ggf. auch ändern.
Parallel dazu erfolgt die Ausgabe per UART mit 9600 Baud, dann sieht
man, welche Tastencodes empfangen wurden.
OK, das ganz große Luxusziel der Ansteuerung nur mit C und SPI wurde
verfehlt. Aber bei DEN engen Timinganforderungen ist das auch
illusorisch. Aber dennoch wurde gezeigt, wie man zwei zeitlich
anspruchsvolle Aufgaben multiplexen kann, und damit problemlos mit nur
einem eher kleinen Mikrocontroller auskommt, auch wenn man zur
Assembler-Schrotflinte greifen muss ;-)
In Zukunft ist es jedoch SEHR zu empfehlen, LEDs mit DEUTLICH längerer
Reset-Zeit und entspannterem Timing zu nutzen, wie sie hier im Thread
genannt wurden. Dann kann man auch auf Assembler verzichten. Das
Grundkonzept bleibt aber gleich!
Im Anhang ein paar Screenshots vom Timing und Versuchsaufbau.
Timing_WS2812B_bit.png Bitabstand innerhalb eines Bytes
Timing_WS2812B_byte.png Bitabstand zwischen Bytes
Timing_WS2812B_sample.png Bitabstand zwischen Bytes beim Sampling und
Speicherung im FIFO
Hinweis! In meinem Test wird der LED-Streifen direkt vom Arduino mit 5V
versorgt. Das geht natürlich nur, wenn man nur sehr wenige LEDs mit
voller Stromstärke einschaltet! Will man mehr LEDs gleichzeitig leuchten
lassen, muss man ein externes Netzteil anschließen und die 5V vom
Arduino abklemmen! Wenn man alle 300 LEDs gleichzeitg mit voller
Stromstärke einschalten WÜRDE, würde der LED-Streifen 18A ziehen! Das
klappt praktisch natürlich nicht, weil dann der Spannungsabfall auf den
dünnen Leitungen viel zu groß wird. Wer dennoch mögichst viele LEDs
leuchten lassen, will, muss mit dicken Leitungen vom Netzteil an
Zwischenpunkten einspeisen. Ich würde mal 2,5mm^2 Querschnitt und eine
Einspeisung pro Meter empfehlen.
Nachtrag zur Unmöglichkeit des vollen LED-Stroms.
Beitrag "Re: Led- Lichterkette der besonderen Art."
Ich kann im Moment nicht messen, wie hoch der Widerstand der +5V/GND
Leitungen dieser Streifen ist. Es sind ca. 4mm breite Bahnen. Sind wir
mal optimistisch und gehen von 35um Dicke aus, macht das 0,14mm^2
Querschnitt. 8-0
Wenn wir von
N = 300 LEDs (RGB)
I-LED = 60mA/LED (RGB zusammen)
17mm Abstand
0,14mm^2 Querschnitt
18mOhm mm^2/m (Kupfer)
ausgehen, kommen wir auf
300*60mA=18A Gesamtstrom
1
Rk = rho * l / A
2
= 18 mohm mm^2/m * 0,017m / 0,14mm^2
3
= 2,2mOhm
zwischen den LEDs (jeweils auf GND und +5V)
Macht in Summe
1
U = N/2 * (N+1)*I-LED * 2 * Rk
2
~ N^2 * I-LED * Rk
3
= 90000 * 60mA * 2,2mOhm
4
= 11,9V
Bissel viel für ein 5V System ;-)
Ok, rechnen wir mal realistischer mit 0,5m LED-Streifen, einseitig
gespeist, das ist gleichbedeutend mit 1m LED-Streifen und beidseitiger
Speisung.
1
U ~ N^2 * I-LED * Rk
2
= 900 * 60mA * 2,2mOhm
3
= 0,122V
Das passt! Und jetzt mit 1m LED-Streifen einseitig (=2m LED zweiseitig)
1
U ~ N^2 * I-LED * Rk
2
= 3600 * 60mA * 2,2mOhm
3
= 0,483V
Das geht gerade noch so, d.h. man muss einen 5m LED-Streifen an den
Enden sowie je 1,5m nach innen versetzt speisen. Zum Gegensteuern kann
man ja mit 5,5V speisen, das ist noch OK.
Falk B. schrieb:> Wer dennoch mögichst viele LEDs> leuchten lassen, will, muss mit dicken Leitungen vom Netzteil an> Zwischenpunkten einspeisen. Ich würde mal 2,5mm^2 Querschnitt und eine> Einspeisung pro Meter empfehlen.
ich hatte alle 36 LEDs einen eigenen stepdown aus 24V gewählt um die
Ströme beherschbar zu machen.
Falk B. schrieb:> Damit ist SPI zumindest raus! Warum?>> Bei diesem Test musste ich feststellen, daß das SPI vom ATmega 2560> nicht so ganz schnell ist. D.h. man kann nicht lückenlos hintereinander> Daten senden, auch wenn man die Schleife zur Datenausgabe mit nop()> taktgenau optimiert.
Danke für's ausprobieren. Ich hatte das weiter oben im Thread schon mal
nachgerechnet und kam auf das gleiche Ergebnis :)
Falk B. schrieb:> Denn die dort genannte Resetzeit von >50us sind real nur 5us, wie es> auch schon im Artikel WS2812 Ansteuerung geschrieben steht.
Das ist natürlich böse. Offenbar gibt es da alles mögliche zwischen 5us
und 280ms. Und alle nennen sich WS2812.
> Bei diesem Test musste ich feststellen, daß das SPI vom ATmega 2560> nicht so ganz schnell ist.
Meinst Du, dass dieses nur speziell beim ATmega 2560 so ist oder bei
allen AVRs?
Alles in allem danke für den ausführlichen Test und Bericht, war eine
Freude zu lesen :-)
Falk B. schrieb:> So, da bin ich mal wieder.
Chapeau! Wirklich tolle Zusammenfassung!
Da lag ich mit dem Overhead durch die ISR gar nicht schlecht ;-)
@ Frank M. (ukw) (Moderator) Benutzerseite
>> Bei diesem Test musste ich feststellen, daß das SPI vom ATmega 2560>> nicht so ganz schnell ist.>Meinst Du, dass dieses nur speziell beim ATmega 2560 so ist oder bei>allen AVRs?
Das hab ich so noch nicht gesehen, wobei ich die Lücke vor Ewigkeiten
mal als 1 CPU-Takt identifiziert habe. Das war aber auf einem ATtiny2313
oder so.
Beitrag "Re: Atmega SPI Geschwindigkeit (Arduino schneller als C?)"Beitrag "Re: SPI Codetuning"http://www.matuschek.net/atmega-spi/
(Mein Gott, das Netz vergißt nichts)
>Alles in allem danke für den ausführlichen Test und Bericht, war eine>Freude zu lesen :-)
Gern geschehen.
Man kann sich das Leben auch schwer machen. Die gängigen IR-Protokolle
lassen sich mit einer handvoll Codezeilen decodieren. Man braucht nicht
immer ein fettes IRMP reinzuquetschen.
batman schrieb:> Man kann sich das Leben auch schwer machen. Die gängigen> IR-Protokolle> lassen sich mit einer handvoll Codezeilen decodieren. Man braucht nicht> immer ein fettes IRMP reinzuquetschen.
Ja kann man ... Aber weshalb sollte man?
Klar, der Quellcode ist sehr lang, aber wenn IRMP entsprechend
konfiguriert ist, wird nur das nötigste mit kompiliert und dann ist es
nicht mehr fett.
Und ich finde IRMPs Sample-Ansatz sehr gut ... Der Sampler wird vom
Timer aufgerufen und macht selbst nur sehr wenig.
Und ganz ehrlich, man kann sich das Leben auch schwer machen und das Rad
immer wieder neu (und schlechter) erfinden ;-)
Mampf F. schrieb:> Klar, der Quellcode ist sehr lang,
und sprengt die Arduino IDE, als ich meine wordclock 2015 baute klappte
es noch, als ich es mit neuester IRMP versuchen wollte leider nicht
mehr.
Joachim B. schrieb:> Mampf F. schrieb:>> Klar, der Quellcode ist sehr lang,>> und sprengt die Arduino IDE, als ich meine wordclock 2015 baute klappte> es noch, als ich es mit neuester IRMP versuchen wollte leider nicht> mehr.
Hmm, hattest du alle Protokolle aktiviert?
Hatte mit IRMP bisher keine Probleme - auch nicht letztens auf einem
ATMega8 (mit vUSB).
Mampf F. schrieb:> Hmm, hattest du alle Protokolle aktiviert?
ja, daran wirds gelegen haben, wollte einen Uni Dekoder machen
nur welche lässt man dann weg für einen Code Erkenner?
@Joachim B. (jar)
>> Hmm, hattest du alle Protokolle aktiviert?>ja, daran wirds gelegen haben, wollte einen Uni Dekoder machen
Das sollte kein Problem sein.
>nur welche lässt man dann weg für einen Code Erkenner?
Gar keinen. Warum auch? Die paar kB Flash hat doch jeder. Was ging denn
nicht?
Falk B. schrieb:> Gar keinen. Warum auch? Die paar kB Flash hat doch jeder. Was ging denn> nicht?
Die Arduino IDE stotterte konnte den gesammten Code nicht verarbeiten,
file zu groß wenn ich mich recht erinnere, ist schon etwas her, habe
dann abgebrochen.
Ich hab mal den IRMP im Normalzustand vermessen. Die ISR dauert dort
3,5-9,2us, dazu kommen die nicht meßbare An- und Absprungzeit der ISR
von ca. 3us bei 16 MHz CPU-Takt. Incl. Reserve sind vielleicht 15us im
Maximum. Wenn man also LEDs hat bzw. kauft, welche 20us oder mehr als
Pause vertragen, braucht man weder Assembler noch eine
IRMP-Modifikation!
Falk B. schrieb:> Wenn man also LEDs hat bzw. kauft, welche 20us oder mehr als> Pause vertragen, braucht man weder Assembler noch eine> IRMP-Modifikation!
meine wordclock von 2015 mit IRMP und 114 LEDs läuft ordentlich ohne
Probleme.
Timer alle 10ms updatet die LEDs, IRMP ist mit IRQ alle 1/15000s dran
Joachim B. schrieb:> Die Arduino IDE stotterte konnte den gesammten Code nicht verarbeiten,
das hab' ich noch nie erlebt; dass ein Compilat mal grösser als die
Zielflashgrösse wurde, ok, das gibt aber ja bloss entsprechende
Meldungen...
@Falk: total OT, aber ich glaube, der Nachfolger deiner 0.6.5
uralt-Software ist diese hier: http://www.qdkingst.com/en/download :-)
Falk B. schrieb:> Bei diesem Test musste ich feststellen, daß das SPI vom ATmega 2560> nicht so ganz schnell ist. D.h. man kann nicht lückenlos hintereinander> Daten senden, auch wenn man die Schleife zur Datenausgabe mit nop()> taktgenau optimiert. Es bleibt immer eine minimale Lücke von ca. 300ns> (5 CPU-Takte), welche nicht unterschritten werden kann.
Was haste genommen, ein normales SPI?
Probier mal einen USART im Master-SPI-Mode, da ist das Tx-Register
doppelt gepuffert.
@ Horst Meier (horst)
>Was haste genommen, ein normales SPI?
Ja.
>Probier mal einen USART im Master-SPI-Mode, da ist das Tx-Register>doppelt gepuffert.
Kann sein, ist aber jetzt mit der Softwarelösung überflüssig.
@ Jan L. (ranzcopter)
>@Falk: total OT, aber ich glaube, der Nachfolger deiner 0.6.5>uralt-Software ist diese hier: http://www.qdkingst.com/en/download :-)
Hab ich probiert, die Software findet meinen LA nicht. Scheint die
falsche Firmware zu haben. Außerdem meldet Windows beim Anstecken ein
Problem, obwhl der alte Treiber mit der alten Software läuft. Ein
Deinstallieren und neu Installieren des Treibers brachte keinen Erfolg.
8-0
Ich glaub meine Hardware ist nicht kompatibel, denn von dem LA1016 gibt
es diverse (Billig)Nachbauten.
Das Bessere ist immer Feind des Guten. Ich hab mal meine Funktionen mit
ein paar Macros aufgepeppt. Jetzt können sie mit 6,3-10MHz arbeiten, und
das mit recht geringen Abweichungen vom optimalen Timing.
Sooo, da ich gerade mal wieder ein WS2811 Problem beheben musste, habe
ich mal meine ASM-Funktion ein wenig aufgefrischt und optimiert. Man
kann jetzt die Bitzeiten direkt in den Quelltext schreiben, die
Berechnung der Delays erfolgt im Quelltext. Ebenso kann man zwischen LOW
und HIGH Speed Modus wählen.