Hallo Leute, ich bin mittlerweile am verzweifeln. Habe mich for letzten Tage intensiv mit dem WS2812 LED-Strip auseinandergesetzt und habe herausgefunden, dass der nicht so ohne weiteres zu bedienen ist. Ich möchte als Abschlussprojekt etwas mit diesem Streifen machen. Wir haben in der Schule mit dem ATMega328P gearbeitet, um genau zu sein mit dem mk2 Board von myAvr. Ich wollte aufjedenfall keinen Arduino benutzen, sondern das Protokoll selber „bedienen“. Ist das mit dem 328P/mk2-Board möglich, ohne Assembler sondern in reinen C? Ich dachte nämlich am Anfang: Ha! Was ein einfaches Protokoll, das geht ja doch ganz einfach mit _delay_us. Vielen Dank schon mal im Voraus.
Maci M. schrieb: > ohne Assembler sondern in reinen > C? Scheint ohne (Inline)Assembler nicht zu gehen. (Achtung! Das ist fix und fertig Lösung) Beitrag "AVR ASM ws2811 / ws2812 Ansteuerung mit FastPWM"
Eine einzelne WS2812 LED geht ohne assembler. da dürfen nämlich die high-pegel undendlich lang sein. die lows müssen halbwegs stimmen, aber das klappt normal mit delayus() ganz gut. Die Nachfolger sehen dann allerdings zu kurze Pulse und resetten. Edith sagt: Wenn man als einzige Aufgabe die ws2812er nimmt, dann schafft man es vmtl. auch ohne assembler für mehrere LEDs. Ansonsten halt was synchrones (apa102 z.B.).
:
Bearbeitet durch User
> Ist das mit dem 328P/mk2-Board möglich, ohne Assembler sondern in > reinen C? > > Ich dachte nämlich am Anfang: Ha! Was ein einfaches Protokoll, das > geht ja doch ganz einfach mit _delay_us. Geht mit deinem Board. In Assembler geht es zuverlässig, in C ist es eher Glückssache. Das Problem: der Unterschied zwischen dem Übertragen einer 0 und einer 1 sind nur ein paar Taktzyklen. Das so genau hinzubekommen ist in Assembler kein Problem, man zählt die Taktzyklen der einzelnen Befehle und fügt ggf Nops ein um das Timing hinzubekommen (insg nur eine handvoll Assembler-Befehle). Diese Genauigkeit fehlt bei C - du weißt nicht, was für Befehle der Compiler genau erzeugt. Man kann jetzt per trial-and-error versuchen, das Timing durch irgendwelche Tricksereien hinzubekommen (btw, die Genauigkeit von delay_us reicht nicht), aber das ist dann eher Zufall und man fliegt mit anderen Compileroptionen oder mit LEDs von anderen Herstellern auf die Schnauze. Eine Variante, das in C hinzubekommen, ist, bestimmte Hardwareblöcke des Mikrocontrollers für das WS2812-Protokoll zu missbrauchen (UART, SPI, ...) um das genaue Timiing hinzubekommen - das ist aber eher was für fortgeschrittene Programmierer und hat nur auf bestimmten µC wirkliche Vorteile (ist in "C" ist kein Vorteil, wenn es nur auf einer bestimmten HW läuft!).
Maci M. schrieb: > Ich dachte nämlich am Anfang: Ha! Was ein einfaches Protokoll, das geht > ja doch ganz einfach mit _delay_us. Bei den im Datenblatt angegebenen Toleranzen von 150ns für die L- und H-Zeiten und Spezifikation im Submikrosekundenbereich kann die Auflösung von _delay_us, unabhängig von Unwägbarkeiten der Codeumsetzung je nach Compiler und Compileroptionen, gar nicht reichen. Davon abgehen legt man sich in C nur Steine in den Weg, die man in ASM gar nicht hätte. C verkompliziert die Sache nur unnötig. Hast du ein Oszi/LA zur Verfügung, um dein Timing vernünftig zu kontrollieren?
foobar schrieb: > Diese Genauigkeit fehlt bei C - du weißt > nicht, was für Befehle der Compiler genau erzeugt. Mit nem PIC hab ich das zuverlässig in C hinbekommen. Für das setzen bzw löschen eines Portbits erzeugt der Compiler zuverlässig einen Assemblerbefehl mit einem Takt. Und die Funktion Nop() aus der Library erzeugt genau einen NOP. Wenn man ein Scope an einen Pin hängt, kann man das sehen ohne Takte zu zählen. Und bei den WS muß nur die High-Zeit präzise sein. In der Low-Zeit schafft man es zuverlässig, die Bits zu schieben oder das nächste Byte zu holen, wenn der µC überhaupt schnell genug ist. Mit Assembler verkompliziert man sich den Rest des Programms wie die Erzeugung der Farbmuster und das Userinterface nur unnötig. MfG Klaus
> Mit Assembler verkompliziert man sich den Rest des Programms wie die > Erzeugung der Farbmuster und das Userinterface nur unnötig. Keiner verlangt, dass das gesamte Programm in Assembler geschrieben wird - es reicht die Routine zum Ansteuern der LEDs.
Vielen Dank für die Antworten. Ich denke ich werde dann die vorgeschlagene Library verwenden , welche dann das Ansteuern der LED‘s übernimmt. Somit kann ich dann den Fokus meines Projektes auf wichtigere Sachen legen.
Wolfgang schrieb: > Hast du ein Oszi/LA zur Verfügung, um dein Timing vernünftig zu > kontrollieren? Ja klar, von der Schule und mein Vater hat auch eins.
Maci M. schrieb: > Ich denke ich werde dann die vorgeschlagene Library verwenden German Angst MfG Klaus
Klaus schrieb: > Und die Funktion Nop() aus der Library erzeugt genau einen NOP. Und du bist sicher, dass sich dahinter ein Funktionsaufruf und nicht ein Makro mit dem Assembler-Befehl "nop" als Inline verbirgt? ;-)
Klaus schrieb: > German Angst Ja, hätte es gerne selber gemacht aber habe 0 Erfahrung in Assembler und möchte wegen sowas nicht mein Fachabitur unnötig riskieren.
Wenn du noch umschwenken kannst investiere in APA102, die sind wesentlich einfacher (und für Anfänger logischer) anzusteuern. Dazu wirst du den Code auch noch erklären können. Als weiteren Vorteil kann der uC nebenbei auch noch etwas anderes machen ohne die korrekte Übetragung zu stören.
Johannes S. schrieb: > Hier findest du einiges dazu: > https://www.mikrocontroller.net/articles/WS2812_Ansteuerung Und hilfreiche Infos, inwiefern sich das Datenblatt-Timing aufweichen läßt, findet man hier: https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/ Bei allen halbwegs neuzeitlichen AVR8 (also auch beim Mega328P) gibt es aber UARTs, die auch als SPI-Master laufen können. Die kann man verwenden, um das exakte Timing zu erzeugen. Aber auch so bleibt die Sache recht zeitkritisch, weil die Aufbereitung der Daten für die SPI-Geschichte relativ aufwendig ist. Wenn es allerdings nicht allzu viele LEDs sind, kann man die aufbereiteten Daten komplett im RAM puffern, dann wird auch Programmierung in C realistisch, sogar mit einer konkurrierenden ISR während der WS28xx-Ausgabe.
Harald schrieb: > Wenn du noch umschwenken kannst investiere in APA102 Ja, habe mich nicht festgelegt. Kann ich dann das Protokoll komplett in C ansteuern? Gibt es evtl. Turorials?
Maci M. schrieb: > Kann ich dann das Protokoll komplett in > C ansteuern? Ja. Wenn du willst. Alternativ: Du könntest die Daten über die SPI Hardware raus schicken. So schaufelst du noch zusätzliche Rechenzeit frei.
Arduino Fanboy D. schrieb: > Maci M. schrieb: > Kann ich dann das Protokoll komplett in > C ansteuern? > > Ja. > Wenn du willst. > > Alternativ: > Du könntest die Daten über die SPI Hardware raus schicken. > So schaufelst du noch zusätzliche Rechenzeit frei. Ich verstehe das Prinzip des Apa102 nicht zu 100%. Die Datenleitung verstehe ich soweit, aber die Clockleitung nicht. Wo muss ich die Clockleitung anschließen? Kann ich dafür einfach meinen auf dem Board integrierten 3,686400 MHz Quarz verwenden?
Du kannst natürlich wie vorgeschlagen mit der integrierten SPI arbeiten. Allerdings müsstest Du das erklären können. Also würde ich vorschlagen, Du machst die SPI in Software. Das ist nicht schwer: Für jede LED musst Du 32bit in die LED reinhalten. Dazu werden die Bits nacheinander an Data angelegt. Wenn das geschehen ist, signalisiert man mittels Clock (0-1-0 Folge), dass die Daten übernommen werden können. Danach wird das nächste Bit übertragen usw. usw. Wenn dann 32 Bit übertragen sind macht man mit der nächsten LED weiter. Man kann das hier nicht alles im Detail aufschreiben, dafür gibt es bereits tonnenweise Tutorials im Netz. Google mal etwas rum, da findet sich was.
Maci M. schrieb: > Die Datenleitung verstehe ich soweit, aber die Clockleitung nicht. Die (Wirkung der) Datenleitung kann man erst verstehen, wenn man verstanden hat, was die Clockleitung tut. Maci M. schrieb: > Wo muss ich die Clockleitung anschließen? Das entscheidest du. Maci M. schrieb: > Kann ich dafür einfach meinen auf dem Board integrierten 3,686400 MHz > Quarz verwenden? Das verstehe ich nicht..... Also antworte ich vorsichtig mit: JA! --- Du bist der Programmierer deiner Anwendung. Du triffst alle Entscheidungen.
Maci M. schrieb: > Ja, hätte es gerne selber gemacht aber habe 0 Erfahrung in Assembler und > möchte wegen sowas nicht mein Fachabitur unnötig riskieren. Ich schrieb ja, daß es in C geht. Knapp ein dutzend Zeilen Code. Wolfgang schrieb: > Klaus schrieb: >> Und die Funktion Nop() aus der Library erzeugt genau einen NOP. > > Und du bist sicher, dass sich dahinter ein Funktionsaufruf und nicht ein > Makro mit dem Assembler-Befehl "nop" als Inline verbirgt? ;-) Ich bin sicher, daß sich dahinter kein Funktionsaufruf verbirgt, sondern ein volatile Assembler-NOP. Und der dauert, Überraschung, genau einen Takt. Das ist der ganze Sinn dieser Library-Funktion, daß man sich nicht mit Assembler beschäftigen muß. MfG Klaus
Arduino Fanboy D. schrieb: > Maci M. schrieb: >> Kann ich dafür einfach meinen auf dem Board integrierten 3,686400 MHz >> Quarz verwenden? > Das verstehe ich nicht..... > Also antworte ich vorsichtig mit: JA! Besser nicht! ( Anschließen bzw. Antworten ;) Klaus schrieb: > Ich schrieb ja, daß es in C geht. Knapp ein dutzend Zeilen Code. Da bin ich mir auch ziemlich sicher. Der uC muss nur schnell genug laufen! Ein Beispiel für einen PIC mit Befehlstakt von 4MHz findet man hier: Beitrag "Re: [ASM & C] PIC12/PIC18/PIC24 WS2812 SPI Library" Für AVR wird es ganz ähnlich sein.
:
Bearbeitet durch User
Harald schrieb: > Google mal etwas rum, da findet sich was. Nein, man findet leider nur sehr wenig und wenn dann nur für den Arduino. Das Prinzip wie man die Clockleitung bedient wird auch nirgendwo erklärt. Oder wie man den led Strip per spi steuert. Schade
Maci M. schrieb: > Nein, man findet leider nur sehr wenig und wenn dann nur für den > Arduino. Arduino ist keine CPU und keine Programmiersprache, den Code kann man ohne weiteres auch in anderen Umgebungen verwenden.
Maci M. schrieb: > Das Prinzip wie man die Clockleitung bedient wird auch nirgendwo > erklärt. Ääähmmm ... Eine Leitung bedient man, in dem man mit dem betreffenden Pin wackelt. Ob du in Software, oder die SPI Hardware es tut, ist zweitrangig. Und ja, wie man in Software an den Pins wackelt, wird tausendfach im Netz erklärt. Auch: Wikipedia hat einen schönen Artikel über SPI grundsätzlich. Das Datenblatt der APA102 sagt dir, wie es das pingewackel gerne hätte Das Datenblatt deines µC erklärt dir was die SPI Einheit kann, oder auch, wie man in Software an den Pins wackelt.
Maci M. schrieb: > Das Prinzip wie man die Clockleitung bedient wird auch nirgendwo > erklärt. Wie von Anderen schon erwähnt, gibt es da bestimmt viele Beispiele. Einfach immer ein Bit an den Datenausganspin anlegen und dann mit Clockausgangspin entsprechend dem DIAGRAMM IM DATENBLATT DER LED toggeln. Ein primitives Beispiel zum Raustakten von 8 Bits (Polarität und Flanken des CLK sowie Reihenfolge der Bits passen evtl nicht zur APA102!):
1 | #define SPI_OUT() { \
|
2 | SPI_DOUT = spiData.bit7; \ /* bit anlegen */ |
3 | SPI_CLK = 1;SPI_WAIT; \ /* clock 1 */ |
4 | SPI_CLK = 0; \ /* clock 0 */ |
5 | SPI_DOUT = spiData.bit6; \ /* naechstes bit */ |
6 | SPI_CLK = 1;SPI_WAIT; \ |
7 | SPI_CLK = 0; \ |
8 | SPI_DOUT = spiData.bit5; \ |
9 | SPI_CLK = 1;SPI_WAIT; \ |
10 | SPI_CLK = 0; \ |
11 | SPI_DOUT = spiData.bit4; \ |
12 | SPI_CLK = 1;SPI_WAIT; \ |
13 | SPI_CLK = 0; \ |
14 | SPI_DOUT = spiData.bit3; \ |
15 | SPI_CLK = 1;SPI_WAIT; \ |
16 | SPI_CLK = 0; \ |
17 | SPI_DOUT = spiData.bit2; \ |
18 | SPI_CLK = 1;SPI_WAIT; \ |
19 | SPI_CLK = 0; \ |
20 | SPI_DOUT = spiData.bit1; \ |
21 | SPI_CLK = 1;SPI_WAIT; \ |
22 | SPI_CLK = 0; \ |
23 | SPI_DOUT = spiData.bit0; \ |
24 | SPI_CLK = 1;SPI_WAIT; \ |
25 | SPI_CLK = 0; \ |
26 | }// end SPI_OUT() |
spiData wäre hier eine UNION aus einem Char und einem Bitfeld mit 8*1 Bit
1 | union v8bit |
2 | {
|
3 | char all; |
4 | struct
|
5 | {
|
6 | unsigned LN :4; |
7 | unsigned HN :4; |
8 | };
|
9 | struct
|
10 | {
|
11 | unsigned bit0 :1; |
12 | unsigned bit1 :1; |
13 | unsigned bit2 :1; |
14 | unsigned bit3 :1; |
15 | unsigned bit4 :1; |
16 | unsigned bit5 :1; |
17 | unsigned bit6 :1; |
18 | unsigned bit7 :1; |
19 | };
|
20 | };
|
21 | union v8Bit spiData; |
:
Bearbeitet durch User
Volker S. schrieb: > Maci M. schrieb: > Das Prinzip wie man die Clockleitung bedient wird auch nirgendwo > erklärt. > > Wie von Anderen schon erwähnt, gibt es da bestimmt viele Beispiele. > Einfach immer ein Bit an den Datenausganspin anlegen und dann mit > Clockausgangspin entsprechend dem DIAGRAMM IM DATENBLATT DER LED > toggeln. > > Ein primitives Beispiel zum Raustakten von 8 Bits (Polarität und Flanken > des CLK sowie Reihenfolge der Bits passen evtl nicht zur > APA102!):#define SPI_OUT() { Danke für das Beispiel, nur habe ich ehrlich gesagt noch keine Ahnung von SPI, vorallem auf dem AVR. Kennt ihr gute Tutorials die SPI auf dem AVR erklären? Ich gehe nämlich nicht davon aus, dass wir dieses Thema noch in der Schule behandeln.
Maci M. schrieb: > nur habe ich ehrlich gesagt noch keine Ahnung > von SPI Es geht eigentlich nicht um SPI. Das ist nur ein Beispiel, weil SPI eben so funktioniert wie die APA102. Einfach eine synchrone Datenübertragung mit einer Datenleitung und einem Taktsignal. Wenn du das verstanden hast, versteht du auch SPI, bzw die Datenübertragung der APA102 oder wie du das SPI Modul das AVR verwenden könntest um die Datenübertragung zur APA102 zu realisieren.
:
Bearbeitet durch User
Volker S. schrieb: > Einfach eine synchrone Datenübertragung mit einer Datenleitung und einem > Taktsignal. Aber wird dann dadurch auch die CPU entlastet im Gegensatz zum WS2812?
Maci M. schrieb: > Volker S. schrieb: > Einfach eine synchrone Datenübertragung mit einer Datenleitung und einem > Taktsignal. > > Aber wird dann dadurch auch die CPU entlastet im Gegensatz zum WS2812? Das Problem bei WS2812: Es gibt hier keine Taktleitung. Der µC muss ein gewisses Timing einhalten, welches für die WS2812 vorgegeben ist. Das ist bei einem AVR mit C etwas knifflig. Bei APA102-LEDs bestimmt der µC per Taktleitung das Tempo. Von daher gibts mit AVRs zusammen mit APA102 überhaupt kein Problem. Das geht sowohl per Bitbanging oder per PCI. Hier gibts eine AVR-Lösung mit WS2812 von Falk, welche funktioniert: Beitrag "LED-Lauflicht im Knight Rider Style" Allerdings spielt hier auch Assembler mit. Bei STM32-µCs ist es dank DMA überhaupt kein Problem, WS2812 zu steuern. Das geht hier ohne große Belastung der CPU.
Maci M. schrieb: > Volker S. schrieb: >> Einfach eine synchrone Datenübertragung mit einer Datenleitung und einem >> Taktsignal. > > Aber wird dann dadurch auch die CPU entlastet im Gegensatz zum WS2812? Jein, in beiden Fällen kostet die Übertragung Zeit. Das Protokoll der APA102 ist einfach nur „robust“ gegen Timing-Einflüsse jedweder Art (Interrupts, falsche Frequenz, etc.) Wenn wir dir die zentrale Übertragungsfunktion liefern, fängst du dann an?
Klaus schrieb: > Ich bin sicher, daß sich dahinter kein Funktionsaufruf verbirgt, > sondern ein volatile Assembler-NOP. Und der dauert, Überraschung, genau > einen Takt. Das ist der ganze Sinn dieser Library-Funktion, daß man sich > nicht mit Assembler beschäftigen muß. Wenn sich dahinter kein Funktionsaufruf verbirgt, ist es doch irgendwie sinnlos, das als Funktion zu bezeichnen ... Das verwirrt nur und führt einen Anfänger auf die falsche Fährte.
Volker S. schrieb: > Einfach eine synchrone Datenübertragung mit einer Datenleitung und einem > Taktsignal. Aber Frank M. schrieb: > Bei APA102-LEDs bestimmt der µC per Taktleitung das Tempo Heißt das, dass ich theoretisch gar nichts mit SPI etc. machen muss? Sondern einfach nur einen Takt draufgeben muss?
1 | PORTD |= (1<<ClockPin); |
2 | _delay_ms(10); //Zeit nur als Beispiel |
3 | PORTD &= ~(1<<ClockPin); |
Klaus schrieb: > Ich bin sicher, daß sich dahinter kein Funktionsaufruf verbirgt, So ist (verstehe ich) das! "Execute NOP instruction here. This is often useful to fine tune delays or create a handle for breakpoints. The NOP instruction is sometimes required during some sensitive sequences in hardware." Klaus schrieb: > Mit nem PIC hab ich das zuverlässig in C hinbekommen. > .... > In der Low-Zeit schafft man es zuverlässig, die Bits zu > schieben oder das nächste Byte zu holen, wenn der µC überhaupt schnell > genug ist. Der rennt dann aber auch mit 80MHz (20 für AVRler)?! Max D. schrieb: > Eine einzelne WS2812 LED geht ohne assembler. da dürfen nämlich die > high-pegel undendlich lang sein. YMMD Das macht aus meinem anstehen den Experiment, ein Projekt. :)))
Maci M. schrieb: > Aber wird dann dadurch auch die CPU entlastet im Gegensatz zum WS2812? Wenn du die SPI Hardware und diese evtl. gar dann im Interrupt Betrieb nutzt, dann deutlich: ja. (DMA geht ja bei den AVR8 nicht) Selbst mit SoftwareSPI kannst du eine höhere Framerate erreichen, als bei den WS2812. Also Zeitgewinn satt. Tipp: SPI ist so primitiv, dass es schon fast quietscht. Im Moment blockierst du dich selber. Wichtige Quellen, habe ich dir genannt, (Video)Tutorials braucht es nicht. Außer, du möchtest gerne noch mehr verwirrt werden.
Teo D. schrieb: > Klaus schrieb: >> Mit nem PIC hab ich das zuverlässig in C hinbekommen. > Der rennt dann aber auch mit 80MHz (20 für AVRler)?! Ne, mit 16MHz, weil 4MHz Befehlstakt ja völlig ausreichen, um 250ns Zeiten zu realisieren. Sogar in C ;-) Maci M. schrieb: > Volker S. schrieb: >> Einfach eine synchrone Datenübertragung mit einer Datenleitung und einem >> Taktsignal. > > Aber wird dann dadurch auch die CPU entlastet im Gegensatz zum WS2812? Wie lang (wie viele LEDs) soll dein Streifen eigentlich werden? Das wäre interessant, zum Abschätzen der "Blockierung"
:
Bearbeitet durch User
Volker S. schrieb: > Das wäre interessant, zum Abschätzen der "Blockierung Ich wollte 1m nehmen mit insgesamt 144 LED‘s, mir würden auch 60 LED‘s reichen doch die gibt es irgendwie nicht mehr.
Maci M. schrieb: > 144 LED‘s 144 WS2812 LEDs wären in Beispiel Beitrag "Re: [ASM & C] PIC12/PIC18/PIC24 WS2812 SPI Library" mit einem 16MHz PIC ~6*1,4ms -> ~8,4ms. Dein AVR sollte ähnliches leisten können. Wenn das Programm absolut nichts anderes zu tun hätte, könnten der gesamte Streifen mehr als 100 mal pro Sekunde aktualisiert werden. Nichts tun hieße natürlich auch immer die gleichen Farben ;-)
Volker S. schrieb: > Wenn das Programm absolut nichts anderes zu tun hätte, könnten der > gesamte Streifen mehr als 100 mal pro Sekunde aktualisiert werden. > Nichts tun hieße natürlich auch immer die gleichen Farben ;-) Naja, das Programm hätte schon ein paar andere Sachen zu tun wie ADC oder Tasterabfragen.
ADC läuft hauptsächlich im Hintergrund und die Tasterabfragen selbst kann man wohl auch vernachlässigen. Eher was mit den ADC Werten und den Tasterereignissen dann passiert wird etwas Zeit brauchen. Sollten dafür evtl. auch noch vor jeder Aktualisierung 10ms drauf gehen (zig Tausend Befehle), käme man immer noch auf eine mögliche Rate von über 50/s.
:
Bearbeitet durch User
Wolfgang schrieb: > Wenn sich dahinter kein Funktionsaufruf verbirgt, ist es doch irgendwie > sinnlos, das als Funktion zu bezeichnen ... Wie willst du das sonst sauber in C abbilden? Du hast das Konzept einer Hochsprache nicht verstanden. Ein Funktionsaufruf in C muß nicht ein Call in Assembler werden (z.B. inline) und auch, wenn in C keine Funktion zu erkennen ist, kann im Assemblat eine vorkommen (z.B. große Datentypen). > Das verwirrt nur und führt einen Anfänger auf die falsche Fährte. Gerade als Anfänger, der nicht gerade einen Compiler schreiben will, sollte man sich nur um die Sprache kümmern, die man lernt. MfG Klaus
Volker S. schrieb: > Ne, mit 16MHz, weil 4MHz Befehlstakt ja völlig ausreichen, um 250ns > Zeiten zu realisieren. Sogar in C ;-) Richtig, BTDT MfG Klaus
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.