Forum: Projekte & Code WS2812 - STM32 PWM/DMA - Easy Lib


von Rene K. (xdraconix)


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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
von Dr. Sommer (Gast)


Lesenswert?

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".

von Rene K. (xdraconix)


Lesenswert?

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. :-)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Rene K. (xdraconix)


Lesenswert?

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.

von AM23 (Gast)


Angehängte Dateien:

Lesenswert?

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

von Rene. K (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.