Forum: Mikrocontroller und Digitale Elektronik Lightweight WS2811/WS2812 Library


von Tim  . (cpldcpu)


Lesenswert?

Hallo zusammen,

da mir die bisherigen Ansätze zur Ansteuerung der WS2812 RGB-LEDS zu 
umständlich (Timergefrickel), zu speziell (Arduino, 100% ASM, C++) oder 
zu groß waren, habe ich noch einmal von vorne angefangen.

Bisher sieht es recht vielversprechend aus. Mit einem reinen 
Bitbanging-Ansatz lassen sich auch auf einem 8MHz AVR ohne 
Loop-Unrolling die notwendigen Timings erreichen. Die compilierte 
C-Routine ist bisher gerade einmal 34 bytes groß.

Bisher habe ich nur an einer einzelnen LED testen können. Hat jemand 
Lust, den Code auch einmal an einem LED-Streifen zu testen?

Die Nutzung ist ziemlich einfach:
- AVR auf 8Mhz konfigurieren. Sollte auf allen außer XMEGA und Attiny 
4/5/9/10/20/40 laufen.
- Code mit Optimierungen compilieren (Mind. -O1)
- Portaddresse und Pin in die Defines eintragen.
- Der Routine eine Addresse auf ein Farb-Array (3 Bytes pro LED, 
Reihenfolge GRB) sowie die Länge des Arrays übergeben.
- Nach jedem Update mindesten 50µs warten.

Ich habe vor, das ganze als Library zu verpacken und auch noch an andere 
Taktgeschwindigkeiten anzupassen.
1
/*
2
  Timing optimized for 8Mhz AVR (excl. XMEGA and reduced instruction set)
3
4
  The total length of each bit is 1.25µs (10 cycles @ 8Mhz)
5
  * At 0µs the dataline is pulled high.  (cycle 4)
6
  * To send a zero the dataline is pulled low after 0.375µs (4+3=7 cycles).
7
  * To send a one the dataline is pulled low after 0.625µs (4+5=9 cycles).
8
9
  10 cycles can not be reached without loop unrolling, or by using byte
10
  writes to the ports. However since critical the timing between the rising and 
11
  falling edge is correct, it seems to be acceptable to slightly increase 
12
  bit timing
13
  
14
  Final timing: 
15
  * 11 cycles for bits 7-1
16
  * 17 cycles for bit 0    
17
*/
18
19
#define ws2812_port 0x18  // Number of the data port register
20
#define ws2812_pin 4    // Number of the data out pin
21
22
23
void ws2812_sendarray_8Mhz(uint8_t *data,uint16_t datlen)
24
{
25
  uint8_t curbyte,ctr;
26
  
27
  while (datlen--) {
28
    curbyte=*data++;
29
    
30
    asm volatile(
31
    "    ldi  %0,8    \n\t"   
32
    "loop%=:lsl  %1      \n\t"   
33
    "    dec  %0      \n\t"    
34
    "    sbi  %2,  %3    \n\t"   
35
  
36
    "    brcs .+2    \n\t"   
37
    "    cbi  %2,  %3    \n\t"    
38
                   
39
    "    brcc .+2    \n\t"   
40
    "    cbi  %2,  %3    \n\t"   
41
    "    brne loop%=    \n\t"   
42
    :  "=&d" (ctr)
43
    :  "r" (curbyte), "I" (ws2812_port), "I" (ws2812_pin)
44
    );
45
    
46
    // loop overhead including byte load is 6+1 cycles
47
  }
48
}

von Tim  . (cpldcpu)


Lesenswert?

Hier übrigens die inner-loop mit Taktzyklen. Etwas frickelig war die 
unterschiedliche Laufzeit der Sprungbefehle. So wie es jetzt 
implementiert ist, heben sich die Verzögerungen beider Befehle 
gegenseitig auf.

Bei 8Mhz funktioniert das ganze nur, weil die Dauer der "Low" Periode 
anscheinend relativ unkritisch ist. Theoretisch könnte man durch 
Loop-Unrolling das Timing auch vollständig korrekt umsetzen können - 
aber so lange das nicht notwendig ist...

[code]
        "    ldi  %0,8       \n\t"    // 0

        "loop%=:lsl  %1      \n\t"    // 1     Datenbit ins Carry
        "    dec  %0         \n\t"    // 2     Schleifenzähler in Z-Flag
        "    sbi  %2,  %3    \n\t"    // 4

        "    brcs .+2        \n\t"    // 5l / 6h
        "    cbi  %2,  %3    \n\t"    // 7l / -    Überspringen bei C=1
                                      // 7l / 6h
        "    brcc .+2        \n\t"    // 9l / 7h
        "    cbi  %2,  %3    \n\t"    // -  / 9h   Überspringen bei C=0
        "    brne loop%=     \n\t"    // 11 loop /10nt  Weiter, wenn Z=1
[code]

von Matthias H. (hallamen)


Lesenswert?

Die Routine funktioniert bei mir mit 12 Leds einwandfrei, danke dafür!
Ich finde diesen Ansatz ohne Timer ganz praktisch (vor allem, wenn nur 
wenige Leds gesteuert werden sollen).

Ich habe deine Funktion auf 16MHz 'verlängert', vielleicht kanns ja 
jemand brauchen. Diese wurde ebenfalls an 12 Leds getestet.

1
#define ws2812_port 0x18  // Number of the data port register
2
#define ws2812_pin 4    // Number of the data out pin
3
4
void ws2812_sendarray_16Mhz(uint8_t *data,uint16_t n)
5
{
6
  uint8_t curbyte,ctr;
7
  
8
  while (n--) {
9
    curbyte=*data++;
10
    
11
    asm volatile(
12
        "    ldi  %0,8       \n\t"    // 0
13
        "    nop\n\t"
14
15
        "loop%=:lsl  %1      \n\t"    //  1     Datenbit ins Carry
16
        "    dec  %0         \n\t"    //  2     Schleifenzähler in Z-Flag
17
        "    sbi  %2,  %3    \n\t"    //  4
18
19
        "    nop\n\t"                  //  5 
20
        "    nop\n\t"                  //  6
21
22
        "    brcs .+2        \n\t"    //  7l / 8h
23
        "    cbi  %2,  %3    \n\t"    //  9l / -    Überspringen bei C=1
24
25
        "    nop\n\t"                  // 10l /  9h
26
        "    nop\n\t"                  // 11l / 10h
27
        "    nop\n\t"                  // 12l / 11h
28
        "    nop\n\t"                  // 13l / 12h
29
 
30
        "    brcc .+3        \n\t"    // 15l / 13h
31
        "    cbi  %2,  %3    \n\t"    // -  / 15h   Überspringen bei C=0
32
33
        "    nop\n\t"                  // 16 
34
        "    nop\n\t"                  // 17 
35
        "    nop\n\t"                  // 18 
36
        "    nop\n\t"                  // 19 
37
38
        "    brne loop%=     \n\t"    // 11 loop /10nt  Weiter, wenn Z=1
39
40
    :  "=&d" (ctr)
41
    :  "r" (curbyte), "I" (ws2812_port), "I" (ws2812_pin)
42
    );
43
    
44
    // loop overhead including byte load is 6+1 cycles
45
  }
46
}

von Tim  . (cpldcpu)


Lesenswert?

Hallo Matthias,

freut mich, dass die Routine für Dich nützlich ist und auch mit mehr als 
einer LED funktioniert. Das hat mich glatt motiviert, den aktuellen 
Stand der Library zu veröffentlichen. Ich habe in der Zwischenzeit den 
Code auch noch für eine Reihe anderer Taktgeschwindigkeiten angepasst.

Download hier: 
https://github.com/cpldcpu/light_ws2812/tree/master/light_ws2812


1
light_ws2812
2
============
3
4
Light wight library to control WS2811/WS2812 based LEDS and LED Strings for 8-Bit AVR microcontrollers.
5
6
7
8
Description
9
===========
10
11
This is a small Ansi-C library to control WS2811/WS2812 based RGB Leds and strings. Only the 800kHz
12
high-speed mode is supported. This library uses a bit-banging approach with cycle optimized assembler
13
innerloops. Some advantages of this approach compared to existing solutions are:
14
15
  * Compatible to all AVR MCUs since it does not rely on special periphery.
16
  * Low hardware footprint: Does not rely on any timer or the USI
17
  * Low software footprint: Size optimized assembler without unrolled loops (<50 bytes in most cases)
18
  * No configuration needed
19
  * Supports reduced core AVR such as Attiny 4/5/9/10
20
  * Arduino or C++ not required
21
22
A disadvantage of this approach is that the code has to be hand optimized for each cpu clock. However,
23
a number of different routines are provided with support cpu clocks from 8Mhz to 16Mhz (standard AVR)
24
or 4MHz to 8Mhz (reduced core).
25
26
Usage
27
=====
28
29
- Add "light_ws2812.c" and "light_ws2812.h" to your project
30
- Change ws2812_port and ws2812_pin in the include file according to the I/O pin you are using.
31
- Uncomment the #define appropiate for your CPU core and clock settings. If you exact clock is
32
  not supported, try a higher or lower clock setting. The WS2811 controller chip is tolerant to
33
  some timing inaccuracy.
34
- Please use at least optimizations settings -O1 to compile.
35
36
A simple example is provided as "test_rgb_blinky.c"
37
38
Release History
39
================
40
41
v0.3 2013/05/06 - Initial release
42
43
Please find updates on https://github.com/cpldcpu/light_ws2812
44
45
bug reports etc: cpldcpu@gmail.com

von Fallobst (Gast)


Lesenswert?

Ein paar Anmerkungen:

- Was spricht gegen dirketes schreiben auf die Ports? Damit kann das 
Timing ab 8 Mhz ohne Loop-unrolling eingehalten werden 
(Beitrag "Re: C komisches Verhalten"). PWM-Ausgänge und 
andere Peripherie wird durch die Port-Register nicht beeinflusst. 
Interrupts müssen sowieso gesperrt werden. Ich sehe keinen Nachteil 
dabei. Mit dem direkten Schreiben könntest du deine Lib wahrscheinlich 
allgmein noch etwas optimieren.
- mehrere nops kann man zusammenfassen um Speicherplatz zu sparen :
  2xnop = rjmp .+2
  3xnop = lpm (wobei r0 zerstört wird)

von Tim  . (cpldcpu)


Lesenswert?

Hallo Fallobst,

vielen Dank für die Anmerkungen! Ich habe, basierend auf Deinem Input, 
gleiche eine v0.4 erstellt.

- Code durch rjmp verkürzt.
- Die Interrupts werden jetzt optional gesperrt.

Direktes Schreiben habe ich allerdings noch nicht implementiert. Ein 
Nachteil ist nämlich längerer Code und die Benutzung von mehr Registern. 
Bis 8Mhz funktioniert es noch ohne, auch ohne Loop-Unrolling. Auf den 
reduced core AVR benötigen CBI/SBI nur einen Taktzyklus, so dass man 
dort generell keinen Vorteil hat. Direktes Schreiben hilft m.E. nur bei 
<8Mhz auf den normalen Cores. Dafür werde ich bei Gelegenheit noch eine 
Routine implementieren...

von Tim  . (cpldcpu)


Lesenswert?


von Tim  . (cpldcpu)


Lesenswert?

Ich habe noch einen Bug im Timing gefunden, der sich durch die 
Optimierungen mit eingeschlichen hatte. Interessanterweise hat der Code 
trotzdem funktioniert...

v0.5 jetzt hoffentlich wieder fehlerfrei:

https://github.com/cpldcpu/light_ws2812/tree/master/light_ws2812

von Tim  . (cpldcpu)


Lesenswert?

Ich habe eben v0.6 hochgeladen. Die neue Version unterstützt beliebige 
Pins auf einem Port durch Bitmasken. Außerdem wird jetzt 4 Mhz auch auf 
den normalen AVRs unterstützt.

https://github.com/cpldcpu/light_ws2812

1
  - Major update: Changed all port accesses from SBI/CBI to OUT. This removes
2
    a timing inconsistency between reduced core AVR and standard AVR,
3
    avoiding separate implementations for different cores. A disadvantage is
4
    increased register usage.
5
  - Added a "ws2813_sendarray_mask" function which allows to pass a bitmask
6
    for the selected port. This allows controlling up to 8 independent LED
7
    strips.
8
  - Removed functions for interrupt handling. Avoiding interference with
9
    interruprs is now up to the user. 
10
  - 4 MHz clock speed is now also supported for standard core AVRs.
11
  - 12 MHz implementation is still untested

von Mario P. (mariopieschel)


Lesenswert?

In den Teilen für 8MHz und 12MHz ist ein kleiner Fehler:

Zeile 138 " brvs exit%=  \n\t"  // 14
und
Zeile 191 " brvs exit%= \n\t"  // 11

nicht "brvs" sondern "brcs"
Das Carry-Flag abfrage nicht Overflow.
So benötigt ein Durchlauf 1/2s.

Übrigens geht auch die 9,6MHz-Variante bei 8MHz.

Super Arbeit, hat mir viel Zeit gespart.

von Tim  . (cpldcpu)


Lesenswert?

Hallo Mario,

ups, guter Punkt. Erstaunlich dass die LEDs das ohne Glitches mitgemacht 
haben. Das Protokoll ist eben doch robuster als man denkt. Habe es 
gleich gefixed und v0.8 hochgeladen.

https://github.com/cpldcpu/light_ws2812/tree/master/light_ws2812
1
- v0.7 2013/05/28
2
  - Optimized timing and size of 8 and 12 Mhz routines. All routines are within 
3
    datasheet specs now, except of 9.6 Mhz which is marginally off but works under
4
    all test conditions.  
5
- v0.8 2013/06/03
6
  - 9.6 Mhz implementation now within timing specifications.
7
  - brvs->brcs. Loops terminate correctly (thanks to Mario Pieschel).

von Tim  . (cpldcpu)


Lesenswert?

>Übrigens geht auch die 9,6MHz-Variante bei 8MHz.

Ja, es gehen so einige Dinge, die laut Datenblatt nicht erlaubt sind :) 
Aber es kann ja immer sein, dass man mal eine Bauteilecharge erwischt, 
die etwas weniger tolerant ist. Die v0.8 schafft es immerhin jetzt für 
alle Taktgeschwindigkeiten das Timing nach Datenblatt einzuhalten. Das 
ist bei den meisten anderen Lösungen nicht so (FastSPI-lib etc.)

von Nils N. (hagbard)


Lesenswert?

Vielen vielen Dank für die Lib!
Hat mir gerade sehr geholfen meine Stripes zu testen.
Es blinkt mit 40 LEDs ohne Probleme auf einem Atmega32 mit 16 MHz :-)
Bei mehr steigt er aus, ob wegen zu viel Strom oder Timing, kann ich 
gerade nicht sagen.

Beitrag "Re: [Mitbestellung] SMD5050 RGB-LED mit integriertem 8-bit PWM Controller"

von Tim  . (cpldcpu)


Lesenswert?

Hi Nils,

freut mich dass es so gut klappt!

Man kann evtl. recht einfach überprüfen, ob es am Strom liegt: Reduziere 
doch einfach mal die Anzahl der angeschalteten LEDS und die Helligkeit. 
Wenn Du dann mehr ansteuern kannst ist die Situation relativ klar. Eine 
LED zieht bei voller Helligkeit ca 60mA. Pro USB Port sind da eigentlich 
nicht mehr als 10 LEDs drin...

Ansonsten würde ich auch defekte LEDS nicht komplett ausschließen. 
(Damit hatte ich bei meinen handgelöteten Strips zu kämpfen.)

von Nils N. (hagbard)


Lesenswert?

Liegt wohl am Strom.
Der 4m Stripe (240 LEDs!) geht, wenn ich z.B. eine LED durchlaufen 
lasse.
Muss aber fürs Schreiben auf die LEDs die Interrupts sperren, sonst hab 
ich Disco...
1
cli();
2
ws2812_sendarray(&led[0],3*WS2812_LEDCOUNT);
3
sei();

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Nils Nachname schrieb:
> Muss aber fürs Schreiben auf die LEDs die Interrupts sperren, sonst hab
> ich Disco...

Wenn du dir das Sperren nicht leisten willst, ist es vllt. besser den 
Library Aufruf selbst in einen (Timer?)Interrupt zu tun. Dann ist sicher 
gestellt, das er nicht unterbrochen wird und Sperren ist unnötig.

von Tim  . (cpldcpu)


Lesenswert?

Ich habe es mit meinem 4m String auch getestet: Bei niedrigster 
Helligkeit (RGB= {0,0,1}) kann man mit einem USB Port den ganzen 
Streifen mit 240 LEDs betreiben. Bei voller Helligkeit ist nach ca 20 
LEDs Schluss.

von Tim  . (cpldcpu)


Lesenswert?

Das man Interrupts während des Sendens verhindern muss sollte eigentlich 
klar sein. Etwas "professioneller" geht es mit <util/atomic.h>. Der 
erzeugte Code ist am Ende jedoch der gleiche wie im Beispiel von Nils.

1
#include <util/atomic.h>
2
3
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
4
{
5
     ws2812_sendarray(..);
6
}

von Nils N. (hagbard)


Lesenswert?

Matthias Sch. schrieb:
[...]
> Wenn du dir das Sperren nicht leisten willst, ist es vllt. besser den
> Library Aufruf selbst in einen (Timer?)Interrupt zu tun. Dann ist sicher
> gestellt, das er nicht unterbrochen wird und Sperren ist unnötig.

Für einen Timerinterrupt ist mir das Senden dann doch zu viel/lang bei 
240 LEDs.
Obwohl ich gerade gar nicht genau weiß, wie lang es eigentlich dauert.

Aber die 4m waren auch nur zum Testen der LEDs... obwohl... man weiß ja 
nie. ;-)

von chris (Gast)


Lesenswert?

Sehr schön :-) Das gefällt mir deutlich besser als die FastSPI des 
Arduino.

Nur: vielleicht sollte man den Thread in die Codesammlung schieben, dort 
findet man Codestücke besser.

von Peter K. (peterka2000)


Lesenswert?

Bei mir zeigt es an: expected ; before led_buffer. Mein Code:
1
#define F_CPU 8000000
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <stdint.h>
5
#include "light_ws2812.h"
6
7
struct CRGB{uint8_t green; uint8_t red; uint8_t blue; };
8
struct CRGB led_buffer[1];
9
10
int main(void){
11
  
12
  while(1){
13
    led_buffer[0].red = 0;
14
    led_buffer[0].green = 255
15
    led_buffer[0].blue = 0;
16
    ws2812_sendarray(&led_buffer[0], 3);
17
    _delay_ms(300);
18
  }
19
  return 0;
20
}

von Christian H. (ch-hunn)


Lesenswert?

Peter K. schrieb:

> Bei mir zeigt es an: expected ; before led_buffer. Mein Code:

> led_buffer[0].green = 255

 Ja logisch, denn dieser Zeile fehlt zum Schluss ein Semikolon ;-)

von Peter K. (peterka2000)


Lesenswert?

Wenn man zu blöd ist, sich den Code nochmal anzugucken ...

von Peter K. (peterka2000)


Lesenswert?

Wenn ich jetzt aber
1
#define F_CPU 8000000
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <stdint.h>
5
#include "light_ws2812.h"
6
7
struct CRGB{uint8_t green; uint8_t red; uint8_t blue; };
8
struct CRGB led_buffer[1];
9
10
int main(void){
11
  
12
  DDRD |= (1 << PD6);
13
  
14
  while(1){
15
    led_buffer[0].red = 255;
16
    led_buffer[0].green = 255;
17
    led_buffer[0].blue = 255;
18
    ws2812_sendarray(&led_buffer[0], 3);
19
    _delay_ms(500);
20
  }
21
  return 0;
22
}
 mache, blitzt die Led nur alle 500 ms auf und geht gleich wieder aus.

von Tim  . (cpldcpu)


Lesenswert?

Peter K. schrieb:
> mache, blitzt die Led nur alle 500 ms auf und geht gleich wieder aus.

* Stimmt die CPU Taktgeschwindigkeit? Ist in WS2812.h das richtige 
Define gesetzt?

* Hat die LED einen Bypasskondensator? (Die WS2812 sind teilweise 
ziemlich empfindlich)

von Peter K. (peterka2000)


Lesenswert?

Tim .  schrieb:
> Peter K. schrieb:
>> mache, blitzt die Led nur alle 500 ms auf und geht gleich wieder aus.
>
> * Stimmt die CPU Taktgeschwindigkeit? Ist in WS2812.h das richtige
> Define gesetzt?
ja, das ist schon OK. Das passiert nur, wenn alle Werter gleich sind.
> * Hat die LED einen Bypasskondensator? (Die WS2812 sind teilweise
> ziemlich empfindlich)
Du meinst nen 100n? Mal probieren.
OK, es liegt tatsächlich daran. Ich hab verbotenerweise auch an den 
Mega8 kein 100n dran. Bitte jetzt nicht hauen.

von Werner (Gast)


Lesenswert?

Mal eine Frage zur Helligkeitseinstellung, auch wenn es hier etwas 
Offtopic ist.
Da die LEDs ja RGB Daten erwarten, müsste ich vermutlich für eine 
saubere Helligkeitsänderung ohne Farbwertänderung einen anderen Farbraum 
als Zwischenschritt verwenden, oder wie macht ihr das?
HSV oder L*a*b* wären da vermutlich geeignet, aber evtl. etwas 
rechenaufwändig?

von Tim  . (cpldcpu)


Lesenswert?

Es gibt ein weiteres Update der Library: Jetzt  mit experimentellen 
Support for ARM Cortex Microcontroller. Bisher habe ich die Library mit 
dem LPC810 getestet.

Video: http://www.youtube.com/watch?v=Uwxt7SuSV7Y
Github Repository: https://github.com/cpldcpu/light_ws2812

von chris (Gast)


Angehängte Dateien:

Lesenswert?

Hier angepasste Version für den Arduino Uno.

von Tim  . (cpldcpu)


Lesenswert?

chris schrieb:
> Hier angepasste Version für den Arduino Uno.

Vielen dank!

von chris (Gast)


Lesenswert?

Gerne geschehen ;-)
Noch ein kleiner Hinweis: In der geposteten Version habe ich die weiter 
oben schon einmal erwähnte Interrupt-Sperre vergessen. Dadurch kommt es 
( sehr selten ) zu einem flackern. Wer das verhinder will, solte also 
"cli() und sei() " um die Sendefunktion bauen.

von Martin S. (drunkenmunky)


Lesenswert?

Servus,

versuche gerade den Code zu verstehen. Beschäftige mich nicht mit AVRs, 
will aber so eine Lib für PICs machen.

Vielleicht könnte einer den Assembler Code etwas kommentieren, damit 
man's einfacher versteht?

Danke!

von Tim  . (cpldcpu)


Lesenswert?

Martin S. schrieb:
> versuche gerade den Code zu verstehen. Beschäftige mich nicht mit AVRs,
> will aber so eine Lib für PICs machen.
>
> Vielleicht könnte einer den Assembler Code etwas kommentieren, damit
> man's einfacher versteht?

Ich habe einen Wiki-Artikel zur WS2812 Ansteuerung geschrieben. 
Vielleicht hilft er Dir weiter...

https://www.mikrocontroller.net/articles/WS2812_Ansteuerung

von Erlang E. (erlang)


Lesenswert?

Hey Leute,

ich nutze o.g. Lib. Bis 100 LEDs klappt alles super, danach gibts aber 
(gerade bei unterschiedlichen Farben je LED) Probleme. LEDs hinter 
nummer 100 werden nicht mehr angesprochen. Verwende nen Atmega328 mit 16 
Mhz. Mit der Adafruit Lib klappt alles.
Jemand ähnliche Probleme?
Viele Grüße

von Tim  . (cpldcpu)


Lesenswert?

Komische Sache, da so etwas nicht durch Timing-Probleme erklärt werden 
kann. Bei mir hat es mit einem kompletten Streifen (240 LEDs) Problemlos 
funktioniert. Ein paar Fragen:

- Welche Taktgeschwindigkeit hat die CPU? Ist die in der Lib richtig 
gesetzt?

- Hat Dein String eine ausreichende Stromversorgung? Probiere doch 
einmal den String mit schwacher Intensität zu beschreiben. Wenn es dann 
geht, wird es an der Stromversorgung liegen.

- Die Lib sperrt im Gegensatz zur Neopixel lib keine Interrupts. Nutzt 
Du intererupts? Funktioniert es, wenn Du diese manuell sperrst? (sei(), 
cli())

von Erlang E. (erlang)


Lesenswert?

Hallo Tim,

danke für deine schnelle Antwort. Ich habe das Problem jetzt mal etwas 
weiter untersucht und isoliert, vielleicht finden wir so besser eine 
Lösung bzw. den Fehler in der Lib (falls es einen gibt).

> - Welche Taktgeschwindigkeit hat die CPU? Ist die in der Lib richtig
> gesetzt?


Die CPU läuft auf 16 Mhz. Es ist ein ArduinoNano Klon. Ich verwende die 
Routine die mittels "ws2812_16MHz" aktiviert wird.

> - Hat Dein String eine ausreichende Stromversorgung? Probiere doch
> einmal den String mit schwacher Intensität zu beschreiben. Wenn es dann
> geht, wird es an der Stromversorgung liegen.

Das Netzteil ist recht kräftig. Der Fehler besteht aber unabhängig von 
der Intensität.
(Details siehe unten)


> - Die Lib sperrt im Gegensatz zur Neopixel lib keine Interrupts. Nutzt
> Du intererupts? Funktioniert es, wenn Du diese manuell sperrst? (sei(),
> cli())

Nein ich nutze in diesem Code keine Interrupts. Habe sie aber auch 
sicherheitshalber
gesperrt.

Ich habe mal einen minimal Code zum testen geschrieben. Dieser lässt 
alle LEDs ausgeschaltet und schaltet genau eine (an TARGET_POS) an. Wenn 
TARGET_POS <= 85 ist, funktioniert alles wie zu erwarten. Wenn 
TARGET_POS > 85 ist, dann bleibt die entsprechende LED dunkel. Dafür 
geht eine LED am Anfang des Stripes (in einer anderen Farbe) an.

Ich habe mit genau den gleichen Rahmenbedingungen die NeoPixel Library 
getestet und es gehen alle Positionen problemlos. Vielleicht doch ein 
Timing Problem? Oder irgendwelche Störungen? Ist die NeoPixel library so 
viel robuster umgesetzt?
1
    // Define and prepare hardware
2
    #define     COUNT           119
3
    #define     TARGET_POS      85
4
5
    DDRC |= (1 << ws2812_pin);
6
7
    cli();
8
9
    // Prepare buffer
10
    uint8_t buf[3 * COUNT];
11
    memset(buf, 0, 3 * COUNT);
12
13
    // Set pixel
14
    uint8_t bufPos = 3 * TARGET_POS;
15
    buf[bufPos] = 0;
16
    buf[bufPos + 1] = 0;
17
    buf[bufPos + 2] = 255;
18
    ws2812_sendarray(buf, 3 * COUNT);

Vielen Dank für eure Hilfe,
Erlang

von Erlang E. (erlang)


Lesenswert?

Hallo Tim,
vielen Dank für deine Hilfe.

Tim .  schrieb im Beitrag #3312722:
> das sieht soweit alles ok aus. Allerdings werden interrupts mit sei()
> gesperrt und mit cli() wieder freigegeben. Außerdem solltest Du nach dem
> Aufruf von ws2812_sendarray 50us warten. Vielleicht geht es dann?

Habe den Code gerade noch einmal angepasst mit cli() statt sei(). 
Weiterhin gleiches
Verhalten. Nach dem ws2812_sendarray Befehl wechselt mein Testprogramm 
in
eine leere while(True) Schleife, daher warte ich deutlich länger als 
50us ;-).

Interrupts kommen definitiv nicht vor. Sehr seltsam alles.

Tim .  schrieb im Beitrag #3312722:
> Dein Fehler klingt, als wenn die Ausführung des calls
> nach einer gewissen Zeit einfach kurz unterbrochen wird, so dass die
> WS2812 resetten.

Genau. Bis 85 klappt alles. Sobald es dann 86 sind, wird mitten zwischen 
zwei bytes resettet, was dazu führt das eine LED weiter vorne (mit 
"falscher" Farbe) angeht. Mein Testcode ist maximal einfach, aber 
trotzdem klappt es nicht. Mit NeoPixel Lib alles wie gewünscht. Komisch 
komisch...

von Tim  . (cpldcpu)


Lesenswert?

Hi Phillip,

eigentlich sieht das alles ok aus. Einen Timingfehler kann ich mir kaum 
vorstellen, da das Signal in den LEDs regeneriert wird. Wenn die Erste 
LED funktioniert, sollte es mit allen klappen. Der Fehler, den Du 
beschreibst klingt so, als wenn der String während des Schreibens 
resetted wird. Das kann passieren wenn der Prozessor kurz hängt.

Hast Du die LEDs vor dem schreiben zurückgesetzt? (Pin auf low, 50us 
warten). Passiert der gleiche Fehler, wenn Du zweimal schreibst?

von Tim  . (cpldcpu)


Lesenswert?

> Habe den Code gerade noch einmal angepasst mit cli() statt sei().
> Weiterhin gleiches
> Verhalten. Nach dem ws2812_sendarray Befehl wechselt mein Testprogramm
> in
> eine leere while(True) Schleife, daher warte ich deutlich länger als
> 50us ;-).
>
> Interrupts kommen definitiv nicht vor. Sehr seltsam alles.

Ok, da warst Du schneller :) Auf dem AVR werden interrupts mit cli() 
gesperrt. Ich hatte das verwechselt, da es auf dem 6502 genau anders 
herum ist. Warum auch immer.

von Icke ®. (49636b65)


Lesenswert?

Das liegt m.E. an einem Überlauf. 85 LEDs mal 3 Farben ergeben genau 255 
Byte, die in der Reichweite eines 8-Bit Pointers liegen. Ab der 86. 
kommt der da nicht mehr mit.

von Tim  . (cpldcpu)


Lesenswert?

Icke ®. schrieb:
> Das liegt m.E. an einem Überlauf. 85 LEDs mal 3 Farben ergeben genau 255
> Byte, die in der Reichweite eines 8-Bit Pointers liegen. Ab der 86.
> kommt der da nicht mehr mit.

Du hast recht. Es ist auch ganz klar, warum:
1
 uint8_t bufPos = 3 * TARGET_POS;
2
    buf[bufPos] = 0;
3
    buf[bufPos + 1] = 0;
4
    buf[bufPos + 2] = 255;

Richtig wäre:
1
 uint16_t bufPos ...

Eigentlich müsste der Compiler da auch eine Warnung ausgeben?!

von R. M. (rmax)


Lesenswert?

Tim .  schrieb:

> Auf dem AVR werden interrupts mit cli() gesperrt.
> Ich hatte das verwechselt, da es auf dem 6502 genau anders
> herum ist. Warum auch immer.

SEI und CLI setzen bzw. löschen beim AVR das Interrupt-Enable-Flag und 
beim 6502 das Interrupt-Disable-Flag. Deshalb wirken sie genau 
entgegengesetzt.

von Erlang E. (erlang)


Lesenswert?

Icke ®. schrieb:
> Das liegt m.E. an einem Überlauf. 85 LEDs mal 3 Farben ergeben genau 255
> Byte, die in der Reichweite eines 8-Bit Pointers liegen. Ab der 86.
> kommt der da nicht mehr mit.

Super. Tausend Dank für den Hinweis. Unglaublich wie blind man manchmal 
ist. Habe auf uint16_t umgestellt und nun läuft es wie gewünscht.

Vielen Dank auch Tim für deine Mühe bei der Fehlersuche und die tolle 
Library. Nun kann der LED Spaß losgehen ;-)

Viele Grüße,
Erlang

von Icke ®. (49636b65)


Lesenswert?

Philipp E. schrieb:
> Unglaublich wie blind man manchmal ist.

Manchmal sieht man halt den Wald vor lauter Bäume nicht, da muß erst ein 
Spaziergänger des Weges kommen ;-)

Die Lib finde ich auch Klasse. Muß man erst mal drauf kommen, das 
Datenbit ins Carry zu shiften.. genial.

von Tim  . (cpldcpu)


Lesenswert?

Ich frage mich jetzt nur, warum der Fehler bei der Neopixel-Lib nicht 
aufgetreten ist? Dann war der code wohl doch nicht der gleiche...

von Erlang E. (erlang)


Lesenswert?

Tim .  schrieb:
> Ich frage mich jetzt nur, warum der Fehler bei der Neopixel-Lib nicht
> aufgetreten ist? Dann war der code wohl doch nicht der gleiche...

Bei der NeoPixel Lib ist der Buffer ja bereits in der Lib drin, daher 
habe ich die manuelle Verwaltung von Position im Buffer, etc. dort nicht 
benötigt. Dort habe ich die
Methode strip.setPixelColor(...) verwendet und die Position entsprechend 
übergeben.

Viele Grüße und nochmals vielen Dank

von Icke ®. (49636b65)


Angehängte Dateien:

Lesenswert?

Martin S. schrieb:
> Vielleicht könnte einer den Assembler Code etwas kommentieren, damit
> man's einfacher versteht?

Ich war mal so frech, im Rahmen meiner Möglichkeiten die Routine in 
reinem Assemblercode nachzuempfinden. Geeignet ist er für ATmega8, 
ATmega16, diverse ATtinys sowie weitere kompatible AVRs bei 16 MHz 
Takt. Auf Optimierungen habe ich bewußt verzichtet, da es mir mit den 
NOPs übersichtlicher erscheint. Die Länge der RGB-Tabelle wird 16-bittig 
ausgewertet, sodaß theoretisch bis zu 21845 LEDs damit abgeklappert 
werden können. Praktisch ist die Anzahl jedoch durch den zur Verfügung 
stehenden RAM und andere Gegebenheiten begrenzt. Der Code muß natürlich 
noch an die tatsächlich verwendete Hardware angepaßt werden, also die 
CPU-spezifische Lib inkludieren sowie Port, Pin und Anzahl der LEDs 
definieren. Das Y-Register ist durch ein beliebiges anderes Registerpaar 
ersetzbar. Für das Befüllen der RGB-Tabelle darf jeder seiner Phantasie 
freien Lauf oder es dem Zufall über-lassen.
Testen konnte ich leider nur auf einem 60 LED langen Stripe, was 
längeres habe ich nicht am Lager.
Wenn jemand Fehler findet oder Ideen hat, wie man das besser machen 
kann, bitte posten. Den Code-Virtuosen hier fällt bestimmt noch was 
ein...

1
;Assembler-Routine für Atmega8, Atmega16 und weitere kompatible AVRs
2
;zum Ansteuern der RGB-LED WS2812 per Bit-Banging
3
;für 16 MHz Taktfrequenz ausgelegt
4
;nur die Senderoutine enthalten, das Füllen der RGB-Tabelle erfordert weiteren Code
5
;diverse Anpassungen an die Hardware (Port,Pin,Anzahl LEDs) sind im Header vorzunehmen
6
7
8
.EQU  crystal = 16000000          ;Systemtakt in Hz
9
10
.DEF  temp = r16              ;temporäres Register
11
.DEF  loopcounter = r17          ;Schleifenzähler
12
13
;Hier Port und Pin festlegen, an denen die WS2812 angeschlossen ist:
14
.EQU  led_port = PORTx          ;WS2812 relevantes PORT Register
15
.EQU  led_ddr  = DDRx            ;WS2812 relevantes Data Direction Register
16
.EQU  led_pin  = PDx             ;WS2812 relevanter I/O Pin
17
18
;Hier die Anzahl der LEDs festlegen (theoretisch bis 21845)
19
.EQU  rgb_count = x            ;Anzahl der LEDs
20
21
22
.DSEG
23
rgb_table:  .BYTE    rgb_count*3      ;RGB Tabelle im RAM anlegen
24
25
26
.CSEG
27
.ORG 0x0000
28
29
rgb_length:  .DW      rgb_count*3      ;Länge der RGB Tabelle (16-Bit)
30
31
    rjmp      main        ;springe zum Hauptprogramm
32
33
34
send_array:
35
    ldi        ZL,LOW(rgb_table)  ;lade die Adresse der RGB-Tabelle in den Z-Pointer  
36
    ldi        ZH,HIGH(rgb_table)
37
outer_loop:    
38
    ld         temp,Z+        ;lade nächstes Datenbyte
39
    ldi        loopcounter,8    ;setze Schleifenzähler
40
inner_loop:
41
    lsl        temp        ;schiebe nächstes Datenbit ins Carry
42
    dec        loopcounter      ;dekrementiere Schleifenzähler
43
    sbi        led_port,led_pin  ;Datenleitung auf H schalten
44
    nop
45
    nop
46
    brcs       PC+2        ;überspringe nächsten Befehl wenn Datenbit = 1
47
    cbi        led_port,led_pin  ;Datenleitung auf L schalten
48
    nop
49
    nop
50
    nop
51
    nop
52
    brcc       PC+2        ;überspringe nächsten Befehl wenn Datenbit = 0
53
    cbi        led_port,led_pin  ;Datenleitung auf L schalten
54
    nop
55
    nop
56
    nop
57
    nop
58
    brne      inner_loop      ;wiederhole die innere Schleife bis Zähler Null ist
59
60
    cp        ZL,YL        ;prüfe, ob Ende der RGB-Tabelle erreicht ist
61
    cpc       ZH,YH
62
    brne      outer_loop      ;wiederhole äußere Schleife, falls noch nicht
63
64
    ret
65
66
67
main:
68
    ldi       temp, LOW(RAMEND)  ;Stackpointer initialisieren
69
    out       SPL, temp
70
    ldi       temp, HIGH(RAMEND)
71
    out       SPH, temp
72
73
    sbi       led_ddr,led_pin    ;I/O-Pin als Ausgang definieren
74
    cbi       led_port,led_pin  ;Datenleitung auf L schalten
75
76
    ldi       YL,LOW(rgb_table)  ;Adresse der RGB-Tabelle ins Y-Register laden
77
    ldi       YH,HIGH(rgb_table)
78
    
79
    ldi       ZL,LOW(rgb_length)  ;Adresse von rgb_length ins Z-Register laden
80
    ldi       ZH,HIGH(rgb_length)
81
    lpm       temp,Z+        ;Low-Byte der RGB-Tabellen-Länge in temp laden
82
    add       YL,temp        ;addiere die Länge der RGB-Tabelle zum Y-Register (Low-Byte)
83
    lpm       temp,Z        ;High-Byte der RGB-Tabellen-Länge in temp laden
84
    adc       YH,temp        ;addiere die Länge der RGB-Tabelle zum Y-Register (High-Byte)
85
86
    ;fülle die RGB-Tabelle nach Belieben mit deiner eigenen Routine
87
88
    cli                  ;Interrupts sperren
89
    rcall      send_array      ;Daten an WS2812 senden
90
    sei                  ;Interrupts freigeben
91
92
main1:
93
    rjmp      main1

von Icke ®. (49636b65)


Lesenswert?

Icke ®. schrieb:
1
ldi       ZL,LOW(rgb_length)  ;Adresse von rgb_length ins Z-Register laden
2
ldi       ZH,HIGH(rgb_length)

Hier hat sich ein kleiner, aber fataler Fehler eingeschlichen, der 
unbemerkt bleibt, solange rgb_length auf Adresse 0x0000 des Codesegments 
liegt. Aufgrund der WORD-Organisation in CSEG muß beim Laden des 
Z-Pointers die Adresse mit 2 multipliziert werden. Richtig lautet es:
1
ldi       ZL,LOW(rgb_length*2)  ;Adresse von rgb_length ins Z-Register laden
2
ldi       ZH,HIGH(rgb_length*2)

von Rene (Gast)


Lesenswert?

Moin Moin,
ich habe einen vorschlag undzwar das die Lib statt mit RGB mit dem HSV 
fabraum arbeitet.

MFG
Rene

von Icke ®. (49636b65)


Lesenswert?

Auch wenn da "rgb_table" steht, die Lib hat mit dem Farbraum nichts zu 
tun. Sie reicht einfach nur die in der Tabelle abgelegten Werte an die 
LEDs durch.

von Tim  . (cpldcpu)


Lesenswert?

Rene schrieb:
> Moin Moin,
> ich habe einen vorschlag undzwar das die Lib statt mit RGB mit dem HSV
> fabraum arbeitet.

Die LEDs verarbeiten nur RGB. Die Lib übernimmt lediglich die Aufgabe, 
die Daten aus dem Buffer im Speicher in die LEDs zu übertragen.

Um mit HSV-Werten zu arbeiten, müsste man dies vor der Übertragung in 
RGB umwandeln.

von Rene (Gast)


Lesenswert?

Okay muss ich mich halt selber drm kümmern, die lib an sich funktioniert 
bei mir. Jetzt habe ich aber noch eine frage bitte nicht hauen. Und zwar 
währe es möglich an die funktion ws2812_sendarray den PORT und dem PIN 
zu übergeben wo er die daten rausschiken soll also sie nicht vorher zu 
definiern. Damit man mehere Stips an einen Controller anzu schließen?

MFG
Rene

von Tim  . (cpldcpu)


Lesenswert?

Rene schrieb:
> währe es möglich an die funktion ws2812_sendarray den PORT und dem PIN
> zu übergeben wo er die daten rausschiken soll also sie nicht vorher zu
> definiern. Damit man mehere Stips an einen Controller anzu schließen?

Dafür gibt es ws2812_sendarray_mask in den neusten Versionen:

https://github.com/cpldcpu/light_ws2812/tree/master/

Damit kann man den Pin frei wählen. Es müssen aber trotzdem alle Strips 
an den gleichen Port angeschlossen werden.

von Tim  . (cpldcpu)


Lesenswert?


von Ulrich Radig (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

Danke für das TOLLE PROJEKT!!

Hier mein bescheidener Beitrag dazu.

Gruß
Uli

von Ulrich Radig (Gast)


Angehängte Dateien:

Lesenswert?

Sorry hatte noch ein Fehler im Source Code drin!

von Martin (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

erstmal Danke an Tim für das schöne Projekt und den Code.
Danke auch an Ulrich Radig für die HSV-Umrechnung.

Mit dieser habe ich leider ein kleines Problem. Die Farben scheinen 
"Sprünge" zu machen, so als ob bei der Berechnung ein paar Bits verloren 
gehen.

<math.h> habe ich eingebunden und linke mit -lm (falls das überhaupt 
notwendig ist). Leider bin ich im Moment etwas ratlos wo der Fehler 
liegen könnte. Evtl kann mir jemand weiterhelfen?

Danke schon mal,
Martin

von Martin B. (martin_b97)


Lesenswert?

Sorry,

habe vorhin vergessen mich anzumelden, daher kann ich den Text jetzt 
nicht mehr ändern. Noch als Ergänzung: Ich verwende EINE WS2812, 
angeschlossen an PORTB0 eines MEGA328P.

Martin

von Martin B. (martin_b97)


Lesenswert?

Hallo nochmal,

langsam habe ich den Eindruck, dass der Hund hier begraben ist:

//Berechnung der Dunkelstufe
//v = (englisch value) Wert Dunkelstufe einfacher Dreisatz 0..100%
    *r = (*r / 100) * v;
    *g = (*g / 100) * v;
    *b = (*b / 100) * v;

Ich vermute da wird aufgrund der unsigned chars r,g,b und v irgendwas 
gerundet oder läuft über. Wenn ich den Teile auskommentiere, sind die 
Abstufungen weg, aber man kann halt die Helligkeit nicht mehr 
einstellen.

Grüße,
Martin

von Radig (Gast)


Lesenswert?

Hallo,

schaue mal hier:
http://www.ulrichradig.de/home/index.php/projekte/hsv-to-rgb-led

habe den Source Code geändert.

Gruß
Uli

von Tim  . (cpldcpu)


Lesenswert?

Ulrich Radig schrieb:
> Hier mein bescheidener Beitrag dazu.

Hallo Ulrich,

super Projekt! Ich glaube das solltest Du noch einmal mit Bildern 
posten, so sieht ja niemand, was sich dahinter verbirgt :)

Hat eigentlich schon jemand ein Layout für einen Ring mit 5cm 
Außendurchmesser erstellt? Die würden sich schön preiswert bei den 
Chinesischen PCB-Herstellern liefern lassen.

von Martin B. (martin_b97)


Lesenswert?

das gaht auch. Ich hatte mir mittlwerweile mit einem cast auf int bei 
der Berechnung beholfen. Aber so ist es eleganter.

Danke,
Martin

von Tim  . (cpldcpu)


Lesenswert?

Eine Idee noch: Dir normalisierst Sättigung und Helligkeit auf 100. Wenn 
Du hier auf 64 oder 128 gehen würdest, würde für den AVR deutlich 
kürzerer Code generiert werden.

von Radig (Gast)


Lesenswert?

Ich habe mir einen mit innen 52mm und außen mit 72mm erstellt. Dieser 
passt auf den Ring meiner Halogenlampe. Gibt es auch im Download auf 
meiner HP.

Gruß
Uli

von Radig (Gast)


Lesenswert?

So würde ich es auch nicht machen:

*g = 4.25 * h;

sondern so:

*g = (425 * h) /100;

es ist aber anders besser verständlich.

Gruß
Uli

von Tim  . (cpldcpu)


Lesenswert?

Radig schrieb:
> *g = (425 * h) /100;
>
> es ist aber anders besser verständlich.

Ich bin mir nicht ganz sicher ob das als Antwort auf meinen Vorschlag 
gemeint war. Aber wenn Du hier statt dessen

> *g = (425 * h) /256;

Einsezt, bekommst Du deutlich kürzeren Code. Hier gibt es aber noch ein 
paar Fallen mit den richtig Casts. Besser:

> *g = (uint8_t)((425 * h) /256);

und h ist ein int oder uint16_t.

von Ulrich Radig (Gast)


Lesenswert?

Ich weiß das eine div  256  128  64  32 besser ist als eine div / 
100. Ist ja dann nur eine schiebe Operation. Es wird halt immer in den 
Beispielen 0 bis 1 oder 0 bis 100% angegeben. Daher auch bei mir nur der 
Wertebereich 0 .. 100 ;-) es dient nur als Beispiel. Sonnst könnte ich 
gleich auch die allgemeine Berechnungsmatrix verwenden.

von Di P. (drpepper) Benutzerseite


Lesenswert?

Ulrich Radig schrieb:
> Sonnst könnte ich
> gleich auch die allgemeine Berechnungsmatrix verwenden.

Kannst du bitte mal einen Link posten? Meiner ansicht nach ist eine 
Matrix für HSV -> RGB nicht möglich.

Eine interessante Implementierung und auch andere nützliche Farbräume 
sind hier:
http://www.cs.rit.edu/~ncs/color/t_convert.html

von Tim  . (cpldcpu)


Lesenswert?

Radig schrieb:
> Ich habe mir einen mit innen 52mm und außen mit 72mm erstellt. Dieser
> passt auf den Ring meiner Halogenlampe. Gibt es auch im Download auf
> meiner HP.

Ich hatte an dieses Format gedacht:

http://www.adafruit.com/product/1463

Wenn man unter 50mm Außendurchmesser bleibt, kann man die Platinen für 
<1EUR pro Stück bei den bekannten Chinesen bestellen.

von Mario W. (mario_w)


Lesenswert?

Hallo Zusammen,

ich verfolge nun schon eine ganze weile dieses Thema, was mich dazu 
bewegt hat auch so ne Kette zu bestellen.

So wie es aussieht sind die meisten schon über das Testprogramm hinaus.
Ich leider nicht.
Satt dessen werde ich noch Wahnsinnig mit dem Streifen.

Mein größtes Problem an der Sache bin wahrscheinlich ich selbst, da ich 
noch keine wirkliche Programmierleuchte bin, aber das kann ich 
dummerweise nicht vorher ändern, sondern nur an diesem Projekt wachsen.

Aber so wie ich gelesen habe gibt es hier Leute die von dem Ahnung haben 
was sie tun.

Bis jetzt habe ich den Eindruck gewonnen das die Dinger total 
empfindlich sind bezüglich - Wärme und EMV.

Es kommt mir so vor als ob ständig die erste LED hobs geht und dadurch 
der Rest macht was er will.

Blinken, gar nicht Leuchten.............

Habt ihr auch solche Probleme oder wie geht ihr mit dem Streifen/LED's 
um?

Schon mal Danke für eure Bemühungen.

Gruß Mario

von Mario W. (mario_w)


Lesenswert?

Meine bisherigen Schadensbilder an mehreren abgeschnittenen LED-Streifen 
mit 2-10 LED's

Bitmuster kommt sauber und richtig an der ersten LED an.
Stromversorgung steht auch.

# Alle LED's aus --> erste LED gibt nur 0 weiter aber in der richtigen 
Anzahl. Deshalb auch alle anderen LED's aus.
# Alle LED's leuchten blau --> vermute default Einstellung. Erste LED 
macht nichts somit alle anderen auch nicht.
# Alle LED's leuchten richtig bis auf die erste --> erste Kaputt gibt 
aber Bit-Muster richtig weiter.
# Alle LED's blinke und die erste sogar wie sie will --> gibt Bit-Muster 
blinkend weiter.
# Alle LED's blinken weiß --> ob wohl blau ausgegeben wird.

Ihr seht ich hab schon fast alles gehabt nur noch keinen voll 
Funktionsfähigen Streifen.

Hat jemand eine Quelle wo man noch an kleine Fetzen vom WS2812 ran 
kommt?
Da ich selbst nicht in der Lage wäre diese Lib für den WS2812B 
umzuschreiben.

Ist es richtig das eine Scene ausgegeben werden kann und der Streifen 
hält diese dann bis eine neue Scene ausgegeben wird?
oder muss kontinuierlich gesendet werden mit Reset dazwischen?

von Tim  . (cpldcpu)


Lesenswert?

Die Ansteuerung von WS2812 und WS2812B ist identisch. Die Library kann 
beides.

Ich werde aus Deiner Fehlerbeschreibung noch nicht ganz schlau.

Hast Du die Punkte aus der Liste "Troubleshooting" schon alle durch?

https://github.com/cpldcpu/light_ws2812

: Bearbeitet durch User
von Mario W. (mario_w)


Lesenswert?

Hi Tim,

auch von mir Danke für das Projekt super Arbeit  :)

Ja das "Troubleshooting" bin ich soweit durch und kann nichts erkennen 
was ich nicht berücksichtigt hab.
Habe gerade ein Oszi dran hängen und dort kann ich auch kein Problem 
feststellen.

Der betriebene Streifen hat 5 LED's, im unten stehenden Programm werden 
nur 3 angesteuert die weiß leuchten sollen.
Habe dein Beispielprogramm genommen und für 3 LED's angepasst.

Ist-Stand --> die drei sind aus und die zwei nicht angesteuerten 
leuchten blau (default).

Oszi sagt: 3x 24bit alles einser mit ca. 650ns high und 650ns low bei 
4,7V
und nach der ersten LED kommen nur noch 0er raus im richtigen Timing und 
Anzahl. Was aber 1er sein sollten.
Somit ist wahrscheinlich wieder die erste LED kaputt.

Hab mittlerweile die EMV Sandalen an und mit 180C° die Litzen dran 
gepappt und trotzdem geht nichts.

Das Programm läuft eigentlich. Ich glaube ich habe 5m Schrott gekauft, 
eine andere Erklärung habe ich momentan nicht :(

Ich habe hier auch ein 10er streifen WS2812B. wenn ich den direkt dran 
hänge tut der leider auch nicht. Oder muss man da noch was umstellen. Da 
laut Datenblatt das Timing anders ist.

Achso Ich verwende ein ATMEGA328P mit 16MHz auf einem Arduino UNO aber 
ohne Bootloader. Programmiere mit AtmelStudio 6.1

#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "light_ws2812.h"
1
int main(void)
2
{
3
  uint8_t mask;
4
  uint8_t test[] = {255,255,255,255,255,255,255,255,255};
5
  
6
  #ifdef __AVR_ATtiny10__
7
  CCP=0xD8;                
8
  CLKPSR=1;                
9
  mask=_BV(PB2);
10
  #else
11
  CLKPR=_BV(CLKPCE);
12
  CLKPR=0;                       
13
  mask=_BV(PB0);
14
  #endif
15
  DDRB|=mask;
16
  
17
  while(1)
18
  {
19
ws2812_sendarray((uint8_t *)&test[0],9);                
20
_delay_ms(50);                                                             
21
  }
22
}

von Tim  . (cpldcpu)


Lesenswert?

>Oszi sagt: 3x 24bit alles einser mit ca. 650ns high und 650ns low bei
4,7V

Das ist nach meinen neusten Erkenntnissen marginal. Vielleicht hast Du 
wirklich ein abweichenden Fertigungslos erwischt?

Du könntest ja mal die V2 testen. Die ist im Moment noch im Entstehen. 
Der aktuelle Entwicklungsstand liegt hier:

https://github.com/cpldcpu/light_ws2812/tree/testing/light_ws2812_AVR

von Mario W. (mario_w)


Lesenswert?

Ha erfolg erfolg.

Habe nach deiner Aussage das die Lib auch für WS2812B funktioniert. Bei 
meinem B Streifen die erste LED abgeschnitten und siehe da.

Alles tut wie es soll :)
Also Programm Top, LED-Stripe aus China flop.
Die V2 werde ich dann auch mal probieren und dir berichten.

Danke für den doch so wichtigen Input.

Gruß und schönen abend.

Mario

von Tim  . (cpldcpu)


Lesenswert?

Merkwürdig. Ich kann die Geschichte mit der ersten LED immer noch nicht 
so recht glauben, aber von andere Seite gibt es ähnliche Berichte:

Beitrag "WS2812 und WS2812b Qualitätsprobleme!"

von Tim  . (cpldcpu)


Lesenswert?

Ich habe mich noch einmal etwas genauer mit der WS2812 Ansteuerung 
beschäftigt:

http://cpldcpu.wordpress.com/2014/01/14/light_ws2812-library-v2-0-part-i-understanding-the-ws2812/

Teil 2 kommt mit der neuen Version der Library.

Ich würde mich über Kommentare freuen.

: Bearbeitet durch User
von Axel H. (axelh)


Lesenswert?

Hi,

Super Seite, interessant zu lesen. Aber eine Frage zum letzten Satz: "A 
'1' can be encoded with pulses of almost arbitrary length as long as 
they are longer than ~625 µs (minimum on WS2812B)."

Das sollen eher 625ns sein, oder?

Axel

von Tim  . (cpldcpu)


Lesenswert?

Axel Heider schrieb:

> Super Seite, interessant zu lesen. Aber eine Frage zum letzten Satz: "A
> '1' can be encoded with pulses of almost arbitrary length as long as
> they are longer than ~625 µs (minimum on WS2812B)."
>
> Das sollen eher 625ns sein, oder?

Oh ja, danke für den Hinweis!

von Tim  . (cpldcpu)


Angehängte Dateien:

Lesenswert?

Hier gibt es ein ziemlich schickes Projekt für WS2812-LEDs:

http://forum.43oh.com/topic/4920-120-led-ring-clock/

Der Autor hat auch die Gerber-Files für den Ring gepostet. Den könnte 
man auch problemlos mit einem AVR betreiben.

Eigentlich wäre auch ein einfacer 60er Ring interessant.

: Bearbeitet durch User
von Tim  . (cpldcpu)


Lesenswert?

Hier gibt es die Eagle-Dateien für die WS2812-Ringe (Neopixel) von 
Adafruit:

https://github.com/adafruit/Adafruit-NeoPixel-Ring

von Tim  . (cpldcpu)


Lesenswert?


von rossi (Gast)


Lesenswert?

Wollte mich für die Lib bedanken. Hab grad mal eben so auf die schnell 
(keine 10 Minuten) ein Testprogramm für einen Mega8 mit 16MHz an einem 
Stripe mit 150 LEDs geschrieben. Funktioniert super!
Hier zwei Videos: Einmal Vollgas, einmal mit gebremster Animation:

http://www.youtube.com/watch?v=RRk7qi0s3tU

http://www.youtube.com/watch?v=BSlZhNBp98Y

von Tim  . (cpldcpu)


Lesenswert?

Danke! Schick, so viele LEDs habe ich bisher noch nicht auf einmal 
getested.

von Fuchs (Gast)


Lesenswert?

Hi,
leider hatte ich nicht so viel Glück wie mein Vorredner rossi.

Ich versuche schon eine Weile die Lib auf einem ST23L152 (Cortex-M3) zum 
Laufen zu bekommen, aber etwas klappt da nicht.

Ich habe den Assembler-Teil leider nicht ganz verstanden, aber ich denke 
es gibt da ein Problem:
1
"    sub %[ctr], #1        \n\t"
2
"    str %[masklo], [%[clr]]    \n\t"
3
"    beq  end%=          \n\t"
und zwar wird mein Register %[ctr] immer weiter verkleinert, ohne dass 
die Schleife jemals verlassen wird.

Vielleicht ist der Befehl beq hier irgendwie falsch.
Oder liegt das an meiner MCU?

Ich habe die (hoffentlich) aktuelle Lib:
* light weight WS2812 lib - ARM Cortex M0/M0+ version
* Created: 07.07.2013

Es wäre nett, wenn da mal jemand draufschauen könnte.

von Tim  . (cpldcpu)


Lesenswert?

HI Fuchs,

ich muss darauf hinweisen, dass ich die ARM-Version bisher noch nicht 
auf einem Cortex-M3 getestet habe. Entwickelt wurde sie auf einem M0+.

Gerade bei den größeren Cortexen ist es schwierig, zyklengenaues Timing 
zu ermöglichen. Die Implementation geht davon aus, dass es keine 
Flash-Waitstates gibt. Dein ST hat wahrscheinlich mindestens 1 
Waitstate, so dass das Timing nicht stimmt. Hast Du Dir einmal den 
Ausgang angeschaut? Evtl. kannst Du die CPU-Clock verringern und die 
Waitstates auf 0 setzen?

Die Schleife im ASM-Teil funktioniert übrigens, da "STR" das Z-Register 
nicht setzt.

http://infocenter.arm.com/help/topic/com.arm.doc.dui0497a/BABIHJGA.html

Generell ist es gerade auf den schnelleren Cortexen sinnvoll, auf einen 
Hardware-Ansatz zu setzen. Bei STM32 würde sich eine Kombination aus SPI 
und DMA anbeiten. Im Wiki-Artikel gibt es ein paar Beispiele:

http://www.mikrocontroller.net/articles/WS2812_Ansteuerung

: Bearbeitet durch User
von rossi (Gast)


Lesenswert?

Ich muss leider zugeben, dass mich mein Glück mit meinem 150 LED 
Streifen nun auch ein wenig verlassen hat und ich auch Opfer des "erste 
LED hin" Problems geworden bin. Da ich meinen Streifen eh komplett 
zerschneiden will hab ich jetzt erst mal die ersten Teilstreifen 
abgeschnitten und dabei stellte sich heraus, dass nur die erste LED hin 
ist.
Jetzt frage ich mich natürlich - werden jetzt die nächsten ersten LEDs 
auch die Grätsche machen bis alle kaputt sind? Was kann man denn dagegen 
tun, dass die erste LED mit der Zeit kaputt geht? Sind lange Streifen 
mit hohen Einschaltströmen evtl. ein Problem? Versorgt ihr alles aus 
einem Netzteil? Also Prozessor und Streifen? Ich hab ein altes 
AT-Netzteil am Streifen (20A an 5V) und mein STK500 mit dem Prozessor. 
Massen sind verbunden, Signal geht direkt an den Streifen. Sollte man da 
vielleicht einen 1k Widerstand in Reihe zum Eingang des Streifens 
schalten? Und in welcher Reihenfolge sollte man einschalten? Erst den 
Streifen, dann den Controller? Helfen vielleicht dicke Elkos am +/- des 
Streifens? Oder gar einen kleinen Spannungsfilter mit Dorssel & Co. um 
saubere Spannung zuzuführen?

von Fuchs (Gast)


Lesenswert?

Hi, danke für die schnelle Antwort.
In meinem Test habe ich 16MHz verwendet und die Waitstates auf 0 
gesetzt. Nach Application Note müsste das klappen bei VCore von 1,8V 
(und mir ist auch nichts abgestürzt).

Mein Problem beginnt eigentlich schon früher als beim Timing des 
Ausgangs.
Und zwar wird (wie erwähnt) die ctr-Schleife im ASM-Teil nie verlassen. 
ctr zählt fröhlich bis beliebig negative Werte weiter...

Wenn ich vor dem BEQ ein "compare mit 0" einfüge (ich weiß, das ändert 
das Timing, ich probiere nur aus...), dann klappt der Sprung, sobald 
ctr=0:
1
"    sub %[ctr], #1             \n\t"
2
"    str %[masklo], [%[clr]]    \n\t"
3
"               cmp %[ctr],#0   \n\t"  //<-- NEU 
4
"               beq end%=       \n\t"

Ich habe kurz gegoogelt, der ST32L benutzt das THUMB2 instruction set. 
Kann es da evtl. Unterschiede geben?

Ok, also so weit, so gut.
Als nächstes habe ich festegestellt, dass (unabhängig vom übergeben 
Array) immer 0er gesendet werden. Es scheint so, als würde der 
BCS-Befehl nie zuschlagen:
1
"    bcs one%=                  \n\t"
2
"    str %[masklo], [%[clr]]    \n\t"
3
"               one%=:          \n\t"

Ich überlege mir jetzt, ob ich:

- den ASM-Teil so anpasse, dass er auf meiner MCU wie gewünscht läuft 
(ich habe mal gegoogelt und hab was gefunden, wie man angeblich mit 
systick die genaue Anzahl Zyklen messen kann)

- versuche das Timing mit SPI und DMA zu realisieren

Ich tendiere eigentlich eher zum ersten...
In beiden Fällen steckt da für mich noch ein gutes Stück Arbeit drin
(bin noch neu, ist mein erstes "Projekt")

von Tim  . (cpldcpu)


Lesenswert?

rossi schrieb:
> einem Netzteil? Also Prozessor und Streifen? Ich hab ein altes
> AT-Netzteil am Streifen (20A an 5V) und mein STK500 mit dem Prozessor.
> Massen sind verbunden, Signal geht direkt an den Streifen. Sollte man da
> vielleicht einen 1k Widerstand in Reihe zum Eingang des Streifens
> schalten? Und in welcher Reihenfolge sollte man einschalten? Erst den
> Streifen, dann den Controller? Helfen vielleicht dicke Elkos am +/- des
> Streifens? Oder gar einen kleinen Spannungsfilter mit Dorssel & Co. um
> saubere Spannung zuzuführen?

Hier im Thread gibt es ja schon einige Infos:

Beitrag "WS2812 und WS2812b Qualitätsprobleme!"

Das Minimum sollte wohl eine Serienterminierung am Ausgang des 
Controllers mit 100-150 Ohm sein. 1k ist zuviel.

von Tim  . (cpldcpu)


Lesenswert?

Fuchs schrieb:
> Ich habe kurz gegoogelt, der ST32L benutzt das THUMB2 instruction set.
> Kann es da evtl. Unterschiede geben?

Der M3 unterstützt gegenüber dem M0 zusätzliche Befehle. Unterschiede 
kann ich mir nur vorstellen, wenn der code anders compiliert wird. Deine 
Beobachtungen sind merkwürdig. Meistens ist es aber nicht so, dass die 
CPU plötzlich ganz anders funktioniert, sondern es woanders Probleme 
gibt :)

Du kannst die Schleife ja mal in C nachprogrammieren, und schauen was 
der Compiler daraus macht?
1
int i=8;
2
int data=xx;
3
4
while (--i) {
5
  PORT=HI;
6
  if (data&128) PORT=LO;
7
  data<<=1;
8
  PORT=LO;
9
}

oder so ähnlich

Fuchs schrieb:
> Ich überlege mir jetzt, ob ich:
>
> - den ASM-Teil so anpasse, dass er auf meiner MCU wie gewünscht läuft
> (ich habe mal gegoogelt und hab was gefunden, wie man angeblich mit
> systick die genaue Anzahl Zyklen messen kann)
>
> - versuche das Timing mit SPI und DMA zu realisieren
>
> Ich tendiere eigentlich eher zum ersten...
> In beiden Fällen steckt da für mich noch ein gutes Stück Arbeit drin
> (bin noch neu, ist mein erstes "Projekt")

Ich würde Dir zum Zweiten raten, da es auf deinem M3 ziemlich schwierig 
sein wird, nachvollziehbares Timing zu generieren, es aber andererseits 
mächtige Peripherie gibt. Im oben verlinkten Artikel gibt es ja schon 
Beispiele.

: Bearbeitet durch User
von Tim  . (cpldcpu)


Angehängte Dateien:

Lesenswert?

Es gibt eine neue Version der WS2812 im 8mm Gehäuse. Sieht echt nett 
aus!
Ich werde die mal etwas genauer anschauen.

von Axel H. (axelh)


Lesenswert?

Wo hast du die neue Version her?

von Tim  . (cpldcpu)


Lesenswert?

Im Moment scheint das nur eine Vorserie zu sein. Größere Stückzahlen 
gibt es erst später.

Hier kann man schon kleinere Stückzahlen kaufen:
http://solderingsunday.com/shop/components/pixelbits-bakers-dozen/

Zum Bild oben Links: Der Pinabstand scheint nur 2.5 mm statt 2.54 mm wie 
im Datenblatt zu sein.

: Bearbeitet durch User
von Tim  . (cpldcpu)


Lesenswert?

Bei der Ansteuerung gab es keine Überraschungen. Witzige Dinger.

http://cpldcpu.wordpress.com/2014/02/18/new-member-of-the-ws2812-family/

von benwilliam (Gast)


Lesenswert?

btw, nur so als frage zwischen durch warum versucht man mit einem STM32 
die 150 WS2812b mit bitbanging an zu steuern?
Anstatt einfach den SPI zu benutzen?

von Axel H. (axelh)


Lesenswert?

Viele Wege führe nach Rom, und das ist wohl der einfachste und 
portabelste um was um leuchten zu bringen.
Mit einem LPC810 habe ich das hier mit SPI und nachgeschaltetem SCT am 
laufen. Ist halt ein bisschen mehr Aufwand bis das mal läuft.

BTW: Irgendwer Interesse an eine Sammelbestellung der 8mm version? $15 
für den 12er pack und $10 Versand. Und halt noch Zoll.



Axel

von Tim  . (cpldcpu)


Lesenswert?

Axel Heider schrieb:
> Viele Wege führe nach Rom, und das ist wohl der einfachste und
> portabelste um was um leuchten zu bringen.
> Mit einem LPC810 habe ich das hier mit SPI und nachgeschaltetem SCT am
> laufen. Ist halt ein bisschen mehr Aufwand bis das mal läuft.

Die Version aus dem lpc800 Forum?

Axel Heider schrieb:
> BTW: Irgendwer Interesse an eine Sammelbestellung der 8mm version? $15
> für den 12er pack und $10 Versand. Und halt noch Zoll.

Kam bei mir Zollfrei und EUSt-Frei an, obwohl als Wert $50 deklariert 
war. Sind "Hobby Parts" von der EUSt befreit?

von Axel H. (axelh)


Lesenswert?

> Die Version aus dem lpc800 Forum?

Ja, basierend auf der. Prinzipiell funktioniert der Code super und wenn 
man ein paar Kommentare ergänzt, dann ist das sogar verständlich, was da 
gemacht wird.  :)

> Sind "Hobby Parts" von der EUSt befreit?

Laut Zoll Webseite geht alles bis 45 Eur zollfrei als Geschenk durch. Da 
bist du mit den $50 also knapp drunter. Mit dem aktuellen Dollar-Kurs 
sollten also 4 Packungen zollfrei sein ($60 ca. 44 EUR).

Axel

von R. M. (rmax)


Lesenswert?

Axel Heider schrieb:

> Laut Zoll Webseite geht alles bis 45 Eur zollfrei als Geschenk durch.

Als Geschenk gilt es aber nur, wenn es von einer Privatperson an eine 
Privatperson geschickt wird. Ich durfte vor ein paar Jahren mal für eine 
Sendung mit Werbegeschenken aus Kanada (CD-ROMs und T-Shirts) im Wert 
von CAD 50 beim Zoll antanzen und Einfuhrabgaben zahlen.

: Bearbeitet durch User
von Axel H. (axelh)


Lesenswert?

Auch wenn's jetzt OT ist, hab mal im Wiki die Seite 
Elektronikversender: Zoll und Abgaben ergänzt. Schien dazu bisher 
noch nichts zu geben.

von Tim  . (cpldcpu)


Lesenswert?

Axel Heider schrieb:
> Auch wenn's jetzt OT ist, hab mal im Wiki die Seite
> Elektronikversender: Zoll und Abgaben ergänzt. Schien dazu bisher
> noch nichts zu geben.

Im China-Bauteile Thread gibt es bestimmt auch einige dazu:

Beitrag "China SUPER Bauteile-Schnäppchen Thread"

von Conny G. (conny_g)


Lesenswert?

Axel Heider schrieb:
> BTW: Irgendwer Interesse an eine Sammelbestellung der 8mm version? $15
> für den 12er pack und $10 Versand. Und halt noch Zoll.

Interessiert, abhängig vom Preis!
Würde so für 30 Dollar kaufen, in der Hoffnung, dass bei einer größeren 
Gesamtmenge dann auch 60-100 Stück dafür drin sind...

von Tim  . (cpldcpu)


Lesenswert?

Lusting, langsam klärt sich auch, woher die LEDs kommen. Ich habe mal 
nachgefragt, ob günstigere Preise für größere Mengen möglich sind. Melde 
mich, wenn es eine Antwort gibt.

: Bearbeitet durch User
von Tim  . (cpldcpu)


Lesenswert?

Ich habe mit dem Hersteller einen guten Kompromiss zu einer 
Sammelbestellung finden können:

Beitrag ""Sammelbestellung" für 8mm RGB LEDs mit WS2811 chip"

von Axel H. (axelh)


Lesenswert?

Cool, Danke!

Axel

von Michael S. (michael_s98)


Lesenswert?

Hi,

wirst du deine Library auch für XMegas kompatibel machen?
Ich würde ja gerne aber meine ASM kenntnisse lassen da leider sowas
nicht zu

von Tim  . (cpldcpu)


Lesenswert?

Eigentlich sollte sie auf XMega funktioniert, oder übersehe ich da 
etwas?

von Michael S. (michael_s98)


Lesenswert?

Ich habs leider nicht zum laufen bekommen.
Und deine DMA header file ist ja "noch" leer :)

von Tim  . (cpldcpu)


Lesenswert?

Michael S. schrieb:
> Ich habs leider nicht zum laufen bekommen.

Was ist denn genau das Problem?

> Und deine DMA header file ist ja "noch" leer :)

Was für ein DMA header File? :)

von Michael S. (michael_s98)


Lesenswert?

Beim xMega haben sich die Portregister etwas geändert. Das konnte ich 
auch selbst noch in der Lib aendern. Die Portregister denke ich sind 
aber nicht das Problem, sondern das es bei dem ASM Code ein Fehler gibt 
und meine ASM Kenntnisse nicht vorhanden sind ;P ist es schwierig es zu 
lösen. Ich hab ja nichtmal den Fehler selbst nach googlen nicht 
verstehen können gG

light_ws2812.c: In function ‘ws2812_sendarray_mask’:
light_ws2812.c:108:5: warning: asm operand 2 probably doesn’t match 
constraints [enabled by default]
light_ws2812.c:108:5: error: impossible constraint in ‘asm’
make: *** [obj/light_ws2812.o] Fehler 1

von Tim  . (cpldcpu)


Lesenswert?

Ah, ich sehe schon. Das Problem scheint zu sein, dass die Portregister 
nicht mehr PORTx und DDRx heissen, sondern OUTx und DIRx.

Versuche mal die Register in light_ws2812.h direkt einzutragen. Dazu 
musst Du diese Zeilen ersetzen:
1
#define ws2812_PORTREG  CONCAT_EXP(PORT,ws2812_port)
2
#define ws2812_DDRREG   CONCAT_EXP(DDR,ws2812_port)

durch
1
#define ws2812_PORTREG  CONCAT_EXP(OUT,ws2812_port)
2
#define ws2812_DDRREG   CONCAT_EXP(DIR,ws2812_port)

Die Fehlermeldung scheint durch eine ungültige Portregisteraddresse 
verursacht zu sein. Evtl. hast Du auch ein Portregister gewählt, welches 
nicht mehr durch OUT angesteuert werden kann.

: Bearbeitet durch User
von MB (Gast)


Lesenswert?

ich möchte die LED-Funktion als Statusanzeige für verschiedene 
Funktionen nutzen, also jede .c-Datei soll eine zugewiesene LED 
ansteuern.

Allerdings habe ich keine Ahnung, wie ich die Daten der
1
struct cRGB led[..];
mit in andere .c Dateien global übernehmen kann.

Wenn ich
1
struct cRGB led[..];
 in jeder Datei einfüge, sind die bisherigen RGB-Werte der main.c 
verloren und es wird nur die aktuell genutzte Status-LED angezeigt.

Wer kennt sich damit aus ???

von Di P. (drpepper) Benutzerseite


Lesenswert?

stichwort: "extern"

steht in deiner (und jeder anderen) C-Referenz.

von Tim  . (cpldcpu)


Lesenswert?

Wie "Di" Geschrieben hat. Alternativ kannst Du auch auch pointer auf die 
Struktur als Funktionsparameter übergeben. Vom Programmierstil her ist 
das etwas sauberer.

von Di P. (drpepper) Benutzerseite


Lesenswert?

Tim    schrieb:
> Vom Programmierstil her ist
> das etwas sauberer.

stimmt.

von MB (Gast)


Lesenswert?

Mit "extern" hatte ich es vorher auch schon probiert, es hat aber nicht 
geklappt.

Mit Pointer geht es nach einigem basteln.
man lern eben nie aus ;-)

Dankeschön

von Di P. (drpepper) Benutzerseite


Lesenswert?

MB schrieb:
> Mit "extern" hatte ich es vorher auch schon probiert, es hat aber nicht
> geklappt.

Die richtige Vewendung von "extern" ist dabei natürlich entscheidend ;).
In einer c-Datei muss die Variable deklariert (und ggf. initialisiert) 
werden. In einer von allen anderen c-Dateien eingebundenen header-Datei 
wird diese Variable dann als extern deklariert.
Das bewirkt, dass von allen verteilten Programmteilen auf die selbe 
Speicherstelle zugegriffen wird, wenn der name der Variablen fällt.
"extern" signalisiert dem compiler, dass sich die zu kompilierende 
c-Datei darauf verlassen kann, dass Speicher für diese Variable 
vorhanden sein wird. Wo das ist, macht dann der Linker den einzelnen 
o-Dateien klar.

von MichaelS98 (Gast)


Lesenswert?

Hi Tim,

ich habs nun nochmal nach langer Zeit versucht mit dem xMega die 
WS2812er Leds anzusteuern, aber da ich wie gesagt in inline assembler 
nicht wirklich gut bin ;P Hab ichs leider immernoch nicht hinbekommen.

Evtl hast du ja noch eine Idee wie ich das aendern muesste damit das auf 
einem xMega32A4 läuft.

Das ist die aktuelle Funktion von dir die ich versucht habe anzupassen 
;P
Aber er sagt das er einen Fehler in Parameter 2(3) hat, das 
PORTD.OUTSET.

Die Interrupts lass ich bewusst an da ich die Länge des Strips abgreifen 
möchte über einen Interrupt. Was ja alles auf nem ATMega wunderbar 
funktioniert...

Vielen Dank im Vorraus für deine/eure Hilfe

// sends array to ws2812 port
void ws2812_sendarray(uint8_t *data,uint16_t datlen) {
    //irqoff
    uint8_t curbyte, ctr, masklo, maskhi;
    maskhi = PIN0_bm;

    masklo  =~ maskhi & PORTD.OUTSET;
    maskhi |= PORTD.OUTSET;

    while (datlen--) {
        curbyte =* data++;

        asm volatile(
        "       ldi %0,8        \n\t"
        "loop%=:out %2, %3      \n\t"
        "       lsl %1          \n\t"
        "       dec %0          \n\t"
        "       rjmp .+0        \n\t"
        "       brcs .+2        \n\t"
        "       out %2, %4      \n\t"
        "       rjmp .+0        \n\t"
        "       nop             \n\t"
        "       out %2, %4      \n\t"
        "       breq end%=      \n\t"
        "       rjmp .+0        \n\t"
        "       rjmp .+0        \n\t"
        "       rjmp .+0        \n\t"
        "       rjmp loop%=     \n\t"
        "end%=:                 \n\t"
        :   "=&d" (ctr)
        :   "r" (curbyte), "I" (PORTD.OUTSET), "r" (maskhi), "r" 
(masklo)
        );
    }
    //irqon
}

von Tim  . (cpldcpu)


Lesenswert?

MichaelS98 schrieb:
> Evtl hast du ja noch eine Idee wie ich das aendern muesste damit das auf
> einem xMega32A4 läuft.
>
> Das ist die aktuelle Funktion von dir die ich versucht habe anzupassen
> ;P
> Aber er sagt das er einen Fehler in Parameter 2(3) hat, das
> PORTD.OUTSET.

Ich habe leider keinen XMEGA zum testen und kann das Manual nur kurz 
überfliegen. Du solltest Dir die Sektionen zu den I/O Ports genauer 
durchlesen.

 - OUTSET ist der falsche Port. Du benötigst OUT
 - Du musst PORTD auf einen der virtuellen I/O Ports mappen, damit er 
mit dem Befehl "Out" beschrieben werden kann. Steht ab s. 145 im Manual.


> Die Interrupts lass ich bewusst an da ich die Länge des Strips abgreifen
> möchte über einen Interrupt. Was ja alles auf nem ATMega wunderbar
> funktioniert...

Ich verstehe nicht so ganz, was Du damit erreichen willst? Bin aber 
skeptisch dass es sinnvoll ist, während der Routine einen Interrupt 
auszulösen.

: Bearbeitet durch User
von MichaelS98 (Gast)


Lesenswert?

Habs mittlerweile hinbekommen :) Kleinen Grundkurs in inline assembler 
und dann gings auch ;P
Das mit den Interrupts ist auch nur bei der Initialisierung der Fall bei 
den weiteren Ausgaben wird der Interrupt auch ausgeschaltet.
Ich nutze nur einen Interrupt der auf Highlevel auslöst und dort ist 
meine "Rückleitung" für die LED Strips (soll heissen der letzte DOUT ist 
dadran)
um dynamisch die Lönge des Strips zu ermitteln.
Klappt auch mittlerweile wunderbar

Vielen Dank nochmal für deine Hilfe Tim :)

Gruß
Michael

von Andreas (Gast)


Lesenswert?

Hi, ich habe eine Kette von 42 WS2811 Leds und würde am ende gern noch 
einen Atmega8 hängen um damit 7 high power Led Stromquellen zu steuern. 
Mein erster Ansatz war einfach die Chips dafür zu verwenden leider 
pfeift die Stromquelle bei der PWM-Frequenz der WS2811.

Deswegen meine Frage hat jemand schon mal überlegt eine Lib zu bauen die 
sich komplett wie ein WS2811 verhält also mit ein und ausgang, damit man 
den Transparent in eine kette hängen kann?

Der Grund für das ganze ist einfach ich würde zur Lampe mit den LEDs 
einfach gern nur 3 Kabel legen (+,GND,Din) und nicht noch LAN, USB usw. 
bzw den Steuer µC einfach beim Netzteil etwas entfernt.

Gruß
Andreas

von Tim  . (cpldcpu)


Lesenswert?

Andreas schrieb:
> Hi, ich habe eine Kette von 42 WS2811 Leds und würde am ende gern noch
> einen Atmega8 hängen um damit 7 high power Led Stromquellen zu steuern.
> Mein erster Ansatz war einfach die Chips dafür zu verwenden leider
> pfeift die Stromquelle bei der PWM-Frequenz der WS2811.

Ist das bei einer PWM-Ansteuerung nicht normal? Was willst Du denn 
sonst?

Andreas schrieb:
> Deswegen meine Frage hat jemand schon mal überlegt eine Lib zu bauen die
> sich komplett wie ein WS2811 verhält also mit ein und ausgang, damit man
> den Transparent in eine kette hängen kann?

Interessante Idee. Prinzipiell ist das relativ einfach. Du müsstest nur 
die steigende Flanke abwarten und dann nach 0.5µs den Eingang noch 
einmal einlesen. Dies ist dann der Bitwert. Siehe auch hier:

http://cpldcpu.wordpress.com/2014/01/14/light_ws2812-library-v2-0-part-i-understanding-the-ws2812/

Schwierig ist allerdings, dass bei diesem Ansatz die CPU zu 100% 
beschäftigt ist. Abhilfe könnte hier ein Pin-Change Interrupt schaffen. 
Der muss allerdings sehr genaue getimed sein.

von Icke ®. (49636b65)


Lesenswert?

Andreas schrieb:
> Deswegen meine Frage hat jemand schon mal überlegt eine Lib zu bauen die
> sich komplett wie ein WS2811 verhält also mit ein und ausgang, damit man
> den Transparent in eine kette hängen kann?

Bei dem ohnhin schon arschknappen Timing dürfte es schwierig bis 
unmöglich sein, diese Aufgabe mit einem ATmega zu lösen. Dafür brauchts 
schon leistungsfähigere Controller.

von Tim  . (cpldcpu)


Lesenswert?

Icke ®. schrieb:
> Bei dem ohnhin schon arschknappen Timing dürfte es schwierig bis
> unmöglich sein, diese Aufgabe mit einem ATmega zu lösen. Dafür brauchts
> schon leistungsfähigere Controller.

Unsinn. Das kann auch ein ATtiny. Allerdings macht der Controller dann 
sonst nicht all zu viel.

: Bearbeitet durch User
von Icke ®. (49636b65)


Lesenswert?

Tim    schrieb:
> Allerdings macht der Controller dann sonst nicht all zu viel.

Das ist aber der Punkt. Was nützt es, wenn der Controller die Daten zwar 
weiterreichen kann, aber keinen Takt mehr für andere Aufgaben frei hat?

von Tim  . (cpldcpu)


Lesenswert?

Icke ®. schrieb:
> Das ist aber der Punkt. Was nützt es, wenn der Controller die Daten zwar
> weiterreichen kann, aber keinen Takt mehr für andere Aufgaben frei hat?

Kommt darauf an, was der Controller sonst noch machen soll. Zumindest 
während des Reset-Pulses wäre noch Zeit für Anderes.

: Bearbeitet durch User
von Stefan S. (sschultewolter)


Lesenswert?

Hallo Tim,

ich habe ein kleines Problem mit deiner Libary und mir ist gerade nicht 
bewusst, woran das liegt.

Ich poste hier einmal die kurzen Ausschnitte, die wichtig sein können.
1
/*main.h*/
2
#define NUM_LEDS 60
3
struct cRGB leds[NUM_LEDS];

1
/* Eine kleine Funktion, die das struct beschreibt. Es handelt sich um eine Uhr mit vor/nachlaufenden Leds. Das u.a led == 60 nicht eintritt, eine kurze if Anweisung*/
2
3
void setPixel(uint8_t led, uint8_t r, uint8_t g, uint8_t b)
4
{
5
  if(led >= 60 && led < 65) led -= 60;
6
  else if(led <= 255 && led > 255) led = 60 - (255 - led);
7
  
8
  leds[led].r = r;
9
  leds[led].g = g;
10
  leds[led].b = b;
11
}

1
/* wird innerhalb while() aufgerufen, ansonsten läuft nichts nebenbei in der Dauerschleife */
2
void fadeClock(void)
3
{
4
  const uint8_t fade[32] /*PROGMEM*/ =
5
  {
6
    7, 15, 23, 31, 39, 47, 55, 63, 71, 79, 87, 95, 103, 111, 119, 127, 135, 143,
7
    151, 159, 167, 175, 183, 191, 199, 207, 215, 223, 231, 239, 247, 255
8
  };
9
  static uint8_t lastIndex;
10
  uint8_t index = millis() / 63;
11
12
  if(index != lastIndex)
13
  {
14
    lastIndex = index;
15
    memset(leds, 0, NUM_LEDS * 3);
16
    /*
17
    sets(second() - 2, 0, 0, fade[15-index]);
18
    sets(second() - 1, 0, 0, fade[31-index]);
19
    sets(second(), 0, 0, fade[31]);
20
    sets(second() + 1, 0, 0, fade[16+index]);
21
    sets(second() + 2, 0, 0, fade[0+index]);
22
23
    sets(minute(), 0, 255, 0);
24
    
25
    sets(hour() * 5-1, 255, 0, 0);
26
    sets(hour() * 5, 255, 0, 0);
27
    sets(hour() * 5+1, 255, 0, 0);
28
    */
29
    sets(59, 0, 0, 85);
30
    
31
    for(int i = 0; i < NUM_LEDS; i++) ws2812_setleds(leds,i);
32
  }
33
}

Die Leds 59 kann jedoch nicht angesteuert werden.

Habe zum testen, ob die Led doch einen abbekommen hat, eben mit dem 
Arduino getestet und der FastLed lib. Dort konnte 59 Problemlos 
angesteuert werden.


Gruß Stefan

von Tim  . (cpldcpu)


Lesenswert?

1
 for(int i = 0; i < NUM_LEDS; i++) ws2812_setleds(leds,i);

Was willst Du denn mit dieser Zeile bezwecken? Um das LED-Array auf den 
String zu schreiben reicht folgendes:

1
   ws2812_setleds(leds,NUM_LEDS);

: Bearbeitet durch User
von Stefan S. (sschultewolter)


Lesenswert?

Danke, werde es testen. Hatte jetzt nicht nicht dran gedacht, dass damit 
das komplette Array geschrieben wird. Dann macht es auch sinn, wieso es 
zu Probs kommt, wenn er auf einmal das 60 fache schicken muss.

von Hain (Gast)


Lesenswert?

Hallo,

kann es sein, dass die Methode meinen Timer0 beeinflusst?

Ich nutze die Libary für eine Uhr mit 60 Leds. Was ich jetzt bei dem 
ersten Test nicht gemacht habe, ist das Array nur schreiben, wenn sich 
etwas ändert. Derzeit ballert er jeden Durchlauf einmal das Array ab.

Blos wie verhält sich das auf Dauer? Ich habe vor, bis zu 16mal in der 
Sekunde das Array neu zu beschreiben. Ich habe vor, neben der 
gebastelten internen Uhr ebenfalls einen DS3231 einzusetzen, liegt als 
SOIC vor.

Jedoch möchte ich diese nicht jede Stunde mit dem dem Atmega abgleichen. 
Denn ich mache teils ein Fade und das sähe dann unschön aus.

Eine Abweichung von wenigen Sekunden pro Tag fände ich schon recht viel. 
Ich möchte einmal täglich den Wert mit der RTC vergleichen und wenn die 
differenz größer 10sec (evtl. noch geringer) und dann aktualisieren.

Sicherlich, meist bekommt man den Abgleich nicht mit, aber mich stört, 
dass man ihn mitbekommen kann.

So, noch einmal auf den Test zurück. Wie gesagt, ich habe den nun mal 
eine gewisse Zeit laufen lassen. Es waren 52Minuten, welche ich mit 
einer Stoppuhr als Referenz gemessen haben. Man konnte beim umschalten 
schon sheen, dass der Sekundenzeiger keinesfalls schnell arbeitet.

Eine Sekunde auf dem Atmega328P 16MHz brauchte etwa 79% länger als meine
Stoppuhr (01:32:55)

Kann man das ganze errechnen, wie sich das verhält, wenn ich nur 16x die 
Sekunde ein Update machen, wie hoch die Differenz vermutlich sein wird?

time.h
1
#ifndef TIME_H_
2
#define TIME_H_
3
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
7
void time_init(void);
8
void time_set(uint8_t hour, uint8_t minute, uint8_t second);
9
uint8_t hour(void);
10
uint8_t minute(void);
11
uint8_t second(void);
12
int16_t millis(void);
13
uint32_t millis2(void);
14
15
#endif /* TIME_H_ */

time.c
1
#include "time.h"
2
3
volatile unsigned int h;
4
volatile unsigned int min;
5
volatile unsigned int sec;
6
volatile unsigned int ms;
7
volatile unsigned int ms2;
8
9
void time_init(void)
10
{
11
  TCCR0A = (1<<WGM01);
12
  TCCR0B |= (1<<CS01 | 1<<CS00);
13
  OCR0A = 249;
14
  TIMSK0 |= (1<<OCIE0A);
15
  sei();
16
}
17
18
ISR (TIMER0_COMPA_vect)
19
{
20
  ms++;
21
  ms2++;
22
  if(ms == 1000)
23
  {
24
    sec++;
25
    ms = 0;
26
    if(sec == 60)
27
    {
28
      min++;
29
      sec = 0;
30
    }
31
    if(min == 60)
32
    {
33
      h++;
34
      min = 0;
35
    }
36
    if(h == 24) h = 0;
37
  }
38
}
39
40
uint8_t hour(void)
41
{
42
  return h;
43
}
44
45
void time_set(uint8_t hour, uint8_t minute, uint8_t second)
46
{
47
  h = hour;
48
  min = minute;
49
  sec = second;  
50
}
51
52
uint8_t minute(void)
53
{
54
  return min;
55
}
56
57
uint8_t second(void)
58
{
59
  return sec;
60
}
61
62
int16_t millis(void)
63
{
64
  return ms;
65
}
66
67
uint32_t millis2(void)
68
{
69
  return ms2;
70
}

von Hain (Gast)


Lesenswert?

So, ich habe noch einmal einen Test über 2h laufen lassen. Diesmal wird 
jede Sekunde einmal das Array neugeschickt.

Nun liegt der Fehler bei ca 1,3% (insgesamt ca 10 Sekunden Differenz). 
Damit kann ich leben, zu mal bei diesem Testprobanten sowieso nur SMD 
Resonator verbaut ist. Das entspricht in etwa der Fehlerquote.

Werde nun noch mal den Test bis morgen früh durchführen, wenn ich nun 
jede Sekunde 16mal den Wert ändere.

von Tim  . (cpldcpu)


Lesenswert?

Hain schrieb:
> kann es sein, dass die Methode meinen Timer0 beeinflusst?

Den Timer nicht, aber die Interrupts werden natürlich gesperrt. Versuche 
doch einmal, die Interrupt-Frequenz zu verringern. Der Fehler wird immer 
dann auftauschen, wenn während des WS2812 calls zwei interrupts 
aufgerufen werden.

: Bearbeitet durch User
von Tim  . (cpldcpu)


Lesenswert?

Ich habe mir mal ein paar neue LEDs angeschaut, die APA102:

http://cpldcpu.wordpress.com/2014/08/27/apa102/

Diese LEDs lassen sich per SPI ansteuern. Bin etwas unschlüssig, ob es 
überhaupt Sinn macht, diese auch in der Lib zu unterstützen.

: Bearbeitet durch User
von Di P. (drpepper) Benutzerseite


Lesenswert?

Sieht sehr interessant aus, danke für die Info.

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


Lesenswert?

Tim    schrieb:
> Diese LEDs lassen sich per SPI ansteuern. Bin etwas unschlüssig, ob es
> überhaupt Sinn macht, diese auch in der Lib zu unterstützen.

 Ja, aber in DaBla ist von 512KHz und 4 Bytes die Rede. Das ist weniger
 als WS28xx.

: Bearbeitet durch User
von Karol B. (johnpatcher)


Lesenswert?

Tim    schrieb:
> Diese LEDs lassen sich per SPI ansteuern. Bin etwas unschlüssig, ob es
> überhaupt Sinn macht, diese auch in der Lib zu unterstützen.

Ich sehe hierfür keine Notwendigkeit, um ehrlich zu sein. SPI 
unterscheidet sich deutlich von dem WS2811/12 "Interface und wird meist 
direkt in Hardware umgesetzt. Neben einer kurzen Initialisierung, 
beschränkt sich das Senden ja dann letztendlich auf das Schreiben in ein 
Register. Bei Controller mit DMA kann das dann sogar vollständig im 
Hintergrund ablaufen. Besser geht es kaum.

Mal sehen, ob sich diese LEDs bzw. entsprechend bestückte Streifen 
durchsetzen werden und ggf. sogar zu ähnlichen Preisen gehandelt werden. 
Wünschenswert wäre es alle Male.

Mit freundlichen Grüßen,
Karol Babioch

von Tim  . (cpldcpu)


Lesenswert?

Marc Vesely schrieb:
> Ja, aber in DaBla ist von 512KHz und 4 Bytes die Rede. Das ist weniger
>  als WS28xx.

Das scheint mir nur ein Beispiel zu sein. Ich hatte mit 4 MHz noch keine 
Probleme. Ich werde mal nachfragen, ob es so etwas wie eine 
Spezifikation gibt...

Karol Babioch schrieb:
> Mal sehen, ob sich diese LEDs bzw. entsprechend bestückte Streifen
> durchsetzen werden und ggf. sogar zu ähnlichen Preisen gehandelt werden.
> Wünschenswert wäre es alle Male.

Glaube nicht, dass die so schnell günstiger werden. Für das low-price 
Segment hat der Anbeite die APA104, einen WS2812B clone.

von Tim  . (cpldcpu)


Angehängte Dateien:

Lesenswert?

Anbei ein Flyer den ich von der Firma bekommen habe. Sie planen auch 
LEDS mit 12 bit, sowie kleine Varianten mit 3.5x3.5 mm. Klingt 
interessant.

: Bearbeitet durch User
von Axel H. (axelh)


Lesenswert?

Hi,

Die mcd Werte sind aber niedrig. Oder verwechsel ich da was?

Axel

von BADCABL1E (Gast)


Lesenswert?

Hallo
Ich brauch mal ein bisschen Hilfe! Ich nutze ein Atmega320pu und schaffe 
es einfach nicht die LEDs zu laufen zu bringen!
Ich bin mir nicht sicher ob es an meinem Programm liegt oder an dem zu 
heißem  verlöten der LED liegt!
Kann ich bei der Lib von oben etwas richtig falsch machen?
Was müsste ich alles ändern?

Ich wünsche noch eine schöne Woche

von Karol B. (johnpatcher)


Lesenswert?

BADCABL1E schrieb:
> Kann ich bei der Lib von oben etwas richtig falsch machen?

Ja.

Falls du aber wirklich konkrete Hilfe möchtest, dann musst du Details 
(Beispielprogramm, Fehlermeldungen, Beschreibung des Fehlverhaltens, was 
hast du überhaupt vor, was sind die Voraussetzungen, usw.) herausrücken. 
Dein Beitrag in seiner aktuellen Form ist ungefähr so nützlich wie die 
Aussage "Mein Auto springt nicht an".

Mit freundlichen Grüßen,
Karol Babioch

von BADCABL1E (Gast)


Lesenswert?

Das ist mir ja auch klar. Vielen Dank für die schnelle Antwort!
Leider kann ich nicht viele mehr sagen... Ich bekomme keine 
Fehlermeldung und ein Signal erhalte ich auch. Aber nichts leuchtet.
Ich will die LED nur zum Laufen bringen und dann würde ich weiter 
schauen.

von BADCAB1E (Gast)


Lesenswert?

Hallo
Ich versuche es noch einmal nach einigem gebastel.
Mein Atmega328pu läuft mit einem internen 16mhz tackt. Ich nutze den 
Code von  oben (ohne Änderungen) und definiere den PINB1 als Output für 
das Signal. Wenn ich nun das alles anschalte bekomme ich ein Weißes 
Licht (ändern Läst sich das nicht)
Ich entschuldige mich für meine vorherigen Posts und hoffe diese 
Informationen sind hilfreicher ;)
Noch ein schönes Wochenende und vielen Dank!

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


Lesenswert?

BADCAB1E schrieb:
> Mein Atmega328pu läuft mit einem internen 16mhz tackt. Ich nutze den

 ???

von BADCAB1E (Gast)


Lesenswert?

sorry ich meinte, dass ich für die Delay Funktion F_CPU=16000000 
definiert habe

von Tim  . (cpldcpu)


Lesenswert?

BADCAB1E schrieb:
> Ich nutze den
> Code von  oben (ohne Änderungen) und definiere den PINB1 als Output für
> das Signal. Wenn ich nun das alles anschalte bekomme ich ein Weißes

Welchen Code nutzt Du denn genau?

Die aktuelle Version liegt hier:

https://github.com/cpldcpu/light_ws2812

von BADCAB1E (Gast)


Lesenswert?

genau die! Und um Fehler auszuschießen habe das RGB_blinky.c auch schon 
verwendet. Aber ich hab immer weißes Licht.

von Tim  . (cpldcpu)


Lesenswert?

Hast Du schon die Punkte unter "Troubleshooting" abgearbeitet?

Ansonsten passen vermutlich die tatsächliche Taktfrequenz und die im 
Code einstellte nicht zusammen.

von BADCAB1E (Gast)


Lesenswert?

"Troubleshooting" hab ich durchgearbeitet... Das was ich nicht verstehe 
ist, dass ich weißes Licht erhalte --> Das bedeutet doch ich steuere 
R,G,B an?
Ich vermute, da ich ja ein Signal bekomme, dass es an der Frequenz 
liegt.
Wo kann ich die Taktfrequenz einstellen/ Prüfen? Ich habe sie zur Zeit 
in der Toolchain bei Atmel-studio festgelegt.

von Tim  . (cpldcpu)


Lesenswert?

SO etwas kann passieren, wenn Deine tatsächliche CPU-Clock niedriger als 
der F_CPU wert sind.

Hast Du die Fuses richtig gesetzt?

von BADCAB1E (Gast)


Angehängte Dateien:

Lesenswert?

Mein freund hat ein Oszilloskop (zum Glück) Ich glaube, dass das zu 
schnell ist(Bild)! Wenn das so ist wie kann ich es ändern!
Vielen vielen dank für die schnellen Antworten!

von Tim  . (cpldcpu)


Lesenswert?

Nö. Ist zu langsam. Jeder Puls sollte 1.25µs haben, bei Dir sind es 
2.5µs.

von BADCAB1E (Gast)


Lesenswert?

Also ich hab jetzt die Taktfrequenz auf 8mhz runterkorrigier. Jetzt 
leuchtet die LED Grün! Reicht mir aber immer noch nicht ;) Was könnte 
ich denn anders machen oder noch besser was mache ich denn falsch?
    MfG

von Conny G. (conny_g)


Lesenswert?

Ich kenn jetzt das Blinky nicht, aber Deine Frage sagt es ist nicht 
grün, was Du wolltest.
Dein Signal sieht nach 0 255 0 aus. Bei den WS2812 wäre das Rot (GRB als 
Reihenfolge), bei den WS2811 ist es grün (RGB Reihenfolge).

Vielleicht musst Du der Library noch sagen, welchen Chip Du hast?

von Joachim B. (jar)


Lesenswert?

Tim    schrieb:
> Nö. Ist zu langsam. Jeder Puls sollte 1.25µs haben, bei Dir sind
> es
> 2.5µs.

ich kam mit dieser und fastLED 1 auch nicht so klar, 100 LEDs brauchten 
300ms.
Jetzt mit fastLED2 bin ich bei 3ms

von Icke ®. (49636b65)


Lesenswert?

BADCAB1E schrieb:
> Was könnte ich denn anders machen oder noch besser

Eine halbe Stunde hinsetzen und VERSTEHEN lernen, für was die Routine 
zuständig ist und für was nicht. Ihre Aufgabe ist das Senden der Daten 
zu den WS2812, nicht aber das Bereitstellen der Daten. Ich bezweifle 
auch, daß eine Korrektor des Taktes nach unten hilfreich ist, wenn die 
Pulse ohnehin schon zu lang sind.

von Conny G. (conny_g)


Lesenswert?

Icke ®. schrieb:
> BADCAB1E schrieb:
>> Was könnte ich denn anders machen oder noch besser
>
> Eine halbe Stunde hinsetzen und VERSTEHEN lernen, für was die Routine
> zuständig ist und für was nicht. Ihre Aufgabe ist das Senden der Daten
> zu den WS2812, nicht aber das Bereitstellen der Daten. Ich bezweifle
> auch, daß eine Korrektor des Taktes nach unten hilfreich ist, wenn die
> Pulse ohnehin schon zu lang sind.

Er hat nicht den Takt geändert, sondern F_CPU richtig gesetzt.
Das war mit 16 Mhz das doppelte des realen internen Taktes, also sind 
die Delays dann ungewollt doppelt so lang.

von BADCAB1E (Gast)


Lesenswert?

Hallo
Ich hab mich heute noch einmal vor den PC gehockt... Nachdem ich den 
Code (ohne Änderung) noch einmal auch den Chip geflasht habe, blinkten 
die LEDS! Ich verstehe zwar nichts, aber wenn es geht ist es mir auch so 
recht;)
Ich bedanke mich herzlichst bei allen die mir geholfen haben!

Mit freundlichen Grüßen
BADCAB1E

Und da ich Icke® nicht ausschließen möchte, bedanke ich mich für den 
sinnlosesten Kommentar den ich gelesen habe! Die Zeit den zu schreiben 
hätte man sicherlich besser nutzen können.

von Icke ®. (49636b65)


Lesenswert?

BADCAB1E schrieb:
> Die Zeit den zu schreiben hätte man sicherlich besser nutzen können.

In der Tat Zeitverschwendung. Den Beweis lieferst du gleich mit:

BADCAB1E schrieb:
> Ich verstehe zwar nichts, aber wenn es geht ist es mir auch so
> recht;)

von Tobias N. (silberkristall)


Lesenswert?

Oh man oh man.

Selbst ICH habe die lib sofort ans laufen bekommen. Leute gibts :-P

von Joachim B. (jar)


Lesenswert?

Tobias N. schrieb:
> Selbst ICH habe die lib sofort ans laufen bekommen. Leute gibts :-P

ich habe es ja auch geschafft, aber warum 100 LEDs 300ms brauchen hat 
mir niemand sagen können. Dann habe ich fastLED probiert, dito, wieder 
nur Sprüche von anderen.

Weitergegoogelt und fastLED2 gefunden und siehe da 3ms für 100 LEDs was 
ziemlich genau passt, ein Bit 1,25µs (bei 16MHz) mal 24 Bit für eine LED 
in RGB = 30µs x 100 LEDs = 3ms

so dachte ich mir das, aber vorher 2 Libs vergebens probiert und selbst 
an mir gezweifelt.

von Di P. (drpepper) Benutzerseite


Lesenswert?

Joachim B. schrieb:
> selbst an mir gezweifelt.

Der erste Schritt in die richtige Richtung :)

von Joachim B. (jar)


Lesenswert?

Di Pi schrieb:
> Der erste Schritt in die richtige Richtung :)

(wieder so ein Kommentar der kein bischen hilft......)
aber trotzdem gelöst, wenn auch nicht mit der ws2811/12 oder fastLED1

fastLED2 läuft wie erwartet, was soll ich da noch nach den anderen oder 
meinen vermeintlichen Fehler suchen falls es den überhaupt gibt.

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

Joachim B. schrieb:
> (wieder so ein Kommentar der kein bischen hilft......)
> aber trotzdem gelöst, wenn auch nicht mit der ws2811/12 oder fastLED1
>
> fastLED2 läuft wie erwartet, was soll ich da noch nach den anderen oder
> meinen vermeintlichen Fehler suchen falls es den überhaupt gibt.

Nutze auch die lib von Tim aber ich hab keine Ahnung was dein gelaber 
von wegen fastLED dauernd soll. Was ist das? Was hat das hier mit dem 
Thread zu tun?
Du hast halt irgendwelche Arduino-Probleme. Kannst du damit nicht in 
arduino.cc rumnerven?

von Joachim B. (jar)


Lesenswert?

cyblord ---- schrieb:
> ich hab keine Ahnung was dein gelaber
> von wegen fastLED dauernd soll. Was ist das? Was hat das hier mit dem
> Thread zu tun?

OK ich erkläre es dir

zuerst hatte ich die wsLIB vom Tim versucht, auf dem puren AVR 
(Lochraster, nix Arduino!)

lief für 40 LEDs prima und ich hatte keinen Grund am Timing zu zweifeln, 
nicht mal nachgemessen.

Dann wollte ich die wordclock bauen, als ich die 117 LEDs fertig 
bestückt hatte kam der erste Test, alle LEDs im Farbwechsel und ich sah 
wie die Farben von der ersten zur letzten LED durchgereicht wurden und 
habe sagenhafte 300ms gemessen was auch bei den lahmen 800kHz nicht sein 
dürfte.

Ich recherchierte und fand fastLED also diese wahlweise mit #defines 
installiert und beide gegeneinander vermessen. Kein nennenswerter 
Unterschied ca. 5% also im Ergebnis auch zu lahm.

Ich wollte schon des Projekt mit den WS erden und auf LPD umsteigen 
(2MHz clock) und fand dann fastLED2 was das gewünschte Ergebnis bringt.

Mir fehlt einfach der Beweis das mit der WS Lib 100 RGB LEDs in 3ms zu 
schalten sind, das ist kein Gemecker in Richtung Tim, nur meine 
Feststellung und mit euren Komentaren komme ich halt (wie so oft in 
Foren) kein Stück weiter.

Tims LIB funkioniert, Anfänger so wie ich freuen sich über die ersten 
Farbspiele die leicht umzusetzen sind, trotzdem läuft es nicht rund. 
PUNKT

Nichts weiter wollte ich dem TO mitteilen und wo es eventuell klemmt.

von Icke ®. (49636b65)


Lesenswert?

Joachim B. schrieb:
> Mir fehlt einfach der Beweis das mit der WS Lib 100 RGB LEDs in 3ms zu
> schalten sind

Der Beweis ergibt sich schon aus der Tatsache, daß die Ansteuerung der 
WS2812 gar nicht funktionieren kann, wenn die Routine grob von dem im 
Datenblatt angegegebenen Timing abweichen würde. Die Übertragung eines 
Bits dauert 1,25µs, macht also bei 24 Bit 30µs pro LED. 100 mal 30µs 
ergeben -tataa- genau 3ms plus ~50µs Reset. Laut Datenblatt kann das 
Timing pro Bit bis zu 300ns abweichen, in der Praxis scheinen sie sogar 
etwas mehr zu vertragen. Wir reden allerdings von Zeiten im Bereich 
einstelliger µs und nicht vom Faktor 100. Wenn bei dir die Übertragung 
300ms für 100 LEDs dauern soll, dann kann das schon theoretisch 
unmöglich sein. Du hast entweder einen Meßfehler oder du mißt etwas 
anderes.

Joachim B. schrieb:
> und ich sah
> wie die Farben von der ersten zur letzten LED durchgereicht wurden

Auch das ist nicht möglich, weil die Farben in der gesamten Kette erst 
nach dem Reset-Puls übernommen werden und zwar nahezu gleichzeitig.

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

> Joachim B. schrieb:
>> Mir fehlt einfach der Beweis das mit der WS Lib 100 RGB LEDs in 3ms zu
>> schalten sind

Allein schon wenn man den Code von Tim anschaut, sieht dass hier 
nirgendwo so eine große Verzögerung auftreten kann. Der druchläuft die 
Hauptschleife so schnell wie möglich und somit ergibt sich die Zeit für 
X LEDs automatisch.

Icke ®. schrieb:
> Joachim B. schrieb:
>> und ich sah
>> wie die Farben von der ersten zur letzten LED durchgereicht wurden
>
> Auch das ist nicht möglich, weil die Farben in der gesamten Kette erst
> nach dem Reset-Puls übernommen werden und zwar nahezu gleichzeitig.

Möglich schon. Aber das liegt dann nicht an der lib sondern am Programm 
welches die lib mit Daten füttert. Er hat halt ein Lauflicht 
programmiert ;-)

Ne also Joachim, mal ehrlich, deine Aussagen hier zeugen schon von 
großer Unbedarftheit. In einem solchen Fall sollte man nicht von 
Beweisen schwadronieren und irgendwelche Verzögerungen unterstellen. 
Eigenen Code checken und den fixen wär angesagt. Und nicht so lange libs 
austesten bis es zufällig mal geht.

von Tim  . (cpldcpu)


Lesenswert?

Joachim B. schrieb:
> Dann wollte ich die wordclock bauen, als ich die 117 LEDs fertig
> bestückt hatte kam der erste Test, alle LEDs im Farbwechsel und ich sah
> wie die Farben von der ersten zur letzten LED durchgereicht wurden und
> habe sagenhafte 300ms gemessen was auch bei den lahmen 800kHz nicht sein
> dürfte.

Klingt, als wenn Du ws2812_setleds in einer Schleife aufgerufen hast. 
Das ist natürlich Unsinn, da der Aufruf das ganze Array auf einmal 
beschreibt. Es wird kein Index, sondern die Länge übergeben. Es gibt 
einfach keine Möglichkeit, die LEDS schnell oder langsam zu beschreiben. 
Die Geschwindigkeit ist immer die gleiche.

Ich muss mich allerdings den Vorrednern anschließen. Du verunsicherst 
mit solchen Kommentaren nur andere Anfänger. Wäre besser, wenn Du Dein 
konkretes Problem beschreiben würdest (mit Code!), anstatt solche 
Statements abzugeben.

: Bearbeitet durch User
von Tim  . (cpldcpu)


Lesenswert?


von Joachim B. (jar)


Lesenswert?

Tim    schrieb:
> Klingt, als wenn Du ws2812_setleds in einer Schleife aufgerufen hast.
> Das ist natürlich Unsinn,

hmmm, ist ja Schnee von vorgestern, ich hatte diese LIB und fastLED 
beide auf dem Chip und konnte per #define beide probieren und beide 
haben für 117 LEDs und einen Farbwechsel nicht einzeln aufgerufen 300ms 
mit dem Oszi vermessen. Komischerweise hatte ich mit fastLED2 sofortigen 
Erfolg, damit war bestätigt das die LEDs pro Farbset nur die geschätzten 
30µs (1,5µs x24 bit) brauchen und 100 davon ca. 3ms.

Nun könnt ihr mich alle füür blöd halten, aber warum habe ich das denn 
sofort mit fastLED2 geschafft?

Die einzige Erklärung die ich noch habe, falsche LIB erwischt, falsch 
aufgerufen, was ich aber nicht glaube

ich wollte gerade noch mal nachsehen, aber der Link
Beitrag "Re: Lightweight WS2811/WS2812 Library"

führt zu:
https://github.com/cpldcpu/light_ws2812/tree/master/light_ws2812

page not found, in Schelm der Böses dabei denkt..... OK die Vorversionen 
sind alle rausgeschmissen, kann ich verstehen

aber wo sollte mein Fehler sein wenn ich

#define MAXLEDS 117
for(i=0;i<MAXLEDS;i++)
{
  value.b = 255; value.g = 0; value.r = 0; // RGB Value -> Blue
  LED.set_crgb_at(i, value); // Set value at LED found at index 0
}

CONTRL_LED_ON; //macro eine single_LED am anderen Port einschalten
  LED.sync(); // Sends the value to the LED
CONTRL_LED_OFF; //macro single_LED am anderen Port ausschalten

und die T on Time der CONTRL_LED mit dem Osi prüfe?

aber egal, ich hatte 2 LIBs versucht bei der 3ten Erfolg, es ist nun 
müssig zu suchen woran es lag, könnte ich natürlich wiederholen, aber 
mag ich grad nicht.

Vielleicht hatte ich auch nur eine vorvorfinal Version erwischt.

dann tut mir meine Kritik am TO leid.

: Bearbeitet durch User
von Tim  . (cpldcpu)


Lesenswert?

Joachim B. schrieb:
> führt zu:
> https://github.com/cpldcpu/light_ws2812/tree/master/light_ws2812
>
> page not found, in Schelm der Böses dabei denkt..... OK die Vorversionen
> sind alle rausgeschmissen, kann ich verstehen

Hier sind alle alten Versionen zu finden:
https://github.com/cpldcpu/light_ws2812/commits/master

Zum Rest kann ich nicht viel ergänzen. Du hast leider immer noch nicht 
den tatsächlich von Dir benutzten Code gepostet. Allerdings verstärkt 
sich mein Verdacht von oben...

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Tim    schrieb:
> Du hast leider immer noch nicht
> den tatsächlich von Dir benutzten Code gepostet.

mir wurde unterstellt

Tim    schrieb:
> Klingt, als wenn Du ws2812_setleds in einer Schleife aufgerufen hast.

und das hatte ich nicht, du kannst mich für blöd halten aber ich weiss 
was ich getippt hatte:

Joachim B. schrieb:
> for(i=0;i<MAXLEDS;i++)
> {
>   value.b = 255; value.g = 0; value.r = 0; // RGB Value -> Blue
>   LED.set_crgb_at(i, value); // Set value at LED found at index 0
> } // LED set in der Schleife
>
> CONTRL_LED_ON; //macro eine single_LED am anderen Port einschalten
>   LED.sync(); // Sends the value to the LED
> CONTRL_LED_OFF; //macro single_LED am anderen Port ausschalten
// Messung ausserhalb der Schleife

komisch nur, das ich deine erste LIB die ich funktionierend an einem 
puren Atmel auf eine Lochraster selbst gebaut mit einer Arduino LIB aus 
anderer Quelle (ich nehme mal an nicht von dir) am nanoV3 verglichen 
hatte und das beide 300ms für die 100 LEDs benötigten.

> Allerdings verstärkt sich mein Verdacht von oben...

nun ja bleibt dir unbenommen.

ist kein Problem, deine LIB ist ja hier nicht nicht für Arduino, ich 
brenne das noch mal auf die pure AVR Musteplatte s.o.

welche Version ist jetzt aktuell? bitte Link.

von Tim  . (cpldcpu)


Lesenswert?

Die aktuelle Version ist immer hier:
https://github.com/cpldcpu/light_ws2812

Und hier gibt eine Übersicht der Releases. Ich habe aber nicht den 
Eindruck, dass das Feature von vielen genutzt wird:
https://github.com/cpldcpu/light_ws2812/releases

von Joachim B. (jar)


Lesenswert?

Tim    schrieb:
> Klingt, als wenn Du ws2812_setleds in einer Schleife aufgerufen hast.

könnte glatt sein (sorry)

aber dann muss ich ein Verständnisfehler zwischen set_led und send_array 
haben

im blinky.c wurde nirgends send_array aufgerufen und das war die 
Vorlage.

Wie würde es denn in deiner LIB richtig laufen?

also set_led und send_array unabhängig? (dann könnte ich send ja 
vermessen und meine Falschbehauptung selber widerlegen).

dann würde set led nicht einzeln erfolgen sondern wenn fertig mit 
send_array?

tut mir echt leid wenn ich hier falsches geschrieben hatte, aber ohne 
bessere Erklärung wie man das nutzt ist mein Fehler verständlich.

: Bearbeitet durch User
von Tim  . (cpldcpu)


Lesenswert?

Joachim B. schrieb:
> Tim    schrieb:
>> Klingt, als wenn Du ws2812_setleds in einer Schleife aufgerufen hast.
>
> könnte glatt sein (sorry)

Ok, danke fürs Nachforschen! Eine andere Erklärung hätte mich sehr 
erstaunt.

> aber dann muss ich ein Verständnisfehler zwischen set_led und send_array
> haben
> im blinky.c wurde nirgends send_array aufgerufen und das war die
> Vorlage.

Ja, und warum rufst Du es dann in Deinem Code auf? Weder im Readme, noch 
in dem Beispiel wird diese Funktion erwähnt. Ich sehe aber, woher die 
Verwechslung kam.

"send_array" ist eine interne Funktion, die im Wesentlichen aus 
Kompatibilitätsgründen zur v1.0 vorhanden ist. Grund für das neue 
Interface ist, dass viele die Anzahl der LEDs und Bytes verwechselt 
haben und mit dem Drumherum (INT sperren, delay für reset) nicht zurecht 
kamen.

> Wie würde es denn in deiner LIB richtig laufen?
>
> also set_led und send_array unabhängig? (dann könnte ich send ja
> vermessen und meine Falschbehauptung selber widerlegen).

Die Funktion heisst "set_leds", weil sie mehrere LEDs beschreibt. Die 
LEDS werden im Array übergeben. Es ist überhaupt nur dieser eine 
Funktionsaufruf notwendig.

> tut mir echt leid wenn ich hier falsches geschrieben hatte, aber ohne
> bessere Erklärung wie man das nutzt ist mein Fehler verständlich.

Mir fällt auf, dass ich vielleicht noch ein Beispiel zum Beschreiben 
ganzer Strings hinzufügen sollte. Das sollte einige Missverständnisse 
ausräumen.

von Joachim B. (jar)


Lesenswert?

Tim    schrieb:
> Die Funktion heisst "set_leds", weil sie mehrere LEDs beschreibt. Die
> LEDS werden im Array übergeben. Es ist überhaupt nur dieser eine
> Funktionsaufruf notwendig.
>
>> tut mir echt leid wenn ich hier falsches geschrieben hatte, aber ohne
>> bessere Erklärung wie man das nutzt ist mein Fehler verständlich.
>
> Mir fällt auf, dass ich vielleicht noch ein Beispiel zum Beschreiben
> ganzer Strings hinzufügen sollte. Das sollte einige Missverständnisse
> ausräumen.

sorry das verstehe ich grad noch nicht, ich meinte wie setze ich die 
Farben, Helligkeiten einzelner LEDs im Array bevor set_leds aufrufe?

Ich möchte ja für meine Wordclock nur die nötigen LEDs setzen und dann 
komplett abschicken.

von Tim  . (cpldcpu)


Lesenswert?

Joachim B. schrieb:
> sorry das verstehe ich grad noch nicht, ich meinte wie setze ich die
> Farben, Helligkeiten einzelner LEDs im Array bevor set_leds aufrufe?

Wie man halt Arrays in Ansi-C beschreibt:

1
   struct cRGB led[16]; // array mit 16 leds reservieren
2
3
   led[0].r=255;led[0].g=00;led[0].b=0;    // Write red to led1
4
   led[1].r=255;led[1].g=00;led[1].b=0;    // Write red to led2
5
   led[2].r=255;led[2].g=00;led[2].b=0;    // Write red to led3

Alternativ kannst Du auch die ganze Struct (cRGB) gleichzeitig schreiben 
und Dir vorher Farben definieren.

1
struct cRGB cblack={0x00,0x00,0x00};
2
struct cRGB cwhite={0xff,0xff,0xff};
3
4
led[0]=cblack;
5
led[1]=cwhite;

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Tim    schrieb:
> Mir fällt auf, dass ich vielleicht noch ein Beispiel zum Beschreiben
> ganzer Strings hinzufügen sollte. Das sollte einige Missverständnisse
> ausräumen.

dazu fällt mir noch ein, ist denn set_led nicht ein "ungünstiger" Name 
für eine Funktion die nur die LED im Array setzen soll?

ich fand

Tim    schrieb:
> "send_array" ist eine interne Funktion, die im Wesentlichen aus
> Kompatibilitätsgründen zur v1.0 vorhanden ist.

doch irgendwie verständlicher,

also LED setzen im Array mit der Funktion set_led und abschicken mit 
send_array.

Da wären alle Missverständnisse doch selbsterklärend ausgeräuumt.

von Tim  . (cpldcpu)


Lesenswert?

Ja, da hast Du vielleicht recht. Aber es macht wenig Sinn das jetzt zu 
ändern, da es nur noch mehr Verwirrung stiften würde.

von Joachim B. (jar)


Lesenswert?

Tim    schrieb:
> Ja, da hast Du vielleicht recht. Aber es macht wenig Sinn das jetzt zu
> ändern, da es nur noch mehr Verwirrung stiften würde.

OK, wenigstens DANKE das du mich nicht für doof hältst

cyblord ---- schrieb:
> Nutze auch die lib von Tim aber ich hab keine Ahnung was dein gelaber
> von wegen fastLED dauernd soll.
Di Pi schrieb:
> Joachim B. schrieb:
>> selbst an mir gezweifelt.
>
> Der erste Schritt in die richtige Richtung :)

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

Joachim B. schrieb:
> Tim    schrieb:
>> Ja, da hast Du vielleicht recht. Aber es macht wenig Sinn das jetzt zu
>> ändern, da es nur noch mehr Verwirrung stiften würde.
>
> OK, wenigstens DANKE das du mich nicht für doof hältst
>
> cyblord ---- schrieb:
>> Nutze auch die lib von Tim aber ich hab keine Ahnung was dein gelaber
>> von wegen fastLED dauernd soll.
> Di Pi schrieb:
>> Joachim B. schrieb:
>>> selbst an mir gezweifelt.
>>
>> Der erste Schritt in die richtige Richtung :)

Du hast die lib, wie von uns vermutet, einfach nur falsch benutzt. 
PUNKT.
Ob das nun an angeblich ungünstigen Funktionsnamen liegt, sei 
dahingestellt. Nur lag das Problem eben nicht in der lib, sondern in 
DEINEM Code der die lib nutzt. Trotzdem hast du auf die lib gehauen und 
den Fehler dort hingeschoben.
Also verdreh das jetzt hier nicht.

von Joachim B. (jar)


Lesenswert?

cyblord ---- schrieb:
> Du hast die lib, wie von uns vermutet, einfach nur falsch benutzt.
> PUNKT.

ja und?

> Ob das nun an angeblich ungünstigen Funktionsnamen liegt, sei
> dahingestellt.

woran denn sonst, schliesslich kann ich lesen, wenn es led_set gibt muss 
das noch lange nicht led_sync sein, ich kann nämlich unterscheiden 
zwischen setzen und syncen, aber egal, DU sollst RECHT behalten wenn es 
dir dann besser geht.


> Nur lag das Problem eben nicht in der lib, sondern in DEINEM Code der die lib 
nutzt. Trotzdem hast du auf die lib gehauen und
> den Fehler dort hingeschoben.

ich habe 2 verschiedene LIB genutzt und gleiche Ergebnisse bekommen, 
worauf sollte ich es denn sonst schieben?
uns als ich die dritte LIB nutzte klappte es wie erwartet.

> Also verdreh das jetzt hier nicht.
und was motzt du hier rum?
ich verdrehe nix, aber du pöbelst.

von Di P. (drpepper) Benutzerseite


Lesenswert?

Schluss jetzt!

von Joachim B. (jar)


Lesenswert?

ich wollte noch mal ne kleine Rückmeldung geben

ich habe ja einige Platinen hiervon bestellt und schon 2 aufgebaut:
https://github.com/JChristensen/mini1284

vorher arbeitete ich mit der Arduino FastLED Lib am m328p aber am m1284p 
funktionierte die nicht, Timingproblem, alle Farbwerte 24 x 1,5µs = 30 
µs wurden zu langsam übertragen, 33µs und die WS2812b spielten nicht 
mit.

Erst dachte ich an einen Ausreisser, baute den m1284p 2x auf.

Dann wechselte ich dem mit 16 MHz programmierten m1284p den Quarz zu 
18,432MHz und siehe da, Timing passt 30µs WS2812b läuft aber mit der 
Verständigung zur Arduino IDE war es nun aus.

Dann erinnerte ich mich hieran und band die ws2812b LIB ein die es ja 
nun auch vom Tim als Arduino LIB gibt und siehe da es läuft! auch auf 
dem m1284p

Dafür schon mal ein Riesendanke...

nun noch meinen ganzen Code auf WS2812 Lib umstricken.....

mühsam.....

von Ibram G. (ibram)


Lesenswert?

Hallo Tim,

Ich nutze Deine Lib auf dem Arduino Uno.
Klappt hervorragend im direkten Aufruf.
Da ich mehrere LED Streifen unterschiedliche Aufgabe, aber gleicher 
Logik beabsichtige (Farbverteilung an Hand von Parametern, Löschen der 
nicht genutzten LEDs), bietet es sich an, die Task in Subroutinen zu 
verpacken und mit dem jeweiligen LED-Objekt und Parametersatz zu rufen.

Ich bin noch nicht ganz fertig damit, aber auch das scheint lässig und 
ohne Verrenkungen möglich zu sein - Prima Design!

Vielen Dank,
Tarik

von Simon (Gast)


Lesenswert?

Hallo Tim,

gibt es eine Möglichkeit, die Leds zu Gruppieren, damit das struct/Array 
entsprechend klein sein kann?


Ich habe 100 Leds. Wobei immer 10 Stück hintereinander den gleichen Wert 
haben sollen.

Müsste halt eine externe Variable oder einen weiteren Parameter haben, 
um die Anzahl an gleicher aufeinaderfolgender Leds

Wenn ich das richtig sehe, müsste ich nach dem Entritt in While schleife 
dafür sorgen, dass sich jeweils nach 3 Durchläufen das Muster 
wiederholt, komm da aber noch nicht mit klar. Bin noch recht neu dabei. 
Könnte mir da evtl. jemand die Funktion kurz anpassen?
1
void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi)
2
{
3
  uint8_t curbyte,ctr,masklo;
4
  uint8_t sreg_prev;
5
6
  masklo  =~maskhi&ws2812_PORTREG;
7
  maskhi |=        ws2812_PORTREG;
8
  sreg_prev=SREG;
9
  cli();
10
  
11
  while (datlen--) {
12
    
13
    curbyte=*data++;
14
    
15
    asm volatile(
16
    "       ldi   %0,8  \n\t"
17
    "loop%=:            \n\t"
18
    "       out   %2,%3 \n\t"    //  '1' [01] '0' [01] - re
19
    #if (w1_nops&1)
20
    w_nop1
21
    #endif
22
    #if (w1_nops&2)
23
    w_nop2
24
    #endif
25
    #if (w1_nops&4)
26
    w_nop4
27
    #endif
28
    #if (w1_nops&8)
29
    w_nop8
30
    #endif
31
    #if (w1_nops&16)
32
    w_nop16
33
    #endif
34
    "       sbrs  %1,7  \n\t"    //  '1' [03] '0' [02]
35
    "       out   %2,%4 \n\t"    //  '1' [--] '0' [03] - fe-low
36
    "       lsl   %1    \n\t"    //  '1' [04] '0' [04]
37
    #if (w2_nops&1)
38
    w_nop1
39
    #endif
40
    #if (w2_nops&2)
41
    w_nop2
42
    #endif
43
    #if (w2_nops&4)
44
    w_nop4
45
    #endif
46
    #if (w2_nops&8)
47
    w_nop8
48
    #endif
49
    #if (w2_nops&16)
50
    w_nop16
51
    #endif
52
    "       out   %2,%4 \n\t"    //  '1' [+1] '0' [+1] - fe-high
53
    #if (w3_nops&1)
54
    w_nop1
55
    #endif
56
    #if (w3_nops&2)
57
    w_nop2
58
    #endif
59
    #if (w3_nops&4)
60
    w_nop4
61
    #endif
62
    #if (w3_nops&8)
63
    w_nop8
64
    #endif
65
    #if (w3_nops&16)
66
    w_nop16
67
    #endif
68
69
    "       dec   %0    \n\t"    //  '1' [+2] '0' [+2]
70
    "       brne  loop%=\n\t"    //  '1' [+3] '0' [+4]
71
    :  "=&d" (ctr)
72
    :  "r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo)
73
    );
74
    //  }
75
  }
76
  
77
  SREG=sreg_prev;
78
}

von Tim  . (cpldcpu)


Lesenswert?

Das lässt sich recht einfach realisieren, indem man die Funktion 
mehrmals hintereinander aufruft. Dass funktioniert nur mit dem alten 
Interface, da die neue Funktion bereits den Reset-delay beinhaltet.

Es gibt ein Beispiel im Repository:

https://github.com/cpldcpu/light_ws2812/blob/master/light_ws2812_AVR/Examples/Chained_writes.c

Die Daten werden erst beim Reset (>10µs delay) in die LEDs übernommen. 
So lange zwischen den Schreibzugriffen weniger als 5µs liegen, können 
diese aneinander gereiht werden.

von Simon (Gast)


Lesenswert?

Hallo Tim, danke schon einmal für die schnelle Antwort
Habe einmal 8 Leds angeschlossen. Led 1 - 4 soll den gleichen Wert 
zugewiesen bekommen. Genauso bekommt Led 5 - 8 den gleichen Wert.

Leider tut sich so noch nichts.
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include "light_ws2812.h"
4
5
#define NUM_LEDS 2
6
#define NUM_GROUP 4
7
struct cRGB ledsRGB[NUM_LEDS];
8
9
void group(struct cRGB *rgb, const int16_t leds, uint8_t group)
10
{
11
  for(uint8_t a = 0; a < NUM_LEDS; a++)
12
  {
13
    for(uint8_t b = 0; b < group; b++)
14
    {
15
      ws2812_sendarray((uint8_t*)&rgb[a], 3);
16
    }
17
  }
18
}
19
20
int main(void)
21
{
22
  ledsRGB[0].r = 255;  // Erste Led Rot
23
  ledsRGB[1].g = 255; // Zweite Led Blau
24
25
  while (1)
26
  {
27
    // Die ersten 4 Leds sollen Rot, die anderen 4 sollen Blau sein!
28
    group(ledsRGB, NUM_LEDS, 4);
29
    _delay_ms(50);
30
  }
31
}

von Tim  . (cpldcpu)


Lesenswert?

Sieht eigentlich ok aus (auch wenn der Compiler ein paar Warnings 
schmeissen wird...).

Stimmen Taktfrequenz und Portkonfiguration?

von Simon (Gast)


Lesenswert?

Klappt nun ;)

von Sascha (Gast)


Lesenswert?

Hallo,

ich habe ein Problem bei deiner APA102C Lib.
Möchte das ganze mit dem Attiny841 und HW SPI betreiben.


in /*...*/ steht der orginal Inhalt, was mache ich hier bei der HW SPI 
falsch, dass keine Daten gesendet werden?
1
inline void SPI_init(void)
2
{
3
  // MOSI | SCK
4
  DDRA |= (1<<PORTA6) | (1<<PORTA4);
5
  SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR0);
6
  /*
7
  apa102_DDRREG  |=  _BV(apa102_data);
8
  apa102_DDRREG  |=  _BV(apa102_clk);
9
  apa102_PORTREG &= ~_BV(apa102_clk);  // initial state of clk is low
10
  */
11
}
12
13
// Assumed state before call: SCK- Low, MOSI- High
14
void SPI_write(uint8_t c) {
15
  SPDR = c;
16
  while(!(SPSR & (1<<SPIF)));
17
18
  /*uint8_t i;
19
  for (i=0; i<8 ;i++)
20
  {
21
  if (!(c&0x80)) {
22
  apa102_PORTREG &= ~_BV(apa102_data); // set data low
23
  } else {
24
  apa102_PORTREG |=  _BV(apa102_data); // set data high
25
  }
26
  
27
  apa102_PORTREG |= (1<< apa102_clk); // SCK hi , data sampled here
28
29
  c<<=1;
30
  
31
  nop();  // Stretch clock
32
  nop();
33
  
34
  apa102_PORTREG &= ~_BV(apa102_clk); // clk low
35
  }
36
  // State after call: SCK Low, Dat high
37
  */
38
}

von holger (Gast)


Lesenswert?

>was mache ich hier bei der HW SPI
>falsch, dass keine Daten gesendet werden?

Setze den SS Pin auf Ausgang.

von Sascha (Gast)


Lesenswert?

Hab ich gerade selbst schon gemacht, das war das Problem. Trotzdem 
Danke! Nun gehts.

von E. T. (jadeaffenjaeger)



Lesenswert?

Hi, ich versuche auch gerade die Library zum Laufen zu bekommen. Leider 
bisher erfolglos... Mein Attiny45 erzeugt zwar ein Signal, die Lows und 
Highs sind aber ca. 10x länger als sie sein sollten. Der Attiny läuft 
auf 8MHz, F_CPU ist entsprechend definiert, die Warteperiode wird auch 
richtig erzeugt, aber mit dem WS2812-Code scheint irgendetwas nicht zu 
stimmen.

Hier der Minimalcode:
1
    1 #define F_CPU 8000000UL
2
    2 #include <util/delay.h> 
3
    3 #include "light_ws2812.h"
4
    4 
5
    5 struct cRGB led[10];
6
    6 
7
    7 int main (void)
8
    8 {
9
    9 
10
   10         int val = 255;
11
   11         int i;
12
   12 
13
   13         /*CLKPR=_BV(CLKPCE);*/
14
   14         /*CLKPR=0;*/
15
   15         while(1)
16
   16         {
17
   17                 for(i = 0; i < 10; i++)
18
   18                 {
19
   19 
20
   20                         led[i].r = 255;
21
   21                         led[i].g = 0;
22
   22                         led[i].b = 0;
23
   23                 }
24
   24 
25
   25                 ws2812_setleds(led,10);
26
   26 
27
   27                 /*val++;*/
28
   28                 /*if (val == 256) val = 0;*/
29
   29                 _delay_ms(5);
30
   30         }
31
   31 }

Hab auch spaßeshalber mal probiert, F_CPU um den Faktor 10 kleiner zu 
machen, das ändert aber nix. Irgendeine Idee, was ich falsch mache?

Angehängt sind die Logic Analyzer-Screenshots von den erzeugten Takten 
und den 5ms-Warteperioden

von dummy (Gast)


Lesenswert?

>Irgendeine Idee, was ich falsch mache?

CKDIV8 Fuse?

von E. T. (jadeaffenjaeger)


Lesenswert?

Fuses/Takt sollten mMn stimmen, da die _delay_ms() ja auch vom Takt 
abhängig ist, und mit der angegebenen F_CPU fehlerfrei funktioniert.

von Tim  . (cpldcpu)


Lesenswert?

>#define F_CPU 8000000UL

Das define muss natürlich global im Makefile gesetzt werden. Sonst sieht 
es die Lib nicht.

von Jojo S. (Gast)


Lesenswert?

und was macht:
ws2812_setleds(led, 10*3);

deine unvollständige Ausgabe löscht den Frame vielleicht wieder.

von E. T. (jadeaffenjaeger)


Lesenswert?

F_CPU global setzen hat es gefixt. Das war mir nicht klar. Danke fuer 
die schnelle Hilfe!

von c-hater (Gast)


Lesenswert?

Icke ®. schrieb:

> Auch das ist nicht möglich, weil die Farben in der gesamten Kette erst
> nach dem Reset-Puls übernommen werden und zwar nahezu gleichzeitig.

Das stimmt leider schlicht nicht, bzw. erst dann, wenn mehr als ca. 256 
LEDs angesteuert werden.

Man sieht das nur nicht, wenn man die Dinger mit einem einzelnen Burst 
füttert und dann einen stabilen Pegel ausgibt (also z.B. Latch/Reset). 
Nach "kurzer" Zeit übernehmen dann zwar alle LEDs den zuletzt an sie 
gesandten Wert, aber eben nicht gleichzeitig, sondern nach einem 
bestimmten Schema verzögert.

Wenn man den Kram nicht nach der Burst-Methode ansteuert, sonder sich 
die Mühe macht, einen Treiber zu programmieren, der zyklisch mit Vmax 
die Dinger füttert, dann kann man dieses Verhalten sehr schön sichtbar 
machen.

Das habe ich (anfangs ungewollt) bei dem Versuch getan, die PWM der LEDs 
um zusätzliche 3Bit in Software zu erweitern. Das Ergebnis sah einfach 
mal Scheisse aus und garnicht so, wie eigentlich erwartet, es zeigten 
sich nämlich "wabernde" Störungen statt gleichmäßig verringerter 
Helligkeit.

Also die 3Bit-Erweiterung zunächst provisorisch auf nur ein Bit 
zurückgebaut und die Sache mal genauer untersucht. Effektiv wird als 
Testmuster also abwechselnd immer ein Frame komplett "weiss" und ein 
Frame komplett "schwarz" rausgeschickt. Ein komplettes Frame meiner 1 
Bit PWM-Erweiterung umfasst hier also 2 Frames des LED-Feeds.

Und obwohl die effektive Framerate (~285Hz bei 60 LEDs) eigentlich 
locker für einen gleichmässigen Helligkeitseindruck reichen sollte, 
zeigte sich ein waberndes Helligkeitsmuster und diesem Wabern sah man 
sofort an, dass es irgendwie regulär ist.

Also, wenn's regular ist, dann sollte sich die Sache besser sichtbar 
machen lassen, wenn man statt 1:1 Duty 1:n verwendet und n eine 
Primzahl-1 sein lässt. Gedacht, getan: bei 1:6 ergab sich dann deutlich 
sichtbar das ganze Ausmass dieser Scheisse.

Womit für's Erste meine Idee der PWM-Erweiterung gestorben ist. Bis zu 
dem Zeitpunkt, wo ich die Gesetzmäßigkeiten der Sache vollständig 
verstanden habe, was bis dato nicht der Fall ist. Nur einige Teilaspekte 
konnte ich aufklären bzw. sind bereits aus dem 1:6-Versuch direkt 
offensichtlich geworden.

Wer Lust hat, kann ja mitknobeln, am Wochenende werde ich mal meine 
bisherigen Ergebnisse aufbereiten und hier posten. Ich werde dafür dann 
einen neuen Thread namens "The secret of WS2812B" eröffnen.

Wer das nachvollziehen will, sollte sich irgendeinen AVR besorgen mit 
SPI-fähiger UART und der Fähigkeit, mit einem 20MHz Quarz zu laufen. Ich 
habe konkret einen Tiny4313 verwendet, es sollte aber auch jeder andere 
gehen, der die genannten Anforderungen erfüllt.

von Tim  . (cpldcpu)


Lesenswert?

Diese "Über-PWM" ist im Fadecandy implementiert:

https://www.adafruit.com/product/1689

Die Updates hängen natürlich am recht langsamen PWM-Timing, daher wird 
es dort zu verzögerungen kommen. Um sich das Verhalten der LED-Treiber 
genauer anzuschauen, könnte man sich über ein Oszilloskop den 
Eingangsstrom anschauen. Ist einfacher als die visuelle Beurteilung.

von Marco H. (damarco)


Lesenswert?

Das stimmt leider auch nicht ;) Jede Flanke die über >650ns glaube ich 
liegt wird als 1 erkannt.  Reset bei >9ns bis 50ns wenn keine Daten 
kommen.

Der Reset bewirkt im Treiber das dieser die nächsten Daten die kommen 
übernimmt. Nach 24bit rastet der Treiber ein und gibt die weiteren Daten 
am Out aus. Das spiel setzt sich unendlich fort, die Länge spielt keine 
Rolle. Natürlich nur für die Framerate, je länger die Kette um so 
geringer die Framerate.


Der IN wird vom Treiber gesampelt und ob eine 1 oder 0 erkannt wird ist 
nur davon abhängig wie oft der Treiber pro Sample am IN den gleichen 
Pegel einließt.

z.Bsp 3 sampels ist der Pegel 1 -> 0, 5 Samples Pegel 1-> 1.

Der Treiber generiert am OUT ein Signal was unabhängig ist vom IN, also 
von dessen Timing.

Es gab eine Seite die dies genau beschreibt! Ich finde diese leider 
nicht mehr auf Anhieb.

von Conny G. (conny_g)


Lesenswert?

c-hater schrieb:
> Wer Lust hat, kann ja mitknobeln, am Wochenende werde ich mal meine
> bisherigen Ergebnisse aufbereiten und hier posten. Ich werde dafür dann
> einen neuen Thread namens "The secret of WS2812B" eröffnen.

Es wäre ja nur logisch, dass jeder Pixel seine Daten mit einer kleinen 
Verzögerung weitergibt - vorne wird gesampelt, hinten wird rausgegeben.
Aber OUT hängt ja nicht direkt am IN, sondern braucht ein paar 
Taktzyklen, das Signal hinten wieder anzulegen.
Also hat zeitlich gesehen jede weitere LED einen anderen Offset zum 
Latch und übernimmt die Farbe mit etwas Verzögerung.
Wenn also gelatcht wird müsste es wie ein Lauflicht mit ein paar 
Nanosekunden von vorne nach hinten durchlaufen.
Und wenn man eine passende Frequenz der Ansteuerung drüberlegt hat man 
eine schöne Interferenz.

von Marco H. (damarco)


Lesenswert?

Genau ! Deswegen sollte man eine Schlange beim verlegen vermeiden wenn 
man Videos ausgeben will.

Jede Zeile muss dann auf einen extra Ausgang die synchron gestartet 
werden.

von c-hater (Gast)


Lesenswert?

Conny G. schrieb:

> Es wäre ja nur logisch, dass jeder Pixel seine Daten mit einer kleinen
> Verzögerung weitergibt

Ja klar. Das ist aber nicht das Problem, wie meine Versuche 
eindrucksvoll zeigen. Das Problem ist vielmehr, dass bei hoher Framerate 
(und die braucht man, wenn man die PWM erweitern will) die LEDs längst 
nicht mehr bei jedem Latchimpuls die empfangenen Daten in ihre 
PWM-Schaltung übernehmen, sondern sie lassen dabei immer mal wieder 
Frames aus.

Wohlgemerkt: die Daten vom Bus übernehmen sie durchaus in jedem Frame, 
aber man muss eine sehr überlange Latchphase (eine überlange Phase 
Dauer-High tut es übrigens genauso) ausgeben, um sie dazu zu zwingen, 
die vom Bus geholten Daten auch in ihre PWM-Ausgabe zu übernehmen. 
Würden sie das nicht tun, wäre ja auch die Burstansteuerung garnicht in 
der Form möglich, wie sie üblicherweise praktiziert wird...

Blöderweise ist die Erzeugung der überlangen Latchphasen nun zwar 
programmiertechnisch überhaupt kein Problem (genau das machen ja 
letztlich die "Burst-ler"), aber leider für das Ziel einer erweiterten 
PWM wegen der dadurch verursachten massiven Reduktion der Framerate 
völlig unbrauchbar.

Deswegen ist das Spannende die Enschlüsselung des Schemas, nach dem die 
Datenübernahme in die PWM  ausgelassen wird. Das erfolgt nämlich 
keinesfalls zufällig, sondern ist offensichtlich sehr gut durchdacht. 
Bloss ist das Schema dafür ist halt leider nicht dokumentiert. 
Wahrscheinlich hat irgendeine "intellectuell property"-Scheisse das 
verhindert...

Wie auch immer: würde das Schema kennen, könnte man die PWM-Erweiterung 
darauf abstimmen und so letztlich doch noch das Ziel erreichen.

Wie gesagt, am Wochenende poste ich mal, was ich bisher über dieses 
fiese Schema herausgefunden habe und wie ich das gemacht habe.

von Marco H. (damarco)


Lesenswert?

Das kann ich nicht bestätigen.  Alles über >9ns wird als Reset 
interpretiert.  Du musst also zwischen den Frames mindestens 9ns Luft 
lassen.

Ohne das break sind die Treiber noch eingerastet und schieben das Signal 
weiter durch. Im Datenblatt stehen min. 50ns aber ab 9ns funktioniert 
dies schon.

Die maximale Framerate ergibt sich aus der Länge der Kette,Takt,Reset. 
Das Delay zwischen den LEDs ist nicht weiter relevant da es sich ja wie 
ein Domino durch die Kette vorsetzt.


Versuchst du BCM(Binary Code Modulation)? Das wird wohl kaum mit einer 
besseren Auflösung funktionieren da die Framerate viel höher sein muss.

Einfach mal messen zwischen IN/OUT  bei einen erfolgreichen Reset kommt 
am OUT für 24 BIT Zyklen nichts raus.

Schon deswegen wäre die Theorie widerlegt da der nachfolgende Treiber 
dies als Reset erkennen würde ;)

: Bearbeitet durch User
von vorbeieilender (Gast)


Lesenswert?


von Tim  . (cpldcpu)


Angehängte Dateien:

Lesenswert?

Das ganze ist recht einfach erklärt: Der PWM-Timer ist unabhängig von 
der Kommunikationslogik getaktet. Neue PWM-Settings werden nur bei 
Überlauf des PWM-Timers übernommen. Die PWM-Frequenz ist etwa 400 Hz.

Man sieht das im Oszilloskopbild oben sehr schön.

Kanal 2: Datain einer WS2812. Die LED wird abwechselnd auf 000000 und 
FFFFFF geschaltet. Jeder der sichtbaren blöcke entspricht den kompletten 
24 bit.
Kanal 1: Schaltzustand der LEDs, gemessen über Widerstand an VCC.

Wie man sieht, zeigt sich der PWM-Ausgang ziemlich unbeeindruckt von den 
vielen Updates, die an die LED gesendet werden. Erst wenn er überläuft, 
wird der nächste Datenwert übernommen.

: Bearbeitet durch User
von Marco H. (damarco)


Lesenswert?

http://wp.josh.com/2014/05/15/getting-physical-to-uncover-neopixel-pwm-secrets/

genau das wird hier beschrieben ;)

Wenn der Pegel 1->0 fällt wird ein interner Timer gestartet, von 0->1 
wird er gestoppt. Über 6µs nach dem letztens Bit werden die Daten in 
einen Buffer übernommen. Beim nächsten asynchronen PWM Zyklus werden die 
Daten aus dem Buffer auf die LED Ausgegeben.  Das kann im ungünstigen 
Fall ~2ms dauern.

Das bedeutet wenn du die Daten <2ms aktualisierst ist nicht sicher das 
sie auch auf die LED ausgeben werden.

Im Normalfall spielt das aber keine Rolle bei mehr wie einen Pixel.

: Bearbeitet durch User
von Johannes (menschenskind)


Lesenswert?

Hi ich hoffe ich bin hier korrekt.

Habe soeben meinen Code compilieren lassen, allerdings bekomme ich bei 
diesem Ausdruck:
1
ws2812_DDRREG |= maskhi; // Enable output

diese Fehlermeldung:
> pasting "DDR" and "(" does not give a valid preprocessing token

Womit kann das zusammenhängen?

Ich habe das AVR-Studio 5.1.

Danke im Voraus

von holger (Gast)


Lesenswert?

>Womit kann das zusammenhängen?

Mit deinem Programm das hier wie so oft niemand sehen kann?

von Johannes (menschenskind)


Lesenswert?

Das ist der Beispielcode von Tims Githubprojekt und zwar präzise das 
RGB-Blinky-Beispiel
Deswegen hab ich mir gespart, den zu posten, hätte das allerdings 
erwähnen sollen :)

von holger (Gast)


Lesenswert?

>Deswegen hab ich mir gespart, den zu posten, hätte das allerdings
>erwähnen sollen :)

Und ich spare mir es das jetzt selber zu suchen.

von Johannes (menschenskind)


Lesenswert?

Ok, hab den Fehler gefunden:
In der config.h hatte ich den Zielport mit "PORTD" und den Zielpin mit 
"PD6" anstatt nur "D" und "6" angegeben.
Jetzt funktioniert es.

von Ben B. (fataldiskerror)


Lesenswert?

Moin!

Schön zu sehen dass ein 3 Jahre alter Thread immer noch genutzt wird. 
Ich bin auf ihn gestoßen, während ich dabei war, meine eigene 
Implementation in ASM zu schreiben und Probleme bekam.

Vorwort:
Ich bin zwar Beruflich seit vielen Jahren in der Programmierung 
(Hochsprachen wie Java/C#, gelegentlich c++) tätig, im 
Mikrocontroller-Bereich jedoch nur privat und im kleinen. Bisher habe 
ich alle meine Projekte in ASM geschrieben und mit dieser "Library" das 
erste mal c genutzt - funktioniert soweit schon mal super!
Da alles funktioniert geht es mir hier nicht um Lösungen, sondern um 
Verständnis. Ich habe also versucht, das Rad neu zu erfinden - blöde 
Idee, aber ich wollte die Funktionsweise verstehen/nachbauen. Dabei ist 
mir das doch recht knappe Timing bei 16MHz aufgefallen. Ein einfaches 
Bit zu senden ging ja noch problemlos, das ganze über SubRoutinen zu 
lösen dann schon eher nicht mehr (Quarz für 20MHz wollte ich nicht 
nutzen, da gerade nicht griffbereit). rcall und ret zusammen sind ja 
schon 7 Takte. Habe dann das senden von Bits 24 mal hintereinander 
kopiert et voila: ich hatte eine Farbe. Nun ist das leider überhaupt 
nicht wartbar und unglaublich hässlich. Daher Google gefragt und auf den 
Artikel samt diesen Thread gestoßen, Library geladen, auf den attiny 45 
geladen und mich gefreut.

Thema 1:
Nun frage ich mich, wie das mit dem Timing funktioniert und welcher 
Compile-Parameter für das Loop-Unrolling verantwortlich ist.
Stichwort Loop-Unrolling: ich vermute(!), dass der Compiler den asm-Code 
in der Schleife mit korrekt gesetzten ldi´s immer und immer wieder 
hintereinander setzt. Sohätte man nicht das Problem mit der Dauer von 
Aufrufen von SubRoutinen. Stimmt das? In der Doku von gcc habe ich auch 
diverse Compiler-Parameter gefunden, die das machen können, die werden 
jedoch allesamt nicht genutzt. Und bei -O2 (das genutzt wird) steht:
"The compiler does not perform loop unrolling or function inlining when 
you specify -O2".
Oder verstehe ich den Compiler da falsch?

Thema 2:
Ich verstehe das "Protokoll" nicht so ganz. der Teil mit 1,25µs je Bit 
ist klar, 24 Bit je Farbe auch, n 24 Bit Werte hintereinander steuern n 
LEDs an, 50µs low übernimmt die je 24 Bit in die LED und "schaltet" die 
Farbe.
Nicht klar ist mir die Pause zwischen Bits / 24 Bits. Müssen die Bits 
direkt ohne Verzögerung aufeinander folgen (+- Toleranz)? Gleiche Frage 
für die 24 Bits: kann ich dazwischen Pausen <50µs machen, oder stört das 
das Protokoll?

Thema 3:
Kann ich nebenbei noch den Timer nutzen, oder stört das den 
Programmablauf? Ich möchte nur die ganze Ausführung nach z.B. 30 min 
deaktivieren und die LEDs abschalten (ein Pin ist high und schaltet 
damit die Versorgungsspannung der LEDs).
Das Ganze wird ein USB-Powerbank-gestütztes Einschlaflicht für meine 
Kinder.

Danke im Voraus für eure Antworten, Geduld und das Lesen dieses langen 
Posts!

von Tim  . (cpldcpu)


Lesenswert?

Ben B. schrieb:
> Thema 1:
> Nun frage ich mich, wie das mit dem Timing funktioniert und welcher
> Compile-Parameter für das Loop-Unrolling verantwortlich ist.

Die inner-loop ist komplett in Assembler implementiert. Ein Unrolling 
ist nicht notwendig.

Wenn Du das Makefile der Beispiele nutzt, wird als *.lss ein disassembly 
abgespeichert. Dort kannst Du Dir den erzeugten Code ansehen.
>
> Thema 2:
> Nicht klar ist mir die Pause zwischen Bits / 24 Bits. Müssen die Bits
> direkt ohne Verzögerung aufeinander folgen (+- Toleranz)? Gleiche Frage
> für die 24 Bits: kann ich dazwischen Pausen <50µs machen, oder stört das
> das Protokoll?

Jede Pause über 8..9µs wird als reset interpretiert. Die Pausen sollten 
als sicherheitshalber nicht länger als 5µs sein.

> Thema 3:
> Kann ich nebenbei noch den Timer nutzen, oder stört das den
> Programmablauf? Ich möchte nur die ganze Ausführung nach z.B. 30 min
> deaktivieren und die LEDs abschalten (ein Pin ist high und schaltet
> damit die Versorgungsspannung der LEDs).

Du kannst ohne Probleme die Timer verwenden. Allerdings sollten die 
Interrupts während des Schreibens auf der LEDs gesperrt sein, da sonst 
das timing durcheinander kommt.

von Ben B. (fataldiskerror)


Lesenswert?

Moin Tim,

Tim  . schrieb:
> Wenn Du das Makefile der Beispiele nutzt, wird als *.lss ein disassembly
> abgespeichert. Dort kannst Du Dir den erzeugten Code ansehen.

hab ich mal gemacht und was soll ich sagen: wow, das ist mal schwierig 
zu verstehen. Teilweise noch c-Code (Die while-Schleife) und all die 
Sprungbefehle :-) Ich muss mir mal ein einfache Beispiel schreiben und 
lernen .lss zu lesen.

Und ich muss mir einmal genau anschauen, wie das mit dem inline-asm 
funktioniert. Sieht aber recht einfach aus.

Ich habe noch nicht recht verstanden, wie du das Laden der Farbwerte in 
dem knappen Timing schaffst. Theoretisch müsste ja alle 10 Takte ein 
neues Farbwert-Bit gesendet werden (das wird durch die asm-loop-schleife 
mit brne und bitshifting erledigt, soweit ich das verstehe). danach muss 
ja aber auch noch ein neuer Farbwert geladen werden - das ist im 
asm-template nicht drin und bedeutet ja weitere Taktzyklen - wo nimmst 
du die Zeit her? Dumme Frage vielleicht :-) Für mich sieht das so aus, 
als ob die low-Phasen nach jedem Farbwert länger sind. Richtig? Falsch?
Ich hoffe, ihr könnt mein Verständniss für das "wie" etwas vergrößern 
;-)

Dank & Gruß,
Ben

von Johannes (menschenskind)


Lesenswert?

Hi Tim bzw. wer mir gerade helfen kann :):
Mein Problem ist der Betrieb bei F_CPU < 10MHz. Sobald ich von meinem 
Quarz auf 8MHz (interner Takt oder externer Quarz) umsteige, wird das 
vorher funktionierende Leuchtmuster nicht mehr dargestellt.
Ich habe das Troubleshooting durchgegangen und auch "-O3" also "optimize 
most" funktioniert nicht.
Meine F_CPU habe ich in einer config-Header-Datei.

Mein Ziel ist, vom Takt her so niedrig wie möglich zu kommen.
Worin könnte mein Problem bestehen?

Danke im Voraus.

von Tim  . (cpldcpu)


Lesenswert?

Johannes H. schrieb:
> Hi Tim bzw. wer mir gerade helfen kann :):
> Mein Problem ist der Betrieb bei F_CPU < 10MHz. Sobald ich von meinem
> Quarz auf 8MHz (interner Takt oder externer Quarz) umsteige, wird das
> vorher funktionierende Leuchtmuster nicht mehr dargestellt.
> Ich habe das Troubleshooting durchgegangen und auch "-O3" also "optimize
> most" funktioniert nicht.

Bei 8 MHz würde ich eigentlich absolut keinerlei Probleme erwarten. Wenn 
Du davon ausgehst, dass es ein Compiler-Problem ist, könnte es helfen, 
sich das disassmebly-file (LSS) anzuschauen.

Hast Du auch "-Os" probiert? -O3 hilft auf dem AVR meist nicht viel.

> Meine F_CPU habe ich in einer config-Header-Datei.

Am sinnvollsten ist es, wenn man F_CPU im Makefile definiert.

> Mein Ziel ist, vom Takt her so niedrig wie möglich zu kommen.
> Worin könnte mein Problem bestehen?

Prinzipiell sind sogar 4MHz drin. Dort kann es allerdings mit einzelnen 
LEDs schon Probleme geben.

von Tim  . (cpldcpu)


Lesenswert?

Ben B. schrieb:
> Ich habe noch nicht recht verstanden, wie du das Laden der Farbwerte in
> dem knappen Timing schaffst. Theoretisch müsste ja alle 10 Takte ein
> neues Farbwert-Bit gesendet werden (das wird durch die asm-loop-schleife
> mit brne und bitshifting erledigt, soweit ich das verstehe). danach muss
> ja aber auch noch ein neuer Farbwert geladen werden - das ist im
> asm-template nicht drin und bedeutet ja weitere Taktzyklen - wo nimmst
> du die Zeit her? Dumme Frage vielleicht :-) Für mich sieht das so aus,
> als ob die low-Phasen nach jedem Farbwert länger sind. Richtig? Falsch?
> Ich hoffe, ihr könnt mein Verständniss für das "wie" etwas vergrößern
> ;-)

Prinzipiell ist nur das Timing innerhalb eines bits kritisch. Zwischen 
den Bits kann man sich etwas mehr Zeit nehmen (bis zu 3µs). Daher ist es 
kein Problem, ein byte nachzuladen. Eine weitere Optimierung macht hier 
keinen Sinn und schränkte nur die Flexibilität unnötig ein.

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


Lesenswert?

Tim  . schrieb:
> Bei 8 MHz würde ich eigentlich absolut keinerlei Probleme erwarten.

 Bei 8MHz funktionert es nur mit ausgerolltem outerloop, ein ganzes
 Port wird fur ein bit gebraucht ('out Port, Wert') und selbst dann
 sind glitches von 125us nicht zu vermeiden.

 Wenn man es mit 'sbi Port, Pin' versucht, konnen die Specs nicht
 eingehalten werden und glitches sind immer noch drin.

 So etwas nenne ich Library fur Optimisten - falls irgendwann mal
 WS28xx rauskommt, mit strengem Timing, ist die Library nutzlos.

Tim  . schrieb:
> Prinzipiell sind sogar 4MHz drin.

 Nein, mit Sicherheit nicht. Wie du es auch machst, mit 4MHz bist du
 weit aus der Specs raus und kannst nur hoffen, dass die WS2811/2812
 Nachsicht mit dir haben.

: Bearbeitet durch User
von Konrad S. (maybee)


Lesenswert?

Marc V. schrieb:
> sind glitches von 125us nicht zu vermeiden.

Und was soll da eintausend Takte dauern, bitteschön?

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


Lesenswert?

Konrad S. schrieb:
> Und was soll da eintausend Takte dauern, bitteschön?

 Das war natürlich ein Schreibfehler, dankeschön.

von Tim  . (cpldcpu)


Lesenswert?

Marc V. schrieb:
> i 8 MHz würde ich eigentlich absolut keinerlei Probleme erwarten.
>
>  Bei 8MHz funktionert es nur mit ausgerolltem outerloop, ein ganzes
>  Port wird fur ein bit gebraucht ('out Port, Wert') und selbst dann
>  sind glitches von 125us nicht zu vermeiden.

Bitte? Sorry, das ist absoluter Unsinn. Lies Dir doch den Thread oben 
einmal durch.


> Tim  . schrieb:
>> Prinzipiell sind sogar 4MHz drin.
>
>  Nein, mit Sicherheit nicht. Wie du es auch machst, mit 4MHz bist du
>  weit aus der Specs raus und kannst nur hoffen, dass die WS2811/2812
>  Nachsicht mit dir haben.

Bei den WS2812B reicht es. WS2812S und SK6812 sind schneller getaktet, 
hier geht es nicht.

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


Lesenswert?

Tim  . schrieb:
> Bitte? Sorry, das ist absoluter Unsinn. Lies Dir doch den Thread oben
> einmal durch.

 Kann sein, werde mir mal den Thread genau durchlesen und bei github
 vorbeischauen.

Tim  . schrieb:
> Bei den WS2812B reicht es. WS2812S und SK6812 sind schneller getaktet,
> hier geht es nicht.

 Hier ist es mit Sicherheit reine Glückssache ob es funktioniert, da
 weit aus den Specs.

von Johannes (menschenskind)


Lesenswert?

Hi Tim
Ja jetzt mit der F_CPU im Makefile(über die Toolchain-->Symbols) 
funktioniert es (Auch bei 4MHz internem AtMega32-Oszillator).

Könnte mir das bitte jemand näher erklären? Da fehlt mir eindeutig noch 
tiefergehendes Wissen.

von Tim  . (cpldcpu)


Lesenswert?

Marc V. schrieb:
> Tim  . schrieb:
>> Bei den WS2812B reicht es. WS2812S und SK6812 sind schneller getaktet,
>> hier geht es nicht.
>
>  Hier ist es mit Sicherheit reine Glückssache ob es funktioniert, da
>  weit aus den Specs.

Der Knackpunkt der Sache besteht darin, zu verstehen wie die 
State-machine im WS2812 funktioniert (oben verlinkte Artikel). Es gibt 
nur zwei Timings, die überhaupt relevant sind: Die Zeit von der 
steigenden Flanke Din bis zum Sampling-Point (~400-600 ns) und die 
Reset-Dauer (~5µs).

Der Rest ist komplett unkritisch. Das Protokoll ist deutlich robuster 
als es im Datenblatt erscheint. Und das ist auch gut so, da die WS2812 
selbst natürlich auch Fertigungsschwankungen unterworfen sind. Die in 
der Lib eingestellten Timings berücksichtigen erhebliche Toleranzen. Bei 
4 Mhz können diese nicht immer eingehalten werden. Bei 8 MHz ist das 
kein Problem.

: Bearbeitet durch User
von Tim  . (cpldcpu)


Lesenswert?

Johannes H. schrieb:
> Ja jetzt mit der F_CPU im Makefile(über die Toolchain-->Symbols)
> funktioniert es (Auch bei 4MHz internem AtMega32-Oszillator).
>
> Könnte mir das bitte jemand näher erklären? Da fehlt mir eindeutig noch
> tiefergehendes Wissen.

Wahrscheinlich hat irgendein Teil des Code F_CPU nicht gesehen. Im 
Makefile ist das F_CPU define auf jeden Fall richtig aufgehoben.

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


Lesenswert?

Tim  . schrieb:
> Der Knackpunkt der Sache besteht darin, zu verstehen wie die
> State-machine im WS2812 funktioniert (oben verlinkte Artikel). Es gibt
> nur zwei Timings, die überhaupt relevant sind: Die Zeit von der
> steigenden Flanke Din bis zum Sampling-Point (~400-600 ns) und die
> Reset-Dauer (~5µs).

 Da hast du Recht, habe inzwischen auch meine 8 MHz Routine angeschaut.
 Ich habe 6:5 bei Log.1 und 3:8 bei Log.0.
 Und habe auch ordentlich kommentiert, dass die Null auch mit nur
 2 Takten Log.1 geht...


> Der Rest ist komplett unkritisch. Das Protokoll ist deutlich robuster
> als es im Datenblatt erscheint.

 Ja, da hast du wieder Recht.

von Dirk K. (dekoepi)


Lesenswert?

Eine Bibliothek, die "magisch" funktioniert, ist zwar nett - aber so 
etwas eigentlich Einfaches kann man auch selber versuchen zu verstehen 
und umzusetzen.

Ich wollte das mal auf ATmega328 in physischer Form des Arduino Nano 
testen - ohne ASM, ohne besondere Kniffe, direkt als Schnellschuss in 
der Arduino-IDE. Lerneffekt beachtenswert.

Schleifen zum Auseinandernehmen des 24-Bit-Werts je LED führen zu 
falschem Timing. Ich musste manuelles "loop unrolling" verwenden. Nicht 
hübsch, aber funktioniert. Für mehr Ordnung und Übersicht einige 
wiederkehrende Funktionsblöcke als inline eingefügt.

Der letzte Fehler kam daher, dass die Arduino-lib den Timer0 aktiviert 
und für Delay(), millis() und so weiter nutzt. Auch das stört das Timing 
ungemein und führt dann zu Fehlfarben und sporadisch ungewollt 
aufblitzenden LEDs.

Hier die korrekte Lösung (im Sinne von: funktioniert wie gewollt):
http://pastebin.com/312fCpxB

Ist recht einfach und übersichtlich, zudem bei den Timern noch mal 
aufgedröselt, welche Flags das nun sind.

Farbfehler, wenn die Arduino-lib reinfunkt:
https://youtu.be/h7ubECPKRJs

Korrekt sieht es dann so aus:
https://youtu.be/hwUaI-tJ2UE

Bei der Suche findet man so viel Quatsch und teils unverständliche 
Lösungen, da kann eine Variante mehr nicht schaden ;) Vielleicht bastel 
ich das noch für den STM32F030 - gegebenenfalls mit N-FET/P-FET zum 
sauberen Schalten.

von Johannes (menschenskind)


Lesenswert?

Hallo,

Wie müsste man die Befehle fürs Senden modifizieren, damit das Data-Pin 
wie ein OpenCollector/Drain agiert?

Ich möchte nämlich den µC(AVR) an ner 3V Knopfzelle und die LED über 
eine 5V Ladungspumpe betreiben.

Danke im Voraus.

von Tim (Gast)


Lesenswert?

Johannes H. schrieb:
> Wie müsste man die Befehle fürs Senden modifizieren, damit das Data-Pin
> wie ein OpenCollector/Drain agiert?
>
> Ich möchte nämlich den µC(AVR) an ner 3V Knopfzelle und die LED über
> eine 5V Ladungspumpe betreiben.


Die AVR unterstützen, soweit ich weiss, keine echten open-drain 
Ausgänge. Die maximale Spannung an den I/O pins sollte nicht über 
VCC+0.5V liegen, sonst fängt die Clamp-Diode an zu leiten.

Du benötigst also einen echten Pegel-Converter.

von Johannes (menschenskind)


Lesenswert?

Danke Tim, die Charakteristik hätte ich eigentlich selber nachgucken 
müssen...
OK, entweder Levelshifter oder über nen Transistor könnte man es lösen. 
(Transistor und 2 Widerstände sind natürlich günstiger im Preis)

Aber falls ich die Transistorlösung wähle, wird das Signal ja 
invertiert. Welche Zeilen in Deinem Assemblercode müsste man dann 
modifizieren?

von Tim (Gast)


Lesenswert?

Johannes H. schrieb:
> Aber falls ich die Transistorlösung wähle, wird das Signal ja
> invertiert. Welche Zeilen in Deinem Assemblercode müsste man dann
> modifizieren?

Einfach die masken verändern.

https://github.com/cpldcpu/light_ws2812/blob/master/light_ws2812_AVR/Light_WS2812/light_ws2812.c#L110

von Johannes (menschenskind)


Lesenswert?

Hallo Tim

Also einfach eine simple Vertauschung?
1
masklo |= maskhi&ws2812_PORTREG;
2
maskhi = ~ws2812_PORTREG;

von Johannes (menschenskind)


Lesenswert?

Tim?

von Johannes (menschenskind)


Lesenswert?

Ok, hab's gelöst.
Man muss die Übergabe der Masken in dieser Zeile vertauschen:
1
: "r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo)

von Lars H. (hufnala)


Lesenswert?

Hallo Tim,
hallo alle,

vielen Dank für die super lib, habe damit und den Beispielen in wenigen 
Stunden bei meinen bescheidenen C-Kenntnissen einen ATMega mit Stripe 
zum laufen gebracht, Animationen erweitert und das Ganze ohne jegliche 
Probleme Out of the Box! Echt einfach.... :-)

Nachdem mein Projekt Richtung 2 Stripes geht, und ich noch Platz in RAM 
& Flash habe, plane ich den 2. Stripe gesondert anzusteuern (weiß noch 
nicht gang genau welche Animationen ich laufen lassen möchte,
auf jeden Fall eher unterschiedliche z.B. 2 Richtungen als exorbitant 
schnelle und viele LEDs eher so Richtung 2*100 LEDs).

Ein erster Test den ws2812_pin als (globale) Variable umzudeklarieren 
war auch gleich mal erfolgreich.

a) Quick and dirty : Ich lasse die globale Variable, ist zwar bäh, aber 
einfach und mit einem Byte RAM :-)

b) Ich bastele an alle Funktionen die ws2812_pin verwenden einfach eine 
Variable dran. Wenn ich das richtig verstehe auch nur ein Byte RAM und 
schöner und richtiger.

c) Mit viel Phantasie könnte man noch das erste Byte des LED Array 
"umwidmen" oder besser vermtl. eine Struct aufbauen. Dann bräuchte man 
nicht mal 2 Aufrufe (wenn zum gleichen Zeitpunkt geschrieben werden 
soll) sondern könnte das Ziel über die Daten mitgeben und diese einfach
manipulieren. Wäre aber rundweg mehr Tipparbeit da die "led" Struktur 
überall in diese Struktur geschoben werden müsste oder wenigstens einmal
zugewiesen / kopiert (Zeiger zugewiesen) werden müsste.

d) Ein weiterer Weg wäre über ein 2. Define, aber wie die Gesamtstruktur 
dann aussieht kann ich mir nicht erklären. Und ich glaube dafür gäbe es
Schläge :-).

Ihr seht, meine Erfahrung hält bei Design und sicherlich auch der 
Umseztung sich in Grenzen. Auch wenn ich über CTRL-C/V ein klein wenig 
hinaus bin tendiere ich zu b). Bin aber nicht sicher ob ich was übersehe 
oder das mit den 2 Stripes aus anderen Gründen nicht geht.

Wenn's mehr Interesse gibt, bin ich auch durchaus bereit das nach 
Empfehlung runter zu tippen und zu testen. Kann aber bei zu vielen 
Zeigern auch scheitern, aber nur so lernt man...

Danke für Eure Unterstützung!

//hufnala

von Conny G. (conny_g)


Lesenswert?

Ich kenne die Lib jetzt nicht so genau, aber es gibt da noch eine 
Challenge:
Die beiden Bitstreams müssen dann gleichzeitig gesendet werden und das 
ist eine Timing-Geschichte.
Ich habe im Kopf, dass das Timing auf Seiten AVR nicht so viel Luft hat 
und mit Berechnung/Vorbereitung der Aminmation und dem Rausstreamen wird 
es dann eng, wenn nicht sogar nicht mehr möglich.

Warum nicht einfach die 2 Streifen hintereinander hängen und einfach 
separat ihre Werte berechnen?
Das ist einfach eine Halbierung der Frame Rate und wird sicher 
funktionieren.

Genau das geschieht umgekehrt mit Deinen Änderungen: Du versuchst eine 
Verdoppelung der Frame Rate.

von Lars H. (hufnala)


Angehängte Dateien:

Lesenswert?

Hi, sorry dass ich mich erst jetzt melde, habe ein paar Tage nicht 
gelesen...

Die Antwort ist einfach : Mein Controller war in der Mitte geplant, dann 
hätte ich zurück gemusst mit der Data Leitung. Über 4m nicht mein 
favorite :-).

Die Frame Rate ist mir egal, ist wie beschrieben eh langsam. Hab mir das 
nochmal angeschaut, sollte mit der Maske ja schon gehen, das habe ich 
übersehen. Aktuell kämpfe ich mit einem anderen Problem.

Die Lib funktioniert nach Umstellung auf meinem ATMega8 mit 16MHz nur 
wenn ich als Optimierung -O3 einschalte. Damit ist der Code aber mehr 
als 2k Byte größer als mit -OS. Mit -OS funktioniert (über 
Falscheinstellung am Code:Blocks auch OS und O3 gemeinsam probiert) 
alles andere (RS232 / IRMP) so dass es irgendwo an der LIB liegen 
müsste. Noch sind die 2k mehr kein Problem, aber schön ist was anderes 
(ging von 4k auf 6.6k rauf).

Das Timing ist irgendwie seltsam. Bei 8Mhz dachte ich eine Gesamtzeit 
des Pakets von 12ms gemessen zu haben. Als es mit 16Mhz nicht 
funktioniert hat,
war das ganze bei 6ms, jetzt wo es geht sind es 3ms was wohl auch den 
100 LEDs entspricht. Das einzige was ich noch geändert habe ist den 
Reset von 300us auf 70us zu ändern, die Einstellung hatte ich übersehen.

Irgendwer eine Idee?
Die IRMP lib ist schon älter, habe nicht den neuesten Stand. Anbei mal 
das Hauptprogramm. Die LIB ist die aktuelle aus dem Git.

Hier mal die Meldungen beim Compilieren. AVR gcc ist 4.8.3., aktuell aus 
Opensuse Leap 42.2.
1
-------------- Build: Release in Stripe_ATMega8 (compiler: GNU GCC Compiler for AVR)---------------
2
3
avr-gcc -Wextra -Wall -DF_CPU=16000000UL -mmcu=atmega8 -O3 -I/usr/include -c rainbow.c -o obj/Release/rainbow.o
4
rainbow.c: In function 'loadEEColor':
5
rainbow.c:203:1: warning: comparison is always true due to limited range of data type [-Wtype-limits]
6
 if ((Addr >= 0) && (Addr <= 8))
7
 ^
8
rainbow.c: In function 'setprogram':
9
rainbow.c:468:2: warning: comparison is always false due to limited range of data type [-Wtype-limits]
10
  if (newprogram < 0) newprogram = lastprogram;
11
  ^
12
avr-g++ -L/usr/lib -o bin/Release/Stripe_ATMega8.elf obj/Release/irmp.o obj/Release/light_ws2812.o obj/Release/rainbow.o  -mmcu=atmega8 -Wl,-Map=bin/Release/Stripe_ATMega8.map,--cref  
13
/usr/bin/avr-ld: warning: -z relro ignored.
14
/usr/bin/avr-ld: skipping incompatible /usr/lib/libm.so when searching for -lm
15
/usr/bin/avr-ld: skipping incompatible /usr/lib/libm.so when searching for -lm
16
/usr/bin/avr-ld: skipping incompatible /usr/lib/libc.so when searching for -lc
17
Output file is bin/Release/Stripe_ATMega8.elf with size 18,73 KB
18
Running project post-build steps
19
avr-size bin/Release/Stripe_ATMega8.elf
20
   text     data      bss      dec      hex  filename
21
   6642       71      432     7145     1be9  bin/Release/Stripe_ATMega8.elf
22
avr-objdump -h -S bin/Release/Stripe_ATMega8.elf > bin/Release/Stripe_ATMega8.lss
23
avr-objcopy -R .eeprom -R .fuse -R .lock -R .signature -O ihex bin/Release/Stripe_ATMega8.elf bin/Release/Stripe_ATMega8.hex
24
avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex bin/Release/Stripe_ATMega8.elf bin/Release/Stripe_ATMega8.eep
25
avr-objcopy --no-change-warnings -j .lock --change-section-lma .lock=0 -O ihex bin/Release/Stripe_ATMega8.elf bin/Release/Stripe_ATMega8.lock
26
avr-objcopy --no-change-warnings -j .signature --change-section-lma .signature=0 -O ihex bin/Release/Stripe_ATMega8.elf bin/Release/Stripe_ATMega8.sig
27
avr-objcopy --no-change-warnings -j .fuse --change-section-lma .fuse=0 -O ihex bin/Release/Stripe_ATMega8.elf bin/Release/Stripe_ATMega8.fuse
28
srec_cat bin/Release/Stripe_ATMega8.fuse -Intel -crop 0x00 0x01 -offset  0x00 -O bin/Release/Stripe_ATMega8.lfs -Intel
29
/bin/sh: srec_cat: Kommando nicht gefunden.
30
Process terminated with status 127 (0 minute(s), 0 second(s))
31
0 error(s), 3 warning(s) (0 minute(s), 0 second(s))

Vielen Dank für Eure Unterstützung! Jetzt ist dann erst mal Party :-)

Ansonsten Euch allen einen Guten Rutsch ins Jahr 2017!!!

//hufnala

von nappel (Gast)


Lesenswert?

Vielen Dank für die großartige Library!!!
Habe sehr schnell viele Animationen realisieren können.

von Daniel B. (phill93)


Lesenswert?

Hallo,

versuche gerade die Bibliothek auf einem attiny48 zum Laufen zu bringen.
Nur Leuchten die LEDs nur in der initial Farbe.

LEDs: https://www.pololu.com/product/2535 (mit der Arduino Bibliothek 
gehen sie)

Kann das sein das der attiny48 nicht supported wird?

Gruß

Phill93

von Daniel B. (phill93)


Lesenswert?

Hat sich erledigt.
Die CKDIV8 Fuse war noch gesetzt.

von Marcel K. (viewer)


Lesenswert?

Hallo Forum Gemeinde,

Erst mal ein großes Dankeschön an Tim. Eine echt tolle Lib die Du da für 
alle zur Verfügung gestellt hast. Auch Deine Blog habe ich schon 
gelesen. Immer wieder toll zu sehen, dass sich Menschen die Zeit nehmen 
sich so zu engagieren und sein Wissen mit anderen zu Teilen.

Zu meinem Anliegen:
Nein, ich habe kein Problem mit der Anwendung der Lib bzw. mit der 
Ansteuerung der LEDs. Es liegt eher am Verständnis des Codes.
Mir reicht es nicht den Code einfach nur zu verwenden sondern ich möchte 
ihn auch gerne verstehen. Daher habe ich mich seit ein paar Tagen mit 
den ASM Befehlen beschäftigt. Somit hat sich die Anzahl der Fragezeichen 
deutlich verringert.
Ich habe zum Verständnis die Funktion auf die wichtigsten Befehle 
reduziert.
1
asm volatile(
2
  " lsl %[dat],#24          \n\t"  // [ 1]  => OK
3
  " movs %[ctr],#8          \n\t"  // [ 2]  => OK
4
  " ilop%=:                 \n\t"  // [ 3]
5
  " lsl %[dat], #1          \n\t"  // [ 4]  => OK
6
  " str %[maskhi], [%[set]] \n\t"  // [ 5]  => OK
7
  " bcs one%=               \n\t"  // [ 6]
8
  " str %[masklo], [%[clr]] \n\t"  // [ 7]  => OK
9
  " one%=:                  \n\t"  // [ 8]
10
  " sub %[ctr], #1          \n\t"  // [ 9]  => OK
11
  " str %[masklo], [%[clr]] \n\t"  // [10]  => OK
12
  " beq  end%=              \n\t"  // [11]
13
  " b   ilop%=              \n\t"  // [12]
14
  " end%=:                  \n\t"  // [13]
15
  :[ctr] "+r" (i)
16
  :[dat] "r" (curbyte), [set] "r" (set), [clr] "r" (clr), [masklo] "r" (masklo), [maskhi] "r" (maskhi)
17
    );
Generell ist mir schon klar was die Funktion machen soll. Es gibt eine 
äußere und innere Schleife. Die äußere Schleife läuft von 8 bis 0 um die 
einzelnen Bit des Bytes zu ermitteln. Die innere Schliefe ermittelt den 
Wert des einzelnen Bits um entsprechend die Dauer der Ansteuerung des 
logischen Pins zu realisieren.
Die äußere Schleife ist die „i“ Schleife. Diese Schleife scheint das
1
ilop%=:
 und
1
b ilop%=
 zu sein. Aber wie funktioniert dieser Befehl? Ist
1
ilop
 ein frei gewählter Name? Worin besteht der Unterschied zwischen
1
%=:
 und
1
%=
? Der
1
b ilop%=
 Branch Befehl scheint die Loop so lange abzuarbeiten, bis der Wert „0“ 
erreicht ist.

Was ich auch nicht verstehe, sind die drei Befehle
1
bcs one%=
,
1
one%=:
 und
1
beq  end%=
. Ich weiß schon, dass
1
bcs
 branch on carry set heißt, aber was heißt das für die Schleife? Zuerst 
wird der logische Prozessor Port Pin auf „high“ gezogen. Aber was 
passiert danach?
Tim hat am 02.02.2014 mal diese Schleife erwähnt:
1
while (--i) {
2
  PORT=HI;
3
  if (data&128) PORT=LO;
4
  data<<=1;
5
  PORT=LO;
6
}

Das verstehe ich schon da ja mit der If Abfrage bereits früher der Port 
Pin wieder auf low gezogen wird, falls das 8. Bit „1“ ist. (dazwischen 
sind ja die unterschiedlichen delay Zeiten)
Aber woher kommt das
1
one
?
1
beq end%=
 heißt vermutlich, das zu einem bestimmten Zeitpunkt (branch if equal) 
zu
1
end%=:
 gesprungen wird. Was wird denn auf
1
eqal
 getestet?

Bereits am 09.09.2013 schrieb „Icke ®“ hier im Forum, dass es genial 
wäre das Datenbit in das Carry zu schieben. Was ist denn das geniale 
daran? Kann mir das einer erklären?

Ich würde mich freuen wenn mir jemand hier im Forum weiter helfen 
könnte.

Viele Grüße und noch einen schönen Tag

von Tim  . (cpldcpu)


Lesenswert?

Freut mich, dass Du den Code genau verstehen musst. Für den Einstieg in 
Assembler ist GCC-inline ASM allerdings gleich ziemlich kryptisch. Hier 
gibt es eine Übersicht:

http://www.ethernut.de/de/documents/arm-inline-asm.html

Marcel K. schrieb:
> Ist ilop ein frei gewählter Name? Worin besteht der Unterschied
> zwischen%=: und%=

ilop%=: ist ein Label. Das wird durch den Doppelpunkt deklariert
"%=" erzeugt einen unique identifier.

https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
1
  " lsl %[dat], #1          \n\t"  // [ 4]  => OK
2
  " str %[maskhi], [%[set]] \n\t"  // [ 5]  => OK
3
  " bcs one%=               \n\t"  // [ 6]
4
  " str %[masklo], [%[clr]] \n\t"  // [ 7]  => OK
5
  " one%=:                  \n\t"  // [ 8]

Deine Fragen zu den Sprüngen zielen auf die Nutzung von Flags ab. Du 
solltest Dir einmal anschauen, welche Befehle welche Flags setzen. Der 
Code ist teilweise etwas verwirrend, da die Sprungbefehle von Flags 
abhängen, die von weiter zurück liegenden Befehlen gesetzt werden.

Im obigen Fall wird das auszugebende bit von "lsl" ins carry-flag 
geschoben. Wenn das bit eine "1" war, wird durch "bcs" "str" 
übersprungen. "str" zieht den Ausgang vorzeitig auf "0", wenn ein kurzer 
Puls ausgegeben wird.

von Marvin (Gast)


Lesenswert?

Hallo zusammen,

nachdem hier die Bibliothek vorgestellt und reichlich diskutiert wurde, 
dachte ich es ist der richtige Ort um meine Frage zu stellen.

Ich verwende den µC LPC11C24 von NXP, der auf einem ARM Cortex-M0 
basiert,
daher möchte ich die light_ws2812_ARM bentutzen.
Da das Vorgehen in der Readme ganz gut beschrieben ist bin ich auch nach 
ihr vorgegangen.
Allerdins habe ich folgendes Problem:
In der Readme steht:
- Change i/o pin settings according to the I/O pin you are using:
  - Define `LIGHT_WS2812_GPIO_PIN=XXX`
  - Define `LIGHT_WS2812_GPIO_PORT=XXX`

Im Code dann:
1
  #define ws2812_port_set ((uint32_t*)&LIGHT_WS2812_GPIO_PORT->SET0)  // Address of the data port register to set the pin
2
  #define ws2812_port_clr ((uint32_t*)&LIGHT_WS2812_GPIO_PORT->CLR0)  // Address of the data port register to clear the pin

Die Adresse des von mir verwendeten Port ist 0x40044084, was ich 
anstelle von &LIGHT_WS2812_GPIO_PORT eingefügt habe. Jedoch ohne Erfolg.
Kann mir jemand ein Beispiel liefern wie die Umsetzung richtig ist ?

Vielen Dank im Voraus.

von Tim  . (cpldcpu)


Lesenswert?

> In der Readme steht:
> - Change i/o pin settings according to the I/O pin you are using:
>   - Define `LIGHT_WS2812_GPIO_PIN=XXX`
>   - Define `LIGHT_WS2812_GPIO_PORT=XXX`

Ich finde leider meinen LPC810 testcode gerade nicht mehr. Generell 
heissen die I/O ports auf den kleinen LPCs aber "LPC_GPIO_PORT".

Also:

#define LIGHT_WS2812_GPIO_PORT LPC_GPIO_PORT
#define LIGHT_WS2812_GPIO_PIN XXX

Sehe auch gerade, dass sich im include wohl ein bug eingeschlichen hat. 
Kann leider nicht alle ARM-Varianten testen.

> Die Adresse des von mir verwendeten Port ist 0x40044084, was ich
> anstelle von &LIGHT_WS2812_GPIO_PORT eingefügt habe. Jedoch ohne Erfolg.
> Kann mir jemand ein Beispiel liefern wie die Umsetzung richtig ist ?

Was genau funktioniert denn nicht? Lässt sich der code compilieren? 
Liegen am Ausgang signale an? Stimmt das timing nicht?

von Marvin (Gast)


Lesenswert?

Ich glaube das erste Problem liegt daran, dass mir nicht ganz klar ist 
was durch
1
#define LIGHT_WS2812_GPIO_PORT LPC_GPIO_PORT
2
#define LIGHT_WS2812_GPIO_PIN XXX
erreicht werden soll.

Über
1
LPC_IOCON_TypeDef->PIO3_0
kann beispielsweise auf den Pin 0 vom Port 3 zugegriffen werden.

"LPC_GPIO_PORT" kann ich in CMSIS nicht finden, gibt es das 
möglicherweise in den LPC-Bibliotheken ?

Um welchen Bug handelt es sich ?

Das Problem liegt darin, dass sich der Code nicht kompilieren lässt.
Ich würde es sehr gerne Testen und dann ein Feedback geben, da ich das 
Projekt sowieso dokumentieren muss.

von Johannes S. (Gast)


Lesenswert?

also ich finde in der lpc11xx.h sofort das hier:
1
#define LPC_GPIO3             ((LPC_GPIO_TypeDef   *) LPC_GPIO3_BASE )

du fummelst im IOCON Register rum, da werden nur Einstellungen zum IO 
Pin vorgenommen.

Bei einem LPC1347 habe ich WS2812B per SPI angesteuert, das geht bei den 
LPC gut weil man den Takt für SPI sehr genau einstellen kann.

von Johannes (menschenskind)


Lesenswert?

Hallo Tim,

Bei meiner funktionierenden Elektronik(ATTiny85 & 3 WS2812b) wollte ich 
noch etwas die Batterielebensdauer vergrößern und den internen Takt von 
8 auf 6,4MHz verringern, was ja einfach mit den CKSEL Fuses eingestellt 
werden kann.
Da der µC dann im ATTiny15 Compatibility Mode ist, beträgt der interne 
Systemtakt dann 1,6MHz lt. Datenblatt.

Ich habe also im Code die F_CPU auf diesen Wert abgeändert, die Fuses 
programmiert und den Code geflasht.
Aber leider ohne erwünschtes Ergebnis.
Gibt es also evtl. noch etwas anderes, was ich anpassen müsste?
Evtl. passt durch den niedrigeren Takt das Timing für das Datensignal 
nicht mehr, aber das kann ich mir mangels Messhardware nicht anschauen.

Gruß
Hannes

von Icke ®. (49636b65)


Lesenswert?

Johannes H. schrieb:
> Systemtakt dann 1,6MHz lt. Datenblatt

Das dürfte deutlich zu wenig sein.

> Evtl. passt durch den niedrigeren Takt das Timing für das Datensignal
> nicht mehr

So ist es, WIMRE sind 4MHz schon sportlich.

von Helmut H. (helmuth)


Lesenswert?

Johannes H. schrieb:
> Da der µC dann im ATTiny15 Compatibility Mode ist, beträgt der interne
> Systemtakt dann 1,6MHz lt. Datenblatt.

Das Timing wird durch NOPs realisiert, siehe
https://github.com/cpldcpu/light_ws2812/blob/master/light_ws2812_AVR/Light_WS2812/light_ws2812.c

"// Warn or throw error if this timing can not be met with current F_CPU 
settings."
Hats beim Compilieren nicht gewarnt?

von Joachim B. (jar)


Angehängte Dateien:

Lesenswert?

Johannes H. schrieb:
> den internen Takt von
> 8 auf 6,4MHz verringern

Helmut H. schrieb:
> Das Timing wird durch NOPs realisiert

das muss man dann nur erweitern zu 6,4 Mhz

alles lösbarbei dder Arduino fast LED Lib musste ich für den 
ATmegas1284p auch eingreifen, der 1284p hat ein Adressregister mehr 
welches für 10% langsameres Timing verantwortlich ist.

#if defined(_AVR_ATmega1284P_)
  #define NS(_NS) ( (_NS * ( (F_CPU*9L/10L) / 1000000L))) / 1000
  #define CLKS_TO_MICROS(_CLKS) ((long)(_CLKS)) / ((F_CPU*9L/10L) / 
1000000L)
#else
  #define NS(_NS) ( (_NS * (F_CPU / 1000000L))) / 1000
  #define CLKS_TO_MICROS(_CLKS) ((long)(_CLKS)) / (F_CPU / 1000000L)
#endif

: Bearbeitet durch User
von Johannes (menschenskind)


Lesenswert?

Joachim B. schrieb:
> das muss man dann nur erweitern zu 6,4 Mhz

Was meinst Du mit erweitern?
Die 6,4MHz sind aber nur der Oszillator! Der Systemtakt ist in diesem 
Compatibility-Mode aber noch durch 4 geteilt, also nur bei 1,6MHz.

Weiterhin muss ich auch erst mal die aktuelle Bibliothek einbinden. Ich 
habe in meinem Projekt noch eine Version von 2018(?).

von Joachim B. (jar)


Lesenswert?

Johannes H. schrieb:
> Was meinst Du mit erweitern?

na die Lib, machte ich ja auch!

Johannes H. schrieb:
> noch durch 4 geteilt, also nur bei 1,6MHz

kann man berücksichtigen!

Ich habe mich damals durch den fremden Code gewühlt, das kannst du heute 
auch.

von Helmut H. (helmuth)


Lesenswert?

Joachim B. schrieb:
> kann man berücksichtigen!

Habe keine Ahnung welche Version der library verwendet wurde.
In der oben zitierten wird die Anzahl der NOPs anhand der F_CPU 
ermittelt.
Weniger als 0 NOPs wären erforderlich, um das Timing bei 1,6 MHz zu 
erreichen. Das mag zwar mathematisch möglich sein, geht aber 
softwaretechnisch (noch?) nicht.
aaO:
1
// Fixed cycles used by the inner loop
2
#define w_fixedlow    2
3
#define w_fixedhigh   4
4
#define w_fixedtotal  8   
5
6
// Insert NOPs to match the timing, if possible
7
#define w_zerocycles    (((F_CPU/1000)*w_zeropulse          )/1000000)
8
9
#define w1 (w_zerocycles-w_fixedlow)
10
#if w1>0
11
  #define w1_nops w1
12
#else
13
  #define w1_nops  0
14
#endif
15
16
// The only critical timing parameter is the minimum pulse length of the "0"
17
// Warn or throw error if this timing can not be met with current F_CPU settings.
18
#define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000)
19
#if w_lowtime>550
20
   #error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?"
21
#elif w_lowtime>450
22
   #warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)."
23
   #warning "Please consider a higher clockspeed, if possible"
24
#endif

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Helmut H. schrieb:
> Weniger als 0 NOPs wären erforderlich, um das Timing bei 1,2 MHz zu
> erreichen.

aber es geht nicht um 1,2MHz?

Johannes H. schrieb:
> bei 1,6MHz.

sind also nicht weniger als 0 NOPs, ob es für 1,6MHz reicht kann 
getestet werden!

aber stimmt schon ist sportlich, wobei ich kaum glaube das es den 
Aufwand lohnt!

Johannes H. schrieb:
> den internen Takt von
> 8 auf 6,4MHz verringern

von Helmut H. (helmuth)


Lesenswert?

Joachim B. schrieb:
> aber es geht nicht um 1,2MHz?

hatte mich vertippt und später korrigiert.

Die Zeit für low ist zu lang, es braucht 2 Taktzyklen:

((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000)
 (0 + 2) * 1000000 / 1600 = 1250

Deswegen wundert es mich, dass es kompiliert.

: Bearbeitet durch User
von Icke ®. (49636b65)


Lesenswert?

Einfach mal das Datenblatt der WS2812B hernehmen und rechnen.

https://www.digikey.com/en/datasheets/parallaxinc/parallax-inc-28085-ws2812b-rgb-led-datasheet

Eine Null wird bspw. mit 400ns High und 850ns Low codiert, die Eins mit 
800ns High und 450ns Low. Die Toleranz beträgt +-150ns. Bei 1,6MHz 
dauert aber ein Takt schon 625ns und für das Toggeln eines Pins mit SBI 
werden zwei Takte benötigt. Es kann also mit 1,6MHz nicht funktionieren.

von Joachim B. (jar)


Lesenswert?

Johannes H. schrieb:
> Die 6,4MHz sind aber nur der Oszillator! Der Systemtakt ist in diesem
> Compatibility-Mode aber noch durch 4 geteilt, also nur bei 1,6MHz.

und wir wissen nicht mal ob es mit 8MHz (:4) funktioniert.
Sind wir einem Troll aufgesessen?

Icke ®. schrieb:
> Eine Null wird bspw. mit 400ns High und 850ns Low codiert, die Eins mit
> 800ns High und 450ns Low. Die Toleranz beträgt +-150ns. Bei 1,6MHz
> dauert aber ein Takt schon 625ns und für das Toggeln eines Pins mit SBI
> werden zwei Takte benötigt. Es kann also mit 1,6MHz nicht funktionieren

dabei ist es dann egal ob 8MHz oder 6,4MHz

von Icke ®. (49636b65)


Lesenswert?

Joachim B. schrieb:
> und wir wissen nicht mal ob es mit 8MHz (:4) funktioniert.

Der Erfinder der Routine schreibt:

Tim  . schrieb:
> Das Protokoll ist deutlich robuster
> als es im Datenblatt erscheint. Und das ist auch gut so, da die WS2812
> selbst natürlich auch Fertigungsschwankungen unterworfen sind. Die in
> der Lib eingestellten Timings berücksichtigen erhebliche Toleranzen. Bei
> 4 Mhz können diese nicht immer eingehalten werden. Bei 8 MHz ist das
> kein Problem.

von Falk B. (falk)


Lesenswert?

Joachim B. schrieb:
> sind also nicht weniger als 0 NOPs, ob es für 1,6MHz reicht kann
> getestet werden!

Ich hab sowas auch mal programmiert. Unter 5 MHz war da praktisch nix 
mehr machbar, bestenfalls mit "magischen" Frequenzen, die EXAKT die 
Bittimings mit Null NOPs schaffen. Das hab ich dann aber weggelassen, 
wozu auch? Es gibt den Sleep Mode, wenn man Strom sparen will!

Beitrag "Re: Frage zu IR-Remote+LED-Strips an AVR"

> aber stimmt schon ist sportlich, wobei ich kaum glaube das es den
> Aufwand lohnt!

Nö.

von Falk B. (falk)


Lesenswert?

Icke ®. schrieb:
> Der Erfinder der Routine schreibt:
>
> Tim  . schrieb:
>> Das Protokoll ist deutlich robuster
>> als es im Datenblatt erscheint.

Da haben schon viele Leute die gegenteilige Erfahrung gemacht.

von Johannes (menschenskind)


Lesenswert?

Hey Leute,
Danke für den detaillierten Input. Dann muss ich anderweitig sehen, ob 
ich den Stromverbrauch noch weiter senken kann.

Der µC wird am Ende der while in den "Idle" Modus geschickt und mit nem 
TimerInterrupt wieder "Active" gesetzt.
Im PRR habe ich den ADC und das USI deaktiviert. Aber gerade bei Lesen 
des Datenblattes gesehen, dass im ACSR noch der Komparator deaktiviert 
werden kann. Mal sehen, was das bringt.

von Falk B. (falk)


Lesenswert?

Johannes H. schrieb:
> Der µC wird am Ende der while in den "Idle" Modus geschickt und mit nem
> TimerInterrupt wieder "Active" gesetzt.

Schon mal gut, zieht aber immer noch relativ viel. Deutlich mehr spart 
man mit Power Save mode oder gar Power Down. Man kann auch den Watchdog 
Timer zum Aufwachen nutzen.

> Im PRR habe ich den ADC und das USI deaktiviert.

ADC ist sinnvoll, USI nicht, denn das zieht praktisch keinen Strom.

> Aber gerade bei Lesen
> des Datenblattes gesehen, dass im ACSR noch der Komparator deaktiviert
> werden kann. Mal sehen, was das bringt.

20uA.

von Icke ®. (49636b65)


Lesenswert?

Der Sinn des Stromsparens bei dieser Anwendung erschließt sich mir 
ohnehin nicht. Die paar mAh, die sich beim Controller einsparen lassen, 
verbraten die eingeschalteten LEDs in wenigen Minuten.

von Johannes (menschenskind)


Lesenswert?

Falk B. schrieb:
> Schon mal gut, zieht aber immer noch relativ viel. Deutlich mehr spart
> man mit Power Save mode oder gar Power Down. Man kann auch den Watchdog
> Timer zum Aufwachen nutzen.
Hm, das ist ein interessanter Hinweis. Danke! Aktuell nutze ich für die 
Leuchtroutine den Timer1 (Timer0 wird fürs Entprellen genutzt).
Diesen könnte ich dann im PRR deaktivieren, falls das genauso mit dem 
WatchdogTimer funktioniert.

Icke ®. schrieb:
> Der Sinn des Stromsparens bei dieser Anwendung erschließt sich mir
> ohnehin nicht.
Also die Platine ist so ein Wearable für Partys/Festivals und wird mit 
einer 2032 Knopfzelle betrieben. Aktuell im hellsten Modus(für dunkle 
Umgebungen sind die LEDs nur wenig ausgesteuert) hält die rund 8h, aber 
wahrscheinlich durch Qualitätsschwankungen bei den Knopfzellen haben die 
in letzter Zeit wesentlich kürzer durchgehalten.
Von daher versuche ich nun jede zusätzliche Stromsparmöglichkeit 
auszuloten. Im Durchschnitt hat meine Elektronik aktuell maximal 11mA 
Stromaufnahme.

: Bearbeitet durch User
von Gerald B. (gerald_b)


Lesenswert?

Johannes H. schrieb:
> Also die Platine ist so ein Wearable für Partys/Festivals und wird mit
> einer 2032 Knopfzelle betrieben. Aktuell im hellsten Modus(für dunkle
> Umgebungen sind die LEDs nur wenig ausgesteuert) hält die rund 8h, aber
> wahrscheinlich durch Qualitätsschwankungen bei den Knopfzellen haben die
> in letzter Zeit wesentlich kürzer durchgehalten.

Hier eine Knopfzelle verwenden zu wollen, ist in etwas so sinnvoll, wie 
per USB Kabel Starthilfe geben zu wollen.
Es gibt doch kleine, flache LiPos, wie bspw. die Clone vom Nokia bl-5c. 
Wie hast du übrigens Ub gepuffert? Ein 1000µ 6,3V Gel-Elko oder Tantal 
kann durchaus auch nochmal ne Stunde rauholen, wenn die Stromaufnahme 
sehr dynamisch ist. Die Effekte lassen sich da auch anpassen, das wenn 
die Batterie dem Ende entgegen geht, vermehrt stroboartige Effekte oder 
sowas, wie Knightriderblinken, eingesetzt wird.

von Icke ®. (49636b65)


Lesenswert?

Gerald B. schrieb:
> Hier eine Knopfzelle verwenden zu wollen, ist in etwas so sinnvoll, wie
> per USB Kabel Starthilfe geben zu wollen.
> Es gibt doch kleine, flache LiPos, wie bspw. die Clone vom Nokia bl-5c.

Die CR2032 sind nicht für so hohe Ströme ausgelegt. Ihre Kapazität von 
ca. 230mAh erreichen sie nur bei Entladung mit Strömen unter 1mA.

https://www.farnell.com/datasheets/1496885.pdf

Es gibt aber kleine LiPo-Zellen mit 300mAh, die nur unwesentlich größer 
und mit 11mA eher unterfordert sind. Die sollten einen 24h Rave 
problemlos durchhalten.

: Bearbeitet durch User
von Johannes (menschenskind)


Lesenswert?

Icke ®. schrieb:
> Es gibt aber kleine LiPo-Zellen mit 300mAh, die nur unwesentlich größer
> und mit 11mA eher unterfordert sind. Die sollten einen 24h Rave
> problemlos durchhalten.
Ja, ein Akku wäre mir auch lieber gewesen. Aber die Platine habe ich an 
viele Freunde verteilt und es musste eine Energiequelle sein, die man 
einfach austauschen kann, ohne dass extra noch ein Ladegerät nötig ist. 
Und eine USB-Buchse samt Ladeschaltung hätte die Platine auch wieder 
größer gemacht.
Und wenn man die Knopfzellen in größeren Mengen bestellt, dann kommt man 
auf nen Einzelpreis von ~30cent.

Gerald B. schrieb:
> Wie hast du übrigens Ub gepuffert? Ein 1000µ 6,3V Gel-Elko oder Tantal
> kann durchaus auch nochmal ne Stunde rauholen, wenn die Stromaufnahme
> sehr dynamisch ist.
Ich hab einen 4,7µF Keramikkondensator verwendet. Also werde ich mal 
etwas noch größeres einbauen.

: Bearbeitet durch User
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.