WS2812/2811 mit PIC asm.Verzweiflung!

OP #3055557
Lesenswert?

Moin ihrs..

ich probiere seit einigen Tagen, die WS2812 LEDs zum laufen zu bekommen.
Controller ist ein PIC18F2320, derb übertaktet mit 32MHz (läuft aber 
trotzdem). So komm ich auf einen Systemtakt von 8MHz.
Die gewählte Methode ist das sog. Bitbanging.
Ich hab es "schon" auf die Reihe bekommen, die LEDs anzusteuern, 
allerdings eher Laienhaft. Mein erster Code war einfach nur ne Bitfolge 
(24 Bits) mit anschließendem Reset code für die LEDs. Mehrere LEDs 
konnte ich auch zum leuchten bringen, indem ich das ganze kontinuierlich 
geloopt habe. Das alles allerdings nur in einer Farbe und nicht 
wechselnd oder fadend.

Mein Code ist im Anhang, interessant wirds erst ab der "main".
Ich habe irgendwie das gefühl ich bin mit meiner Methode VÖLLIG auf dem 
Holzweg, denn wenn ich versuche verschiedene Farben oder Übergänge zu 
erzeugen, check ich nicht wie das gehen soll. Das ganze rumgewusel um 
andere Farben zu erzeugen zerstört irgendwie mein Timing :(

Könnte sich da mal einer erbarmen und meinen Code durchschauen?
Ganz Klasse wäre natürlich eine Codevorlage die gut zu verstehen ist in 
asm und welche evtl auch mal die Farben wechselt, damit ich das 
verstehen kann..

Dank und Gruß

xedux
Angehängte Dateien:
OP #3055629
Lesenswert?

akaDem schrieb:
> Ich hab gelesen, dass du nichts über SPI zu wissen scheinst.



jo, da hast du Recht! Was ich weiß ist, dass das ne serielle 
Schnittstelle ist, habs aber noch nie benutzt und weiß daher nicht wie 
das Ding funktioniert. Ich denk mal Byte in den Puffer, dann übertragen 
bis Byte leer, nächstes Byte. aber wie das nun auf dem PIC geht ...habs 
mir grad im Datenblatt angeschaut... erschlägt mich erstmal. Ich werd 
mal schauen, ob ich ein Beispiel finde..
#3055668
Lesenswert?

Wieso ist der Übertaktet???
Der 18F2320 schafft HS-PLL Modus mit einem 10MHz Quarz 40Mhz !
CONFIG1H, FOSC3:0 = b'0110'

Mit deiner CONFIG OSC=HS schafft er genau die Quarzfrequenz, die 
richtige Einstellung ist CONFIG OSC=HSPLL !

Datenblatt:
--> 1.3 Device Overview
--> 2.3 HSPLL
--> 23.1 Configuration Bis
OP #3055676
Lesenswert?

Chris B. schrieb:
> Wieso ist der Übertaktet???
> Der 18F2320 schafft HS-PLL Modus mit einem 10MHz Quarz 40Mhz !
> CONFIG1H, FOSC3:0 = b'0110'

Ja, das stimmt. Allerdings ist dann mein Systemtakt wieder bei 10MHz, da 
Fosc/4 = Systemtakt. Damit kann ich meine Timings nicht passend 
einstellen.
Und selbst wenn die Toleranzen dies zulassen...
...geht es hier auch nicht um übertaktet oder nicht.. sondern 
ausschließlich darum, wie ich das Ding sinnvoll betreibe..
Gast #3055793
Lesenswert?

Tom L. schrieb:
> Ja, das stimmt. Allerdings ist dann mein Systemtakt wieder bei 10MHz, da
> Fosc/4 = Systemtakt. Damit kann ich meine Timings nicht passend
> einstellen.

Dann nim halt einen 8MHz Quarz. Weil: 8*4/4 = 8. Und man braucht sich 
hier schon mal keine Gedanken ums Übertakten zu machen.

Und beim PIC-Assembler muß man nicht so viel 'GOTO' benutzen. Das bringt 
uns PIC-Programmierer immer wieder in Verruf und hält das Vorurteil 
aufrecht, PIC-Code sei unübersichtlich ;-)

Übrigens geht das Bitbanging auch mit 10MHz:
Beitrag "Re: [Mitbestellung] SMD5050 RGB-LED mit integriertem 8-bit PWM Controller"
OP #3055853
Lesenswert?

Ollus schrieb:
> Dann nim halt einen 8MHz Quarz. Weil: 8*4/4 = 8. Und man braucht sich
> hier schon mal keine Gedanken ums Übertakten zu machen.
>
> Und beim PIC-Assembler muß man nicht so viel 'GOTO' benutzen. Das bringt
> uns PIC-Programmierer immer wieder in Verruf und hält das Vorurteil
> aufrecht, PIC-Code sei unübersichtlich ;-)
>
> Übrigens geht das Bitbanging auch mit 10MHz:

