WS2811 mit STM32F1 Blue Pill

OP #7540947
Lesenswert?

Gude,

ich hab mit der STM32CubeIDE ein Projekt mit Timer und DMA geschrieben um WS2811 leds mithilfe eines Bluepill boards anzusteuern. Nur leider flackern diese wie wild und ich kann mir nicht erklären woran es liegt. Ich hoffe jemand kann helfen. Mir ist bewusst, dass ein delay in Kombination mim DMA nicht die beste Idee ist, allerdings flackern die LEDs ohne diesen delay ohne erkennbaren Ziel Zustand. Mit dem delay leuchten die LEDs grundsätzlich in der richtigen Farbe, allerdings nicht stabil. Nach dem Datenblatt der WS2811er brauch er mindestens 280 us LOW pegel für den reset, was ich einfach umgesetzt habe, in dem ich das pwm data array entsprechend mit 230 LOW pegeln fülle (800kHz -> 1.25us pro takt). Gibt sicher schönere wege das zu lösen, aber Speicher ist ausreichend vorhanden. In erster Etappe muss der Spaß erstmal laufen. 400 kHz hab ich auch schonmal ausprobiert, funktioniert auch nicht besser, muss also irgendwas von mir creepy sein....woran ich auch schon gedacht hab wäre manglende Qualität des 8 mhz quarzes auf der bluepill.

Die SysClk ist auf 72Mhz konfiguriert, mit dem HSE Eingang (8 Mhz) und entsprechender Konfiguration in der PLLCLK. (s. Bild clk-config)

Der Timer ist konfiguriert mit: Prescaler: 0 ARR: 90-1 (72Mhz / 90 = 800 KHz) (s. Bild tim-config)

DMA läuft in normal operation, memory to pheriphal Memory mit Byte Pheriphal mit Halfword (s. Bild dma-config)

Nachfolgend der Code:

zunächst das header file:

1
#ifndef __ws281x
2
#define __ws281x
3

4
#include "../config.h"
5
#include "../../Core/Inc/main.h"
6

7
//#define NUM_LED         NUM_LED defined in config.h
8
#define USE_BRIGHTNESS 0
9
#define WS2811_RESET_PERIOD 230
10
#define PWM_DATA_ARR_LENGTH ((24*NUM_LED)+WS2811_RESET_PERIOD) // 24Bits per LED + Reset bits
11

12
void ws281x_init();
13
void ws281x_send();
14

15
void setLED(uint8_t LEDnum, uint8_t red, uint8_t green, uint8_t blue);
16
void setAllLEDs(uint8_t red, uint8_t green, uint8_t blue);
17
void setBrightness (uint8_t brightness);
18

19
void ws281x_reset();
20

21

22
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim);
23

24
#endif

und die zugehörige .c:

1
#include "ws281x.h"
2

3
bool dataSentFlag; // True if DMA action is finished and the next one can start
4

5
uint8_t ledData[NUM_LED][3]; // Store led color data in RGB
6
uint8_t pwmData[PWM_DATA_ARR_LENGTH]; // Store led color and brightness data in bit format for the WS281x Led's
7

8

9
void ws281x_init(void) {
10
  dataSentFlag = 0;
11

12
  setAllLEDs(0,0,0);  // Init led data array
13
  ws281x_send();
14
}
15

16
void ws281x_send (void){
17
  uint16_t indx=0;
18
  uint32_t color;
19

20
  setAllLEDs(255,0,0);  // Init led data array
21

22

23
  for (int i= 0; i<NUM_LED; i++){
24
    // Safe led data in color, depending if brightness ctrl is used or not
25
    color = ((ledData[i][1]<<16) | (ledData[i][2]<<8) | (ledData[i][3]));
26

27
    // Translate RGB data in binary format for WS281x leds
28
    // The clk configuration in the .ioc must be set to:   clk:72 Mhz, Arr: 90-1
29
    for (int i=23; i>=0; i--){
30
      if (color&(1<<i))
31
        pwmData[indx] = 60;    // 2/3 of 90 (SysClk:72MHz/ARR:90 --> TimerFreq:800kHz)
32
      else
33
        pwmData[indx] = 30;    // 1/3 of 90
34

35
      indx++;
36
    }
37
  }
38
  for (int i=0; i<WS2811_RESET_PERIOD; i++){
39
      pwmData[indx] = 0;
40
      indx++;
41
    }
42

43
  HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_1, (uint32_t *)pwmData, indx);
44
  while (!dataSentFlag){};
45
  dataSentFlag = 0;
46

47
  HAL_Delay(10);
48
}
49

50
void setLED(uint8_t LEDnum, uint8_t red, uint8_t green, uint8_t blue){
51
  ledData[LEDnum][0] = green;
52
  ledData[LEDnum][1] = blue;
53
  ledData[LEDnum][2] = red;
54
}
55

56
void setAllLEDs(uint8_t red, uint8_t green, uint8_t blue){
57
  for(uint8_t i = 0; i<NUM_LED;i++){
58
    setLED(i,red,green,blue);
59
  }
60
}
61

