Forum: Mikrocontroller und Digitale Elektronik WS2812/SK6812 an STM32F030


von M. Н. (Gast)


Lesenswert?

Hallo,

ich stehe gegenwärtig vor einem kleinen Problem:
Ich habe eine Schaltung mit einem STM32F030F4P6 aufgebaut, an dem SK6812 
LEDs hängen. Ich habe vorsorglich die Datenleitung der LEDs an einen 
SPI-MOSI Pin gehängt, da es ja den Trick gibt das Timing der WS2812 LEDs 
über SPI hinzutricksen.

Um ehrlich zu sein dachte ich mir: "48 MHz CPU Frequenz. Das wird schon 
irgendwie fliegen mit den LEDs".

Dann das böse Erwachen: Mittels des SPI Moduls, habe ich leider keine 
Möglichkeit das Signal für die LEDs zu generieren. Das geht von der 
Taktfrequenz her nicht auf.

Dann dachte ich mir, ich nehme einen Timer und mache es im Interrupt des 
Timers. Noch vor der Implementierung hat ein kurzes überschlagen der 
Werte ergeben: Das packt der STM mit seinen Interruptlatenzen etc. 
nicht.

Aktuell habe ich folgende Lösung:
Eine eklige Assembler Funktion, die ich aus C heraus aufrufe, die ich 
solange getweekt habe, bis das Timing gepasst hat. In C war es leider 
nicht möglich das Timing konsistent und vorhersehbar auf die Reihe zu 
bekommen.

Mein aktuelles Problem ist nun:
Während die LEDs mit Daten bespaßt werden, sind alle Interrupts 
deaktiviert. Sonst wäre das Timing in Gefahr.
Allerdings läuft im Hintergrund noch ein DMA. Und genau der ist mein 
Problem. Dieser DMA blockiert ab und zu die Bus Matrix im STM, sodass 
sich das Timing der Assemblerroutine verschiebt. Ich kann den "Worst 
Case" nicht wirklich isolieren, da ich die internen Bus-Zugriffe weder 
monitoren noch exakt vorhersehen kann.
Ich benötige aber den DMA, damit er im Hintergrund kontinuierlich ADC 
Daten wegspeichert.

Hat jemand von euch noch eine Idee, wie man an einem 48 MHz (maximal) 
STM32F030 Cortex M0 halbwegs zuverlässig das Signal für die LEDs 
generiert? Das Ganze hängt an PA7: Mögliche Alternate Functions: 
SPI1_MOSI TIM3_CH2 TIM1_CH1N TIM14_CH1 TIM17_CH1

Aktuell arbeite ich daran den DMA während des LED-Update auch noch 
abgeschaltet zu lassen. Das wäre dann die "dirty" Lösung. Vielleicht 
fällt jemand von euch ja noch was ein :)

von Teo D. (teoderix)


Lesenswert?

Was oft übersehen wird ist, dass die Tx0 Zeiten ein Minimum darstellen 
und bis kurz vor dem einsetzen des Resets, ausgedehnt werden können.
Nur glaube ich, das dir das nicht im mindesten weiter helfen wird. :(

von Horst (Gast)


Lesenswert?

Was spricht dagegen die ADC-Daten über den Interrupt entgegen zu nehmen? 
Du musst bei den LEDs nur darauf achten, dass die High-Zeit genau 
eingehalten wird. Die Low-Zeit ist nicht so kritisch, solange sie nicht 
länger ist als Treset.

Ich habe das so gelöst, dass ich wärend die LED-Datenleitung high ist, 
die Interrupts deaktiviere. Wenn sie low ist, sind die Interrupts aktiv. 
Dann können auch die ADC-Daten über den Interrupt abgeholt werden.

Wobei es mich aber doch sehr wundert, warum Du Probleme mit dem Timing 
hast im Zusammenhang mit dem DMA. Wie genau erzeugst Du denn das Timing 
in Assembler?

von Horst (Gast)


Lesenswert?

Wie hoch hast Du den HCLK gewählt? 48 MHz?

von EngelAloisius (Gast)


Lesenswert?

Könntest einen ESP32 als hilfsprozessor mehmen. Mit 240mhz schnall genug 
und 2 kerne, davon einer nicht durch interrupts gestört. Und wifi 
anbindung mache er auch noch, webserver zur farbeinstellung oder so.

Den stm32 brauchts eigentlich gar nicht.

von piffpoff (Gast)


Lesenswert?

>Dann das böse Erwachen: Mittels des SPI Moduls, habe ich leider keine
>Möglichkeit das Signal für die LEDs zu generieren. Das geht von der
>Taktfrequenz her nicht auf.

Nur aus Interesse, warum geht das nicht?

Der STM32F030F4P6 kann glaube ich maximal 18 Mhz auf dem SPI.
Also bei kern auf 48Mhz mit 4er prescaler läuft er ja schon auf 12Mhz.
Bei kern auf 32Mhz mit 2er prescaler dann SPI auf 16Mhz.

Für die vom WS28112 benötigten 0.15µs würden doch 6.667Mh schon reichen, 
oder?

von olaf (Gast)


Lesenswert?

Also bei mir geht es. Hier mal der Anfang aus meiner Doku:
1
/* Wie funktionierts:                                                    */
2
/* Der WS2812 erkennt High und Low anhand der Impulsbreite               */
3
/* High ---> 0.8us High und 0.4us low  = 1.25us                          */
4
/* Low       0.4us High und 0.8us high = 1.25us                          */
5
/*                                                                       */
6
/* Wir lassen SPI hier mit 2.25Mhz laufen. Dann dauert ein Bit 0.444us   */
7
/* Drei SPI Bits sind dann 1.33us. Das ist eigentlich langsamer als      */
8
/* notwendigen 1.25us, aber der WS2812 erlaubt +/- 0.6us abweichung.     */
9
/* Daher ist alles zwischen 0.65 und 1.85us in Ordnung.                  */
10
/*                                                                       */
11
/* Ich hatte die Ansteuerung erst schneller laufen mit 3Mhz weil das     */
12
/* sich einfacher aus 48Mhz teilen laesst. Leider funktionieren dann     */
13
/* aber nur maximal 20Leds in Serie. Danach laeuft das Timing weg        */
14
/* und die Leds erkennen die Daten nicht mehr.                           */

Der Trick ist also mehrere Bits fuer ein Bit auf dem Bus auszugeben.

Olaf

von mabe (Gast)


Lesenswert?

Eine Alternative zu SPI wäre, einen Timer-Kanal im PWM-Modus zu 
betreiben und den PWM-Wert per DMA zu aktualisieren.
Den ARR-Wert des Timers musst du so einstellen, dass du die 800 kHz 
Taktfrequenz bekommst. Für den PWM-Wert musst du die Werte dann so 
wählen, dass du die gewünschten HIGH-Zeiten für eine 0/1 bekommst.
Die Werte kannst du dann in einem Array vorbereiten, welches du der DMA 
als Adresse übergibst. Die DMA schreibt dann die neuen Werte im 
Hintergrund in das Timer-Resgister.

Nachteil ist der relativ hohe Speicherverbrauch für das Array. Wenn du 
aber nur wenige LEDs und/oder genug Speicher hast, wäre das eine 
Alternative, da du ja auch den TIM17 als Alternate Function nutzen 
kannst.

von Harald A. (embedded)


Lesenswert?

Diese Erkenntnis trifft irgendwann jeden Entwickler, der mit den 
„intelligenten“ LEDs arbeitet. Die CPU kann noch so schnell sein, beim 
Timing degradiert die LED jede CPU durch Interruptsperren und 
dergleichen. Auswege:
Unterstützende Hardwareschaltungen (da gibt es so Tricks mit DMA, SPI 
und sonstigen Spezialfunktionen).
Oder ein Wechsel auf die APA102, die hat ein entspanntes Timing, was mit 
jeder SPI oder auch Bitbanging bedient werden kann. Interrupts oder 
dergleichen bilden kein Problem. Wenn man will kann man mitten im 
Datenstreaming auch 1 Tag Pause einlegen.
Durch Kauf beim Originalhersteller APA ELectronics (ab 1 Rolle möglich) 
umgeht man auch die Gefahr auf den x.ten Klon hereinzufallen.

von olaf (Gast)


Lesenswert?

> Unterstützende Hardwareschaltungen (da gibt es so Tricks mit DMA, SPI
> und sonstigen Spezialfunktionen).

Man koennte ja einen STM32F030 als unterstuetzende Hardwareschaltung 
verwenden. :-D  (natuerlich nur wenn man noch welche hat)

Aber es stimmt schon, die LEDs sind irgendwie ein Schmerz im Arsch. Das 
ist vermutlich wieder so ein Moment wo der RP2040 mit seiner 
Bitgeklimper-Statemachine punkten kann.

Olaf

von B. W. (yesitsme)


Lesenswert?


von pegel (Gast)


Lesenswert?


von M. Н. (Gast)


Angehängte Dateien:

Lesenswert?

Horst schrieb:
> Wie hoch hast Du den HCLK gewählt? 48 MHz?

Ja. 48 MHz

Horst schrieb:
> Wobei es mich aber doch sehr wundert, warum Du Probleme mit dem Timing
> hast im Zusammenhang mit dem DMA. Wie genau erzeugst Du denn das Timing
> in Assembler?

Naja. Ansich relativ primitiv: Ich habe eine Routine, die über das BSRR 
Register den Ausgang steuert. Das Timing ist dann solange mit Oszi und 
"nops / Warteschleifen einfügen" so hingebogen, bis es gepasst hat. 
Meine ARM-Assebler-Kentnisse sind eher so: "Ich klöppel da drauf rum, 
bis es tut". Deswegen ist es auch nicht schön. Ich habe den Code mal 
angehängt. (Der Code toggelt PA3 anstatt PA7, weil ich da zum Testen 
besser mit dem Oszi dran kam)

Das PRoblem ist, dass dieser Registerzugriff durch diesen verfluchten 
APB durch muss. Da greift leider der DMA auch mit rein. Man sieht das 
auch auf dem Oszi: Die Pulsbreiten fangen dann an zu jittern.

Die Hardware ist schon fertig. Deswegen will ich da jetzt nicht nochmal 
was umbauen.

Teo D. schrieb:
> Was oft übersehen wird ist, dass die Tx0 Zeiten ein Minimum darstellen
> und bis kurz vor dem einsetzen des Resets, ausgedehnt werden können.
> Nur glaube ich, das dir das nicht im mindesten weiter helfen wird. :(

Doch! Genau das ist der Trick! Ich bin davon ausgegangen, dass ich das 
mit dem SPI nicht machen kann, weil ich dachte, dass die gesamte 
Periodenlännge der Pulse wichtig ist. Das geht dann ovn den Prescalern 
des SPIs nicht auf.
Aber wenn nur die High-Zeiten stimmern müssen, dann geht das soweit ich 
sehe!

Vielen Dank! Ich baue es auf SPI um. Dann ist endlich diese vermurkste 
Assemblerroutine draußen.

Vielen Dank

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.