Ich habe hier eine relativ leicht zu nutzende WS2812 Library für den STM32 welche die Daten über PWM rausgibt und diesen mit DMA befeuert. Als ich anfing eine Lib zu suchen hatte ich entweder die Probleme das die verfügbaren Libs viel zu umstaendlich und mitunter viel zu Umfangreich sind. Ich brauchte keine acht Kanaele und wollte keine 3 DMA Channels sowie zwei Timer dafür aufbrauchen. Wollte aber auch auf die Vorzüge von DMA nicht verzichten. Dann kam ich an den Punkt der Bufferung der LED Werte: Viele nutzen (In Verbindung von DMA / PWM) aus einfachheithalber 16Bit Variablen zum speichern des Compare Wertes der einzelnen Nibbles. Was völlig Unnötig ist, da man den DMA ja auch mit Byte zu HalfWord beschreiben kann, das Timing darunter nicht leidet da der DMA ja den 1 Byte Differenz "abwartet". Ich aber somit die Anzahl der LEDs im Buffer aber verdoppeln kann. Klar, die Lib ist natürlich ein RAM-Fresser, aber dafür extrem einfach zu nutzen. Auf einem STM32F103 passen ca. 800 LEDs in den Buffer. Die Dateien liegen auf GitHub: https://github.com/xDraconix/Easy-WS2812-STM32F1-Lib Ich will die Lib noch zu HAL und Bare-Metal umschreiben, rein aus eigenzweck - dürfte dann in den naechsten Tagen auch Online sein. p.s.: Jaaa... meine "ae" Taste ist defekt :-D
Rene K. schrieb: > Was völlig Unnötig ist, da man den DMA ja auch mit Byte zu HalfWord > beschreiben kann, das Timing darunter nicht leidet da der DMA ja den 1 > Byte Differenz "abwartet". Ja, man kann beim STM32F1xx auf Byte-to-HalfWord-Übertragung runter, bei den STM32F4xx benötigt man aber Halfword-to-HalfWord, sonst gehts nicht. So habe ich es jedenfalls umgesetzt für STM32F10x und STM32F4xx im Projekt WordClock mit WS2812. Deshalb läuft der Source https://www.mikrocontroller.net/svnbrowser/wordclock24h/src/ws2812/ auf STM32F103 mit Byte-, auf STM32F401 und F411 mit HalfWord-Übertragung. Man kann auch noch den erforderlichen DMA-Buffer auf die notwendige Datenbreite von lediglich 2 LEDs kürzen, wenn man DMA zyklisch konfiguriert und die Daten während der DMA-Übertragung per ISR nachlädt. > Klar, die Lib ist natürlich ein RAM-Fresser, aber dafür extrem einfach > zu nutzen. Es geht auch ohne RAM-Fresser, siehe oben. Dann ist der DMA-Buffer gerade mal 48 Bytes bzw. 48 Halfwords groß - unabhängig von der Anzahl der LEDs. Zusammen mit Double-Buffering wird das dann ziemlich performant. Dafür braucht man natürlich einen Buffer, welcher die RGB-Werte vorhält (einmal Soll und einmal Ist). Das sind dann 2 x 3 Bytes = 6 Bytes pro LED. > Auf einem STM32F103 passen ca. 800 LEDs in den Buffer. Mit obiger Lib geht (theoretisch) ein Vielfaches davon. Zudem läuft sie auf STM32F1xx und STM32F4xx. Schwieriger zu nutzen ist sie auch nicht ;-)
:
Bearbeitet durch Moderator
Diese Makros beginnen mit Unterstrichen und sind damit für die Standard Library reserviert und dürfen nicht in eigenem Code genutzt werden:
1 | #ifndef __WS2812_H__
|
2 | #define __WS2812_H__
|
3 | |
4 | #define _FREERUNNING
|
5 | #define _NUM_LED 20
|
Außerdem sollte man (20) statt 20 schreiben. Die Funktion Set_Led ist nicht falsch, aber wäre mit Schleifen statt Wiederholungen "schöner".
Frank M. schrieb: > Ja, man kann beim STM32F1xx auf Byte-to-HalfWord-Übertragung runter, bei > den STM32F4xx benötigt man aber Halfword-to-HalfWord, sonst gehts nicht. > So habe ich es jedenfalls umgesetzt für STM32F10x und STM32F4xx im > Projekt WordClock mit WS2812. Deshalb läuft der Source > > https://www.mikrocontroller.net/svnbrowser/wordclock24h/src/ws2812/ > > auf STM32F103 mit Byte-, auf STM32F401 und F411 mit > HalfWord-Übertragung. Oh, okay - ja mit dem F4+ habe ich noch keine Erfahrung mit DMA - danke für den Hinweis, dachte sie verhalten sich da alle gleich. Werde ich mit Umsetzen. Frank M. schrieb: > Man kann auch noch den erforderlichen DMA-Buffer auf die notwendige > Datenbreite von lediglich 2 LEDs kürzen, wenn man DMA zyklisch > konfiguriert und die Daten während der DMA-Übertragung per ISR nachlädt. > >> Klar, die Lib ist natürlich ein RAM-Fresser, aber dafür extrem einfach >> zu nutzen. > > Es geht auch ohne RAM-Fresser, siehe oben. Dann ist der DMA-Buffer > gerade mal 48 Bytes bzw. 48 Halfwords groß - unabhängig von der Anzahl > der LEDs. Zusammen mit Double-Buffering wird das dann ziemlich > performant. Dafür braucht man natürlich einen Buffer, welcher die > RGB-Werte vorhält (einmal Soll und einmal Ist). Das sind dann 2 x 3 > Bytes = 6 Bytes pro LED. DAS ist natürlich eine Super Idee! Einen Soll/Ist Wert wird ja nicht mal zwingend benötigt wenn man nicht unbedingt fein rausfaden will. Somit würde sich das Array ja auf 12,5% schrumpfen und auf dem F1 mit 20kb theoretisch >6000 LEDs ermöglichen. Werde ich auf jedenfall drüber nachdenken und zumindest für mich auf jeden fall mal umsetzen. Auf solch eine Idee bin ich garnicht gekommen :-D Dr. Sommer schrieb: > Diese Makros beginnen mit Unterstrichen und sind damit für die Standard > Library reserviert und dürfen nicht in eigenem Code genutzt > werden:#ifndef __WS2812_H__ > #define __WS2812_H__ > > #define _FREERUNNING > #define _NUM_LED 20Außerdem sollte man (20) statt 20 schreiben. Die > Funktion Set_Led ist > nicht falsch, aber wäre mit Schleifen statt Wiederholungen "schöner". Danke für den Hinweis, wird sofort umgeaendert. :-)
Rene K. schrieb: > Einen Soll/Ist Wert wird ja nicht mal zwingend benötigt wenn man nicht > unbedingt fein rausfaden will. Ja, das stimmt. Mit Double-Buffering (Soll/Ist) kannst Du halt schon während der Ist-Wert-DMA-Übertragung bereits die nächsten Soll-Werte füllen, ohne auf das Ende der aktuellen DMA-Übertragung zu warten. Wenn's nicht zeitkritisch ist, kann man darauf auch verzichten.
So ich hab es mal versucht umzusetzen, ist natürlich nun ein ziemliches Konstrukt in der ISR:
1 | #define LATCH_TIME = 20
|
2 | |
3 | volatile uint16_t DMA_Runner = 0; |
4 | volatile uint16_t DMA_DeathTime = 0; |
5 | |
6 | void DMA1_Channel1_IRQHandler(void) |
7 | {
|
8 | DMA_Runner++; |
9 | |
10 | if(DMA_Runner > NUM_LED) |
11 | {
|
12 | DMA_DeathTime++; |
13 | if(DMA_DeathTime < LATCH_TIME) |
14 | {
|
15 | for(uint8_t i=0; i<24; i++) |
16 | {
|
17 | ws2812_buffer_short[i] = 0; |
18 | }
|
19 | }
|
20 | else
|
21 | {
|
22 | GPIOA->ODR ^= GPIO_Pin_5; //for debug |
23 | DMA_DeathTime = 0; |
24 | DMA_Runner = 0; |
25 | }
|
26 | }
|
27 | else
|
28 | {
|
29 | Set_Short_Led(0,ws2812_Led_Buffer[DMA_Runner][0], |
30 | ws2812_Led_Buffer[DMA_Runner][1], |
31 | ws2812_Led_Buffer[DMA_Runner][2]); |
32 | }
|
33 | DMA_ClearITPendingBit(DMA1_IT_TC1); |
34 | }
|
Damit habe ich nun nur noch 3 Byte per LED und den 24 Byte Buffer zum rausschieben in die PWM. Laeuft schonmal wunderbar. Morgen Vormittag hab ich nochmal ne Stunde Zeit, da mach ich mich mal ans Doublebuffering.
Hallo Zusammen, ich bin zur Zeit an einer Arbeit und habe probleme dise Bibliothek einzubinden, ich habe das STM32F746 Disco Board. Auf was muss ich genau achten. Timer 3 Channel 1 habe ich wie im Anhang mit dem cubemx konfiguriert. Bitte um Hilfe! Danke und liebe Grüsse AM
Hi, Ja... Also das Problem ist, das diese "Lib" für den STM32F1xx ist. Dort wird auch nicht Timer3 sondern Timer verwendet. Desweiteren wird der Timer dort bereits in der Lib auf die richtigen Werte konfiguriert. Der Timer ist, für die F1 Reihe üblichen, 72Mhz geschrieben. Das richtige Timing ist für die WS LEDs wichtig. Auch wirst du, wenn du dein Projekt über CubeMX anlegst, keinen Erfolg haben - da diese Lib die StdPeriph und nicht die CubeHAL verwendet.
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.