Stimmt mit 8MHz und PLL an ginge das auch, wäre dasselbe. Hab aber jetzt 
auch keinen 8MHz Quartz. Wie auch immer, das ist erstmal Nebensache.

Das mit den vielen GOTOs hab ich nur erstmal so gemacht.. schön ist der 
code nicht, das weiß ich wohl :)

Sobald ich raus hab wie das nun funktioniert wird das angepasst.

SPI funktioniert übrigens, hab gerade ein Testbyte rausgeschoben, 
allerdings noch mit Ruhepegel high.. der muss noc hauf low. aber sonst 
scheint das zu klappen. Jetzt ärgert mich noch, dass ich immer 8 Bit 
ausgeben muss, bevor das nächste Byte in den Buffer kann... Meine 
Bitzelle für die LEDs ist 1,25µs und das sind bei 8MHz 10 Bits bzw 5 
Bits bei 4MHz.
Kann man auch nur 5 Bits pro Byte senden? bzw. wie mache ich aus meiner 
8 Bit-Variablen im code ein 5 Bit langes "Byte"?
OP #3055951
Lesenswert?

Die "einfache" Datenweitergabe funktioniert bei den Dingern leider 
nicht.
Ich muss aus jedem Byte des Controllers EIN Bit für die LED basteln 
(siehe Datenblatt) Einfach nur 3 Byte ausm Controller in die LED 
schieben geht dämlicherweise nicht :(   ..scheiss Dinger. Ich frag mich 
warum die nicht eine echte SPI implementiert haben, wo man dann selber 
clocken kann und so.
Echt ärgerlich, so als Anfänger, das alles so hinzubasteln wie es 
vielleicht gehen könnte.
Angehängte Dateien:
Gast #3056479
Lesenswert?

>> nimm die 3 Bytes für die 3 Farben und schiebe sie über die
>> SPI-Schnittstelle raus (Din an DATA anschliessen, den CLK einfach
>> vergessen)
> Du meintest wohl Dout?!

den SDO (Pin 15 des PIC) der SPI-Schnittstelle an Din des WS2812 (Pin 2)
#3056504
Lesenswert?

Zum PIC kann ich nichts sagen, aber mit einem AVR auf 8MHz konnte ich 
einen Strip mit 30 Stück WS2812 problemlos per Bitbanging ansteuern. Das 
einzig Wichtige scheint zu sein, ob die ON-Zeit kleiner oder größer als 
ein gewisser Schwellwert ist. Die OFF-Zeit ist unkritisch, solange man 
nicht in die Nähe der Reset-Zeit kommt.

Für eine 0 hatte ich ein sbi direkt gefolgt von einem cbi (je zwei 
Takte), für eine 1 waren es zwei sbi und ein cbi, das macht eine 
Pulslänge von 250ns für eine 0 und von 500ns für eine 1.
Gast #3056528
Lesenswert?

@Tom L.
> Die "einfache" Datenweitergabe funktioniert bei den Dingern leider
> nicht.
Je nach verwendetem Interface... Ich kenne den PIC nicht. Wenn aber 
beispielsweise der UART die Option hat Start- und Stopbit zu 
deaktivieren biste damit vielleicht besser dran.

> Ich muss aus jedem Byte des Controllers EIN Bit für die LED basteln
Du meinst umgekehrt: Aus jedem Farb-Byte acht SPI-Bytes. Das sollte aber 
doch nicht so schwer sein, oder? Ich hab aber jetzt nicht in deinen Code 
geguckt.

> ..scheiss Dinger. Ich frag mich warum die nicht eine echte SPI
> implementiert haben, wo man dann selber clocken kann und so.
Dann nimm einen WS2801 oder WS2803, da geht das. Und sag bitte nicht, 
dass das ja dann ein externer Chip ist, an den man normale LEDs hängen 
muss.
"Scheiss Dinger" sind das nämlich nicht, ich hab die WS2812 an einem 
8051 per echtem(!) BitBanging (nicht SPI etc.) ans Laufen bekommen.
Bist du fit in Assembler? Dann kommst du vielleicht weiter.

> Echt ärgerlich, so als Anfänger, das alles so hinzubasteln wie es
> vielleicht gehen könnte.
Mach's halt richtig. Ich meine ich hab im Web einen Artikel gelesen, bei 
dem einer die Dinger per SPI auf einem PIC ans laufen brachte. Such mal 
in Youtube nach "LED with integrated WS2811" (nicht WS2812). Wenn ich 
mich recht erinnere, sollte da auch gepostet sein, wie das da gemacht 
wurde.

Ralf
Gast #3056530
Lesenswert?

Nachtrag:
> Kann man auch nur 5 Bits pro Byte senden? bzw. wie mache ich aus meiner
> 8 Bit-Variablen im code ein 5 Bit langes "Byte"?
In dem YT-Link ist auch erklärt, welche Timing-Toleranzen der Chip 
zulässt (steht ja auch im Datenblatt), und welche 8-Bit SPI-Werte dann 
noch funktionieren.

Ralf
#3056538
Lesenswert?

Ralf schrieb:

> Wenn aber beispielsweise der UART die Option hat Start-
> und Stopbit zu deaktivieren biste damit vielleicht besser dran.

Oder den UART-Ausgang (ggf. extern) invertieren, dann kann man Start- 
und Stopbit einfach mitverwenden und bekommt in einem 7n1-Byte des UART 
sogar 3 Bits für den WS2811/12 unter.
#3056549
Lesenswert?

Tja... das mit dem Protokoll ist so eine Sache. Wie auch immer, Dein 
Programm muss ja im zeitkritischen Teil nur die Bytes aus dem RAM 
protokollgerecht zu den LEDs schicken. In der Pause die danach nötig ist 
berechnest Du dann die neuen Farben etc.

Natürlich brauchst Du pro LED 3 Bytes Speicher.

Die einfachste Methode die ich mir vorstellen kann ist ungefähr so:


Schleife1:
    Hole nächstes Byte aus Speicher in X

    Bitzaehler = 8

Schleife2:
    Schiebe X ein Bit nach links ins Carry
    Wenn Carry gesetzt, springe zu Led_An

    Setze DOUT=1
    <Verzoegerung Bit0_High>
    Setze DOUT=0
    <Verzoegerung Bit0_Low>
    Springe zu Nächstes_Bit

Led_An:
    Setze DOUT=1
    <Verzoegerung Bit1_High>
    Setze DOUT=0
    <Verzoegerung Bit1_Low>

Nächstes_Bit:
    Bitzaehler--
    Wenn Bitzaehler > 0 springe zu Schleife2

    Bytezaehler--
    Wenn Bytezaehler > 0 springe zu Schleife1


PIC Assembler sieht ja dermaßen grausig aus, was bin ich froh AVR zu 
nehmen :-)