62
void ws281x_reset(){
63
  for(int i=0; i<(PWM_DATA_ARR_LENGTH);i++)
64
    pwmData[i] = 0;
65

66
  HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_1, (uint32_t *)pwmData, PWM_DATA_ARR_LENGTH);
67
  while (!dataSentFlag){};
68
  dataSentFlag = 0;
69
}
70

71
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
72
{
73
  HAL_TIM_PWM_Stop_DMA(htim, TIM_CHANNEL_1);
74
  dataSentFlag = 1;
75
}

Danke und viele grüße

Angehängte Dateien:
#7541015
Lesenswert?

Werner P. schrieb:

ich benutze eine LED Matrix mit WS2812 und schicke die Daten mit SPI / DMA raus. Wenn ich SPI auf 4 MHz einstelle dann blinken alle LEDs weiss. Nehme ich 8 MHz dann funktioniert es super. Bei 16 MHz blinken einzelne LEDs wild durcheinander.

Ich mache das für eine Kette von WS2812B auch mit SPI und DMA, wobei ein Byte 2 WS2812-bits entspricht, 1000 für ein 0-bit, 1110 für ein 1-bit. Bittakt ist 3MHz. Dadurch komme ich auf eine Bit-Zeit von 1.33µs, was gut zu den im Datenblatt angegebenen Werten passt. Lediglich die T1H-Zeit ist mit 1µs etwas länger als die spezifizierten 950ns, was aber die Funktion nicht beinträchtigt. Die komplette Impulsfolge wird in einem Puffer abgelegt, mit 160 Null-Bits als Reset-Vorspann. Funktioniert mit 60 LEDs problemlos.

Bei WS2811 ist das Timing langsamer. Es sollte aber mit einer SPI-Frequenz von 1.5 MHz funktionieren, was einer Bitzeit von 0.667µs entspricht: T0H: 1bit , Datenblatt sagt < 0.5+-0.15µs, also ganz knapp daneben, funzt aber vermutlich auch. T0L: 3bits = 2.0µs, entspricht exakt der Spezifikation T1L: 2bits = 1.33µs, Datenblatt sagt 1.3 +- 0.15µs T1H: 2bits = 1.33µs, Spezifikation ist 1.2 +- 0.15µs

Alternativ wäre eine Bitdauer von 250µs möglich, was einem SPI-Takt von 4MHz entspricht. Dann wären allerdings 10 SPI-bits für ein WS2811-Bit nötig, was einen höheren RAM-Bedarf mit sich zieht. T0 entspräche dann der Bitfolge 1100000000, T1 1111100000

OP #7543517
Lesenswert?

Hi Sebastian,

ja an sich sieht die Logic passend aus (s. locig_detail.png) und es gibt auch keine Ausschläge die nicht in der Toleranz der LEDs liegen würden.

Beim rauszoomen fällt mir allerdings auf, dass da anscheinend eine unregelmäßigkeit in der Rate wie die Daten gesendet werden auftritt, bin mir aber nicht sicher ob das vlt auch nur durch die Darstellung oder die Auflösung des USB Logic Analyzers so aussieht. (s. long-time-view.png)

Hab im übrigen in Git ein Repo gefunden, in dem beschrieben ist, dass für WS2811 eine reset dauer von 270 us notwendig ist, und nicht wie im datenblatt von adafruit 50us. Damit kann ich den delay nun auch weglassen, das flimmern ist jedoch weiterhin beständig.

Grüße Luca

Angehängte Dateien:
OP #7543526
Lesenswert?

Passt die Spannung des Datensignals oder brauchst du noch einen Levelshifter?

Gute Frage, an die ich bisher tatsächlich gar nicht gedacht hatte.... laut dem Datenblatt von Adafruit brauchen die LEDs VIH = 0.7VDD. Ich hab an dem WS2811 direkt gemessen, was anliegt wenn der Strip mit 12V versporgt wird, und messe hier 5,4V

Demzufolge wären eigentlich 3,7V notwendig, meine Bluepill gibt natürlich nur 3V3 aus. Ich hab parallel auch den Hersteller BFT-Lightning angeschrieben und dazu befragt.

Zitat:

"Es sollte funktionieren, wenn das Steuergerät (angeschlossen an eine 5-V-Stromversorgung) und der 12-V-Streifen (angeschlossen an eine 12-V-Stromversorgung) separat und getrennt voneinander mit Strom versorgt werden. Aber wir haben nicht versucht zu sehen, ob es bei 3V funktioniert. Vielleicht können Sie es versuchen."

So blöd wies klingt hat mich das auf einen andren Fehler meinerseits aufmerksam gemacht: Ich hab den GND des Strips und der Bluepill nicht miteinander verbunden. Gesagt getan nun funktionierts einwandfrei, bissl widersprüchlich zu den Datenblatt aber ich werd mich nicht beklagen.

Abschließend war das Problem vermutlich die Kombination aus timing problem durch den Delay und die falsch angesetzte reset dauer und die fehlende GND Verbindung. Ich hatte beides beim testen und dem Versuch den Fehler zu finden bereits behoben, allerdings natürlich nicht beides gleichzeitig.

Danke an alle Helfer.

Grüße

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren