Forum: Mikrocontroller und Digitale Elektronik WS2812 mit Nucleo und Lib


von Einsteiger (Gast)


Lesenswert?

Hallo,

ich habe jetzt mal angefangen mit den WS2812B LEDS herumzuspielen. 
Hierfür habe ich mir einen LED Ring mit 24 LEDS gekauft. Ich habe wie 
gewünscht +5V und GND mit dem Nucleoboard und den Stripes angeschlossen. 
Im nächsten schritt bin ich dann auf die mbed seite gegangen und habe 
mir folgende Lib angeschaut

https://developer.mbed.org/components/Generic-WS2812-Driver/

Nur leider bekomme ich es mit dieser lib  meine LEDS nicht zum laufen.

Ich ändere in diesem Example nur meinen Pin auf D3 und die Anzahl der 
LEDS auf 24


#define WS2812_BUF 24
#define NUM_COLORS 24
#define NUM_LEDS_PER_COLOR 20


Ich schätze mal das ich irgend ein Timing problem habe. Denn nach 5 
minuten oder mehr warten springen die LEDS an. Wahrscheinlich hat der uC 
dann genau den richtigen takt mal erreicht. Um das zu überprüfen 
benötige ich ein Oszilloskop das habe ich leider nicht. Laut dem 
Datenblatt des WS2812b müssen die Timings folgendermassen sein Seite 3

https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf

In der Lib ist beschrieben das ein Nop ca. 400ns delay macht

also setze ich die Zeit auf

WS2812 ws(D3, 24, 1, 2, 2, 1);

Könntet ihr mir weiterhelfen wie ich am besten weiterkomme ?

Danke!

von Einsteiger (Gast)


Lesenswert?


von Einsteiger (Gast)


Lesenswert?


von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Einsteiger schrieb:
> In der Lib ist beschrieben das ein Nop ca. 400ns delay macht

 Ich kenne Arduino Lib nicht, aber Arduino läuft mit 16MHz, ein Takt
 dauert demzufolge 62,5ns, in Assembler braucht ein NOP genau einen
 Takt, also 62,5ns. Warum das in Arduino C länger dauern sollte, ist
 mir schleierhaft.

 Und auch wie man 400ns mit 62,5ns ohne Rest teilt, müssen dir die
 Authoren erst mal erklären.

von Einsteiger (Gast)


Lesenswert?

Marc V. schrieb:
> Ich kenne Arduino Lib nicht, aber Arduino läuft mit 16MHz, ein Takt
>  dauert demzufolge 62,5ns, in Assembler braucht ein NOP genau einen
>  Takt, also 62,5ns. Warum das in Arduino C länger dauern sollte, ist
>  mir schleierhaft.
>
>  Und auch wie man 400ns mit 62,5ns ohne Rest teilt, müssen dir die
>  Authoren erst mal erklären.

Tut mir leid das ich das nicht vorher gesagt habe, aber ich arbeite mit 
dem Stm32F411 Mikrocontroller bzw dem nucleo board und nicht dem Arduino

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Einsteiger schrieb:
> Tut mir leid das ich das nicht vorher gesagt habe, aber ich arbeite mit
> dem Stm32F411 Mikrocontroller bzw dem nucleo board und nicht dem Arduino

 LOL.
 Und da dauert ein NOP 400ns ?

: Bearbeitet durch User
von Einsteiger (Gast)


Lesenswert?

Ich weiß ja nicht genau wie der Compiler das übersetzt. Ich kann das 
gerade nicht messen, deswegen brauche ich ja euren rat

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Einsteiger schrieb:
> Ich weiß ja nicht genau wie der Compiler das übersetzt. Ich kann das
> gerade nicht messen, deswegen brauche ich ja euren rat

 Ich auch nicht, aber NOP sollte NOP sein und auch so übersetzt
 werden.
 Und bei 100MHz ist NOP 10ns und nicht 400ns...

 Du kannst das aber in einem loop austesten.

von Einsteiger (Gast)


Lesenswert?

Marc V. schrieb:
> Ich auch nicht, aber NOP sollte NOP sein und auch so übersetzt
>  werden.
>  Und bei 100MHz ist NOP 10ns und nicht 400ns...
>
>  Du kannst das aber in einem loop austesten.

Hmm ist schwer das auszutesten, weil ich insgesamt vier parameter 
umändern kann und die können im Bereich von 1 bis 20 sein

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Einsteiger schrieb:
> Hmm ist schwer das auszutesten, weil ich insgesamt vier parameter
> umändern kann und die können im Bereich von 1 bis 20 sein

 Nein, nur NOP in einem loop testen.
 Und schauen was in .lss steht.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Einsteiger schrieb:
> Ich weiß ja nicht genau wie der Compiler das übersetzt.

Das macht man ja auch unabhängig von der Übersetzung mit Timern.

Insbesondere beim Stm32F411!

Entweder mit DMA+UART oder DMA+SPI oder DMA+Bit-Banging.

Schau mal, wie das z.B. bei der WordClock mit WS2812 mit dem 
STM32F411 gemacht wurde.

von Tim  . (cpldcpu)


Lesenswert?

Also bei so einer Implementierung ist es auch eher Glückssache, dass es 
funktioniert.

- Compilersettings
- CPU-Clocks
- Flash-waitstates
- uvm

Haben alle einen Einfluss auf das Timing. Gerade auf schnelleren CM4 
wäre ich sehr skeptisch. Bitbanging ist auf AVR ein sinnvoller Ansatz. 
Bei den Cortexen wüde ich eher Hardwarelösungen einsetzten.

Es gibt bereits etliche Beispiele zu STM32 im Netz.


[code}
    // Begin bit-banging
    for (i = 0; i < FRAME_SIZE * __size; i++) {
        j = 0;
        if (__transmitBuf[i]){
            __gpo = 1;
            for (; j < __oneHigh; j++) {
                __nop();
            }
            __gpo = 0;
            for (; j < __oneLow; j++) {
                __nop();
            }
        } else {
            __gpo = 1;
            for (; j < __zeroHigh; j++) {
                __nop();
            }
            __gpo = 0;
            for (; j < __zeroLow; j++) {
                __nop();
            }
        }
    }
[/code]

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Hi Tim, Du kennst Dich ja mit den WS2812 von allen hier wohl am besten 
aus. Ich traue mich kaum, was hinzuzufügen.

Tim. schrieb:
> Es gibt bereits etliche Beispiele zu STM32 im Netz.

Am weitesten verbreitet scheint Timer-Channel + DMA zu sein. UART mit 
drei Bits pro Byte macht aber mehr Sinn, denke ich.

> Bitbanging ist auf AVR ein sinnvoller Ansatz.
> Bei den Cortexen wüde ich eher Hardwarelösungen einsetzten.

War auch so gemeint: Timer-Hardware triggert DMA-Hardware. Damit bei 
einer defekten LED nicht zuviele LEDs 'dahinter' ausfallen, kann man 
z.B. 8 Bit mit Timer-DMA ins GPIO BSRR parallel ausgeben. Das meinte ich 
mit Bitbanging.

von Einsteiger (Gast)


Lesenswert?

Torsten C. schrieb:
> Schau mal, wie das z.B. bei der WordClock mit WS2812 mit dem
> STM32F411 gemacht wurde.

Ja danke sehr, ich suche gerade noch die Stelle wie da die Timer gesetzt 
werden. Ich habe es noch nicht gefunden..

von Einsteiger (Gast)


Lesenswert?

OK, ich bin jetzt schon am verzweifeln....

ich finde in der Word Clock Projekt nicht die Lib.

Ich möchte einfach eine Lib haben die ich bei meinem Mbed online editor 
mit einbinden kann und dann einfach die LEDS steuern kann. Sprich LED 
nummer XX soll in Farbe Rot leuchten ...

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Einsteiger schrieb:
> Sprich LED nummer XX soll in Farbe Rot leuchten ...

Also:
1
ws2812_set_led(uint_fast16_t n, WS2812_RGB * rgb)
https://www.mikrocontroller.net/svnbrowser/wordclock24h/src/ws2812/ws2812.c?revision=28&view=markup#l295

Aber wie das im Mbed online editor geht?
Vielleicht kann ein anderer helfen?

Frank hat das mit EM::Blocks gemacht.

Ich würde ja einen Inverter an den UART-TX anschließen und die Bits 
einfach ohne fremde Bibliotheken aus dem UART schieben, siehe auch:
Beitrag "WS2812B über USB-UART ansteuern"

: Bearbeitet durch User
von Einsteiger (Gast)


Lesenswert?

Torsten C. schrieb:
> Einsteiger schrieb:
>> Sprich LED nummer XX soll in Farbe Rot leuchten ...
>
> Also:ws2812_set_led(uint_fast16_t n, WS2812_RGB *
> 
rgb)https://www.mikrocontroller.net/svnbrowser/wordclock24h/src/ws2812/ws2812.c?revision=28&view=markup#l295
>
> Aber wie das im Mbed online editor geht?
> Vielleicht kann ein anderer helfen?
>
> Frank hat das mit EM::Blocks gemacht.
>
> Ich würde ja einen Inverter an den UART-TX anschließen und die Bits
> einfach ohne fremde Bibliotheken aus dem UART schieben, siehe auch:
> Beitrag "WS2812B über USB-UART ansteuern"

Danke erst einmal vorab... Ich weiß nicht warum, aber ich bekomme es 
nicht hin über eclipse  den STM zu programmieren.. -.- Deswegen habe ich 
mich für die mbed online variante entschieden.

Ich habe es nach der Anleitung probiert...
http://www.carminenoviello.com/2014/12/28/setting-gcceclipse-toolchain-stm32nucleo-part-1/

von js (Gast)


Lesenswert?

probiere mal das 'cylon' Beispiel in mbed, hatte bei mir auf Anhieb mit 
einer 300er Kette funktioniert:
https://developer.mbed.org/users/AndyA/code/cylon/

du must das die chainLen auf deine 24 setzen und im main code in der 
initialisierung die 3 Ketten auf Längen von zB 6..8 stellen.

von js (Gast)


Lesenswert?

Nachtrag: die benutzte wsDrive Lib arbeitet mit SPI, du musst also einen 
SPI MOSI Pin am Nucleo benutzen.
Die (Burst)SPI Variante ist besser weil die nicht die ganze CPU 
blockiert.

von Einsteiger (Gast)


Lesenswert?

js schrieb:
> probiere mal das 'cylon' Beispiel in mbed, hatte bei mir auf Anhieb mit
> einer 300er Kette funktioniert:
> https://developer.mbed.org/users/AndyA/code/cylon/
>
> du must das die chainLen auf deine 24 setzen und im main code in der
> initialisierung die 3 Ketten auf Längen von zB 6..8 stellen.

hmmm... irgendwie bin ich anscheinend auch dafür zu blöd

hier mein Programmcode
1
 #include "mbed.h"
2
 #include "wsDrive.h"
3
4
 // update period in ms
5
 #define updatePeriod 100
6
  // number of LEDs
7
 #define chainLen 24
8
9
 //DigitalIn dummy(D11,D11); // first activate the pulldown on the pin.
10
 wsDrive ledDriver(D11,D12,D13); // create the SPI bus. You can normally list the MISO and CLK as NC but some mbed library versions don't like that
11
12
 // pixel storage buffer
13
 pixelInfo pixelData[chainLen];
14
15
 Timer updateRateTimer;
16
17
 void blankBuffer(pixelInfo *Ptr)
18
 {
19
    memset( (void *)Ptr, 0, chainLen*sizeof(pixelInfo) );
20
 }
21
22
 void setPixel(unsigned int index, pixelInfo *colourToUse) {
23
   if (index < chainLen) {
24
     pixelData[index].R = colourToUse->R;
25
     pixelData[index].G = colourToUse->G;
26
     pixelData[index].B = colourToUse->B;
27
   }
28
 }
29
30
 void clearPixel(unsigned int index) {
31
   if (index < chainLen) {
32
     pixelData[index].R = 0;
33
     pixelData[index].G = 0;
34
     pixelData[index].B = 0;
35
   }
36
 }
37
38
int main () {
39
40
  int litLed = 7;
41
42
  pixelInfo colour;
43
  colour.R = 0x80;
44
  colour.G = 0x00;
45
  colour.B = 0x00;
46
47
  // Tell the driver where the data is stored
48
  ledDriver.setData(pixelData, chainLen);
49
50
  // Set the buffer to the pattern we want
51
  blankBuffer(pixelData);
52
  setPixel(litLed, &colour);
53
54
  updateRateTimer.start();
55
  while (true) {
56
57
    ledDriver.sendData(); // send the LED data
58
59
    // modify the buffer ready for the next update
60
    clearPixel(litLed);
61
    litLed++;
62
    if (litLed == chainLen)
63
      litLed = 0;
64
    setPixel(litLed, &colour);
65
66
    // wait until the correct time since the last update...
67
    while (updateRateTimer.read_ms() < updatePeriod) {
68
    }
69
70
   updateRateTimer.reset();
71
   }
72
}

Aber danke schon einmal vorab... Wie beschrieben, setze ic hdie 
Chainlength auf 24 und in der Init die Variable ...

Ich habe auch mit dem Ohmmeter mal nachgemessen , die Data in Leitung 
der Leds hat kontakt mit dem Mosi Pin des uC

von Einsteiger (Gast)


Lesenswert?

Ich habe es sowohl mit und Ohne

DigitalIn dummy(D11,PULLDOWN); // first activate the pulldown on the 
pin.

ausprobiert

von Einsteiger (Gast)


Lesenswert?

Also ich bekomme zwa rmit der Lib die LEDs eingeschaltet, aber kann sie 
nicht in der Farbe Variieren.... Bei mir leuchten alle LEDS WEiß und ich 
muss anstelle der Chain length von 24 eher 48 angeben, damit alle 
leuchten

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Wenn Du noch keinen hast, könntest Du Dir einen ebay 272155971624 
besorgen und mal nachmessen, woran es liegt.

von js (Gast)


Lesenswert?

Einsteiger schrieb:
> Also ich bekomme zwa rmit der Lib die LEDs eingeschaltet, aber kann sie
> nicht in der Farbe Variieren....

dein Code sieht ok aus, der dummy In kann weg. Habe mir die mbed Lib für 
den F411RE angesehen, das Problem ist das der SPI Clock nur grob über 
den Prescaler eingestellt wird. Das Timing ist korrekt wenn der 2,4 MHz 
beträgt, die Lib rundet den aber auf 1,56 MHz ab. Mit dem 
nächstkleineren Prescaler bist du bei 3,13 MHz, das gibt Bitzeiten von 
320 / 640 ns. Auch noch ausserhalb der Spec und ohne Gewähr das es geht, 
aber das wäre eine einfache Änderung:

in wsDrive.cpp
1
void wsDrive::sendData()
2
{
3
    // frequency(2400000); // on STM32F411RE rounded to 1560000 Hz
4
    frequency(3130000);    // test, only for STM32F411RE
5
    format(12);
6
    setFormat();

Für eine saubere Lösung mit dem SPI müsste man den Takt anders 
herleiten. Ich hatte die Lib mit einem LPC Board benutzt, da wird der 
Takt genau auf die gewünschte Frequenz gestellt.

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.