Grüße
Markus
OP #3056624
Lesenswert?

Danke für die vielen Antworten. Ich hab bereits die LEDs mit 
integriertem Controller.. und zusammen wird das WS2812 genannt.. da is 
der WS2811 drin!
Das mit den Timings ist nicht das Problem, das hab ich verstanden und 
funktioniert auch, siehe erster post. SPI hab ich gestern auf die Reihe 
bekommen, funktioniert auch. Mir war lediglich nicht klar wie ich 
Farbverläufe etc generieren kann, scheint aber alles als Daten im 
Speicher zu liegen, also jede 24-Bitfolge. Heißt also, jeden 
Helligkeitswert für jede Farbe und jede LED ausm Speicher holen und 
rausschieben.

Bzw, irgendeine geloopte Routine schreiben, die zB heller oder dunkler 
fadet.. wie auch immer.

Danke!
OP #3056627
Lesenswert?

Markus M. schrieb:
> Tja... das mit dem Protokoll ist so eine Sache. Wie auch immer, Dein
> Programm muss ja im zeitkritischen Teil nur die Bytes aus dem RAM
> protokollgerecht zu den LEDs schicken. In der Pause die danach nötig ist
> berechnest Du dann die neuen Farben etc.

Moin Markus,

genau so funktioniert mein code ja auch, bis auf das "Byteholen", der 
sonstige ablauf entspricht dem was du gesschrieben hast. War ich ja doch 
nciht so auf dem Holzweg. Hab auch gemerkt, dass ich mehr oder weniger 
schon fertig war mit der ausgabe.. also byte laden, in einen Buffer 
schieben (TempShift) und das dann übers carry hiften und je nach dem ob 
carry gesetzt oder nicht, in die Unterroutinen für Bit_HI und Bit_LO 
springen.

Danke
#3056740
Lesenswert?

Jo... und wie Du schon selbst festgestellt hast, das Faden etc. machst 
Du dann mit einfachen Operationen auf Deine Tabelle mit den RGB-Werten.

Am besten Du schreibst Dir kleine Unterprogramme die die gewünschte 
Funktion auf eine Menge von Werten ausführt. Z.B.

- Verschieben nach links/rechts
- Faden (addieren/abziehen von festen RGB-Werten auf alle Werte im 
Array, am besten noch mit Begrenzung damit kein Überlauf entsteht)
etc.

Evtl. macht es noch Sinn eine Gammakorrektur einzubauen...

Grüße
Markus

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren