Forum: Mikrocontroller und Digitale Elektronik Mit Python ein festes PWM Muster erzeugen?


von Borsty B. (mantabernd)


Lesenswert?

Hi zusammen,

ich nutz einen Nano Pi Neo Air auf dem ich mit Python Sk6812 LEDs 
ansteuern möchte.

Ich weiß dass es fertige Libs gibt, möchte es aber trotzdem selbst 
versuchen und verstehen was wie funktioniert.


Mein erster Versuch den SPI Bus zu Zeckentfremden hat einigermaßen 
funktioniert. Das Timing war leider nicht stabil genug und ich konnte 
auch den Takt nicht exakt einstellen. Es waren immer mehr oder weniger 
800kHz.
Es funktioniert...  aber nicht zuverlässig.

Der nächste Gedanke war PWM zu nehmen. Hier müsste ich doch die 800kHz 
sauber einstellen können? Die LEDs unterscheiden eine 0 / 1 dann 
folglich am DutyCycle.

Ich kann den DutyCycle auch sauber einstellen, nur muss ich das ja für 
eine exakte Anzahl an Takten ändern können.

Hier hänge ich gerade. Wenn ich PWM aktiviere dann läuft PWM ja sofort 
mit dem festgelegten DutyCycle los. Ich muss aber Muster hinterlegen 
können.
Wenn ich z.B. nur die 5. LED rot leuchten lassen möchte muss ich ja die 
Daten für die ersten 4 LEDs anders rausschicken als die für die 5. LED.

Ist soetwas über PWM überhaupt möglich?

Danke
Gruß
Borsty

: Bearbeitet durch User
von Jim M. (turboj)


Lesenswert?

Borsty B. schrieb:
> Wenn ich z.B. nur die 5. LED rot leuchten lassen möchte muss ich ja die
> Daten für die ersten 4 LEDs anders rausschicken als die für die 5. LED.

Bei Hardware PWM kann man den Pins üblicherweise jeweil einen eigenen 
Duty Cycle zuweisen. Ist das beim RPi anders?

Für Beleuchtungs- und Anzeige Zwecke würde es reichen die Duty Cycle 
Werte jeweils so 30-60mal pro Sekunde zu ändern, um ein Muster flüssig 
zu erzeugen.

von Borsty B. (mantabernd)


Lesenswert?

Die SK6812 LEDs erhalten über den DutyCycle ihre Daten.
Es handelt sich nicht um klassisches PWM Dimming sondern um eine echte 8 
Bit Datenübertragung.

Deshalb muss ich taktgenau festlegen welchen DutyCyle der PWM Pin auf 
die Leitung wirft.

Idealerweise brauch ich eine Liste in der ich die Daten hinterlege, der 
PWM Controller muss mir diese Liste dann "abfahren".

Fraglich nur ob das mit Python auf dem Pi klappt.

von Phil E. (aktiver_mitleser)


Lesenswert?

A) Normalerweise macht man das mit DMA und SPI. Die SPI clock muss gar 
nicht mal 3*800kHz sein (damit du "110" als logische 1 oder "100" als 
logische 0 senden kannst) sondern kann auch deutlich schneller sein. 
Wichtig ist nur dass "Anzahl aufeinanderfolgender Einsen" (bzw. Nullen) 
multipliziert mit der SPI-Clockperiode gleich den Timings des 
WS2812B/SK6812 entspricht (350ns/900ns, siehe auch hier: 
https://www.mikrocontroller.net/articles/WS2812_Ansteuerung). Zum 
Beispiel, bei einer 20MHz SPI clock = 50ns Bit-Periode musst du 7 Einser 
(= 350ns lang "1") und 18 Nullen (= 900ns lang "0") ausgeben, damit am 
Schluss "110" mit 1.25µs Periodendauer raus kommt. Dann verbraucht ein 
Bit im WS2812B-Protokoll zwar 25 SPI-Bits, aber das ist bei 512MB DDR 
egal.

Für 5 LEDS brauchst du also 5 Leds *8Bit/Farbe *3 Farben = 120 Bit im 
WS2812B-Protokoll, oder 3000 Bit (bei einer beispielhaften SPI clock von 
20MHz) die du selber in Bytes aufteilen und über SPI rausschicken musst.

Dann verwendest du DMA: du teilst dem DMA-Controller einmal mit, dass er 
deine 3000 Bit selbständig ans SPI übergeben soll. Der wickelt das dann 
selbständig im Hintergrund ab und füttert das SPI immer mit den nächsten 
Bits sobald es wieder Platz für neue Daten hat.

Um deine LEDs anzusteuern musst du also
1: Deine WS2812B-Bits um einen Faktor SPI-clock/800kHz aufblasen und im 
Speicher ablegen
2: dein DMA konfigurieren dass es kontinuierlich alle aufgeblasenen Bits 
aus dem Speicher ans SPI sendet
3: herausfinden, wie du aus Python dein DMA ansteuerst
4: viel auf Einzelbitebene arbeiten, was in Python möglich aber 
umständlicher ist.

B) Einfacher ist ein "Koprozessor", ein separater Mikrocontroller, dem 
du von Python über UART die PWM-Werte schickst und der kümmert sich dann 
ums Timing und ums raus schicken, ohne dass dir dein Betriebssystem 
dazwischen funkt. Wenn du den Selber-Lern-Effekt-ohne-Libs haben willst, 
kannst du es auch selber auf dem Mikrocontroller implementieren, aber da 
deutlich einfacher als auf deiner Pi-Alternative.

: Bearbeitet durch User
von H. (Gast)


Lesenswert?

Oder wenn man die Auswahl der LEDs noch im Griff hat auf APA102 gehen, 
die kann man ganz geschmeidig mit jeder SPI mit jedem beliebigen Takt 
füttern.

von Borsty B. (mantabernd)


Lesenswert?

Philipp M. schrieb:
> Zum
> Beispiel, bei einer 20MHz SPI clock = 50ns Bit-Periode musst du 7 Einser
> (= 350ns lang "1") und 18 Nullen (= 900ns lang "0") ausgeben, damit am
> Schluss "110" mit 1.25µs Periodendauer raus kommt. Dann verbraucht ein
> Bit im WS2812B-Protokoll zwar 25 SPI-Bits, aber das ist bei 512MB DDR
> egal.

Im Grunde hab ich das sogar so umgesetzt :) Nur bin ich nicht auf die 
Idee gekommen den Takt höher zu halten und die Anzahl der Bits zu 
erhöhen. Gar nicht doof :) Mein Problem war die 800kHz möglichst genau 
zu treffen.

Philipp M. schrieb:
> Dann verwendest du DMA: du teilst dem DMA-Controller einmal mit, dass er
> deine 3000 Bit selbständig ans SPI übergeben soll. Der wickelt das dann
> selbständig im Hintergrund ab und füttert das SPI immer mit den nächsten
> Bits sobald es wieder Platz für neue Daten hat.

Soweit hab ich das alles verstanden aber warum brauch ich DMA? Meine 
SPIDEV Lib kümmert sich doch bereits um den Versand der Daten nach 
"draußen"?
Ob ich jetzt die Daten dem DMA oder meiner SPI Library übergebe ist doch 
prinzipell egal, oder?
Welche Vorteile bringt die Nutzung von DMA in diesem Fall?

H. schrieb:
> Oder wenn man die Auswahl der LEDs noch im Griff hat auf APA102 gehen,
> die kann man ganz geschmeidig mit jeder SPI mit jedem beliebigen Takt
> füttern.

Generell ja, brauch halt RGBW und möglichst günstig soll es auch sein. 
Mit einer fertigen Library funzt ja auch alles, dacht mir halt ich setz 
mich mal hin und schreib das von Grund auf selbst. So schwer kann es ja 
nicht sein ein paar LEDs anzusteuern :)

von Phil E. (aktiver_mitleser)


Lesenswert?

Borsty B. schrieb:
> Ob ich jetzt die Daten dem DMA oder meiner SPI Library übergebe ist doch
> prinzipell egal, oder?
> Welche Vorteile bringt die Nutzung von DMA in diesem Fall?

Ja, sofern deine SPI library das ohne Unterbrechung schafft. Sollte dein 
SPI-Peripheral mal leer laufen (keine Daten im TX FIFO) ist das für 
reguläres SPI ja kein Problem, da die Clock dann auch anhält. Da es beim 
WS2812B-Protokoll aber keine Clock gibt werden manche Symbole länger 
ausgegeben.

"Nano Pi Neo Air" und "Python" klingt nach Linux und nicht nach Echtzeit 
oder bare metal. D.h. wenn dein SPI mal leer läuft, kann es einige 
Millisekunden dauern bis Python neue Daten nachliefert. Bis dahin haben 
sich deine LEDs aber längst resettet (50µs). Außer deine 
SPI-Bibliothek unterstützt DMA, was sie sicherlich tut (wie mir jetzt im 
Nachhinein bewusst wird).

Borsty B. schrieb:
> So schwer kann es ja
> nicht sein ein paar LEDs anzusteuern :)

Falsche LEDs ausgesucht ^^

: Bearbeitet durch User
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
Noch kein Account? Hier anmelden.