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 WS2812LEDs
ü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 :)
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. :(
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?
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.
>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?
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.
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.
> 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
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