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 :)
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?
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
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
Hier mal ein paar Ideeen, wie man den WS2812 ansteuern könnte: * https://ww1.microchip.com/downloads/en/AppNotes/00001606A.pdf * https://www.youtube.com/watch?v=aCK0SpZ2ueg * https://www.youtube.com/watch?v=wBcLXBo2I78
http://stm32f4-discovery.net/2018/06/tutorial-control-ws2812b-leds-stm32/ Ob das wohl bei 48 MHz HSI funktioniert?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.