Arduino->WS2812B-> Arduino

Gast #6882560
Lesenswert?

Ich würde es wenn es unbedingt sein muss mit einem ESP und der RMT 
Perepherie probieren:

https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/rmt.html

Dann brauchst du erst nach der Idle RX Erkennung den Prozessor und hast 
Zeit den durch die Perepherie erfassten Datenstrom zu zerlegen. Die 
restliche Zeit kann er vermutlich in den Sleep.

Wobei dann die Frage ist warum du bei einem ESP nicht einfach WLAN/BT 
verwendest?
#6882595
Lesenswert?

Al. K. schrieb:
> Der Arduino soll am letzten WS2812B angeschlossen werden und
> verschiedene Schaltvorgänge realisieren.
> Im einfachsten Falle, ein Byte  zur Portausgabe.
> Keine Weiterleitung des Datenstroms.

Ist machbar, wenn gleich nicht rein per "Arduino IDE, da muss man wohl 
mit Assembler ran. GGf. mit ein wenig Hardware, welche die 
Pulsdekodierug macht, dann wird es entspannter. Mittels Monoflop die 
Pulsbreite messen und auf der fallenden Flanke abtasten bzw. speichern. 
Aber alles in allem ist das eher ein Krampf. Eine einfache 
UART-Verbindung ist 100x einfacher, selbst bei hohen Baudraten.
Gast #6882765
Lesenswert?

Markus schrieb:
> Ich könnte mir vorstellen, dass es für einen Atmega bassierten Arduino
> vom Timing her schwierig werden könnte.
> Ein ESP sollte es von der Rechenleistung und Peripherie schaffen.

Ich true das einem Atmega locker zu. Beim ESP könnte hingegen das 
Betriebssystem (die WLAN Teile) stören. Da läuft dein eigenes Programm 
nicht ruckelfrei kontinuierlich durch und Interrupt Routinen werden 
nicht immer sofort ausgeführt.
Gast #6883235
Lesenswert?

Stefan ⛄ F. schrieb:

> Ich true das einem Atmega locker zu.

Ja, das kann er (angenommener Systemtakt 16Mhz). Aber es wird eng. Wenn 
nebenbei noch was anderes interruptgesteuert laufen soll (was in der 
konkreten Anwendung, soweit beschrieben, allerdings nicht der Fall ist), 
wird es sogar sehr eng. Da muss man schon ganz ordentlich "tricksen", um 
das zuverlässig hinzubekommen.
Gast #6883452
Lesenswert?

>Ja, das kann er (angenommener Systemtakt 16Mhz).

Jetzt wo Ihr's erwähnt: Ich würde sagen, das geht auch in C mit Polling 
und direkter Pinabfrage. Die Interrupts kann man vorher mit CLI(); 
blockieren.
Der Compiler wird so gut sein und die paar Befehle optimieren.
Gast #6883486
Lesenswert?

Markus schrieb:
>> Ja, das kann er (angenommener Systemtakt 16Mhz).
>
> Jetzt wo Ihr's erwähnt: Ich würde sagen, das geht auch in C mit Polling
> und direkter Pinabfrage. Die Interrupts kann man vorher mit CLI();
> blockieren.
> Der Compiler wird so gut sein und die paar Befehle optimieren.

Denk ich auch. Ein Bit ist 1,2us lang. Man pollt z.B. immer bis zur 
fallenden Flanke, wartet dann bis zur Mitte des Bits, und wertet dann 
den Portstatus aus. Oder man benutzt ICP1. Für ganz wenige Bits könnte 
man vielleicht auch die UART missbrauchen.

LG, Sebastian
Gast #6883773
Lesenswert?

B. W. schrieb:
> Könnte man vielleicht mit einem Timer/PWM die Clock fürs SPI erzeugen?

Im Master Modus kann der ATmega328 den SPI Takt nur vom 
System-Oszillator (mit Vorteiler) ableiten. Im Slave Modus muss der Takt 
extern zugeführt werden. Diesen Eingang kann man bestimmt auch mit dem 
Ausgang eines Timers verbinden, aber wie synchronisierst du den Takt 
dann mit dem Signal?

Außerdem glaube ich, dass du immer 8 Takte brauchst, vorher gibt es für 
die Software kein Bytes zum Auslesen.
#6883807
Lesenswert?

Auf die Steigende Flanke vom WS2812 Signal ein Interrupt setzen. Im ISR 
dann einen Startwert vom Timer setzen. Mit dem Timer im PWM dann die CLK 
fürs SPI erzeugen lassen. Clear wird benutzt, damit der Timer nur einmal 
läuft.

Hmm... vielleicht übersehe ich da gerade auch etwas.

Stefan ⛄ F. schrieb:
> Außerdem glaube ich, dass du immer 8 Takte brauchst, vorher gibt es für
> die Software kein Bytes zum Auslesen.

Da das Protokoll vom WS2812 Byte-orientiert ist, seh ich da noch nicht 
mal ein Problem drin,
Angehängte Dateien:
Gast #6883816
Lesenswert?

B. W. schrieb:
> Hmm... vielleicht übersehe ich da gerade auch etwas.

Ich denke das dauert zu lange. Bedenke dass die ISR nicht immer sofort 
aufgerufen wird und einige Takte braucht, um den Stack zu beschreiben.

Wenn das die Einzige Aufgabe wäre, dann geht das vielleicht noch. Aber 
du brauchst mindestens noch eine Timeout Erkennung, sonst kommst du mit 
dem Zählen der Bits rasch durcheinander.
Gast #6884317
Lesenswert?

Stefan ⛄ F. schrieb:

> Außerdem glaube ich, dass du immer 8 Takte brauchst, vorher gibt es für
> die Software kein Bytes zum Auslesen.

Das wäre kein Problem. Das Problem ist vielmehr, dass die SPI-Einheit 
nicht gepuffert ist. Wenn überhaupt, geht's mit der UART im 
SPI-Master-Modus. Dann entfällt auch das Geraffel mit dem Timer, die 
UART versorgt sich selber mit einem Takt.

Dass der SPI-Takt dann natürlich nicht synchron mit den Daten ist, muss 
man halt dadurch ausgleichen, dass man höherer Bitrate abtastet, das 
zehrt aber natürlich einen Teil des gewonnenen Vorteils gleich wieder 
auf. Ich denke mal, man bräuchte mindestens 4x den Takt der der 
WS28xx-Datenstrippe, um das hinreichend gut abzutasten, also 3,2MHz 
SPI-Takt. Die Interrupts würden dann mit 3.2M/8=400kHz erfolgen, bei 
16MHz hätte man also bis zu 32 Nutztakte für jede ISR und durch die 
Doppel-Pufferung der UART könnte eine Latenz von bis zu ca. 5µs 
ausgeglichen werden, jedenfalls so lange sie nur verhältnismäßig selten 
auftritt.

Also in Asm auf jeden Fall machbar. Arbeitintensiv ist dabei vor allem 
der Decoder, der das asynchron gelesene Gesülze in Bits übersetzt. Das 
Ding müßte ziemlich sicher tabellenbasiert sein, sonst gibt es wohl 
keine Chance, das in unter 32 Takten abzufackeln. Zum Glück hat der 
Arduino 32k Flash, da passt einiges an Tabellen rein. Nur müssen sie 
halt erstmal "konstruiert" werden.  Al. K. traue ich das keinesfalls 
zu...
OP #6884529
Lesenswert?

Hallo,
habe natürlich alles verfolgt und es ist recht interessant.
Ich habe seit 20 Jahren ASM Programmierung aufgegeben und möchte mir das 
nicht mehr antun.
Damals war DMX für die Band aktuell.
In den 80 zigern der U880.

Habe jetzt mal auf die schnelle 8 WS2812B angesteuert.
Mit vorhandenen Lib.
Wenn ich den Daten Steuereingang Abschalte bleiben die Lichtmuster 
erhalten.
Sende ich nur für 7 LEDs , kann ich die Lichtmuster ändern ohne das die 
achte Led beeinflusst wird.

Das bedeutet, wenn ich jetzt 9 Leds definiere und anspreche, das nur 3 
Byte
aus dem letzten Led Datenausgang ausgewertet werden müssen.
Oder eben nur ein Byte um es einfacher zu machen.

Mit dem ESP32 bei abgeschalteten Wifi und Bluetooth, sollte es doch dann 
möglich sein dies auszuwerten.
,,mit der Arduino IDE.


Die Bitlänge könnte doch mit einen Monoflop selektiert werden, wie oben 
schon geschrieben.
Wenn jetzt noch ein 8Bit Schieberegister eingesetzt wird könnte es noch 
einfacher werden.
Ohne den Geraffele wäre es natürlich besser.

MfG
alterknacker
#6884588
Lesenswert?

Al. K. schrieb:
> Hat der das gleiche Protokoll

Johannes S. schrieb:
> das ist afaik der gleiche Chip wie in den LED

hey keine Fakenews!

1. WS2812B Nur Data, eine Leitung in DI und eine raus DO zu +5V und GND
2. WS2811 Din & CLKin sowie Dout & CLKout zu weiteren Chips

Wie dann die einzelne LED ist müsste aus der PWM ergründet werden.
Einziger Vorteil, es gibt ein Clk den man nutzen kann, falls das 
überhaupt ein Vorteil ist denn man muss den CLK bei der WS2812B raten 
wissen oder sonst was, die Toleranz ist riesig groß, ob in der WS2812B 
nun 800kHz eingehalten wird weiss niemand, könnte man aber nach den Bits 
ausknobeln.
#6884634
Lesenswert?

Johannes S. schrieb:
> Das einfachste wird sein das IC WS2811 zu nehmen, dann hat man 3x PWM
> pro Chip der wenige ct. kostet.

Das nützt aber nix, denn der OP will ja das 8 Bit Wort im AVR haben, umd 
damit irgendwas zu machen.

Man kann es vermutlich per ASM im AVR hinkriegen, aber das ist schon 
sportlich. Man kann es aber auch zumindest in Hardware vorverarbeiten. 
Dazu könnte ein Monoflop reichen, das die Bits dekodiert und per 
Flanke zur Verfügung stellt. Man kann das auch in einem extra AVR, z.B. 
ATtiny2313 machen, der dann die 8 Bits parallel ausgibt und per 
Handshake an den "echten" Empfänger weitergibt. So eine Art WS2812 UART. 
In einem CPLD wäre das einfach, ein paar Zähler und ne State machine. 
Aber das ist deutlich mehr Hard- und Softwareaufwand.

Wer die sportlich Herausforderung liebt, kann das machen. Wer ein 
paraktisches Problem lösen will, nimmt normales UART.
Gast #6884747
Lesenswert?

Falk B. schrieb:
> Man kann das auch in einem extra AVR, z.B.
> ATtiny2313 machen, der dann die 8 Bits parallel ausgibt und per
> Handshake an den "echten" Empfänger weitergibt.
> So eine Art WS2812 UART.

So in der Art dachte ich mir das auch. Man könnte die Daten auch seriell 
ausgeben (fire and forget), die UART/USI arbeitet ja von ganz alleine.
#6884758
Lesenswert?

B. W. schrieb:
> Hast du mal das Datenblatt dazu?

https://www.alldatasheet.com/datasheet-pdf/pdf/1132633/WORLDSEMI/WS2811.html

selber suchen wäre nett!

aber bei der Suche fiel mir auf das ich WS2811 mit WS2801 verwechselte

der WS2801 hat Data und Clock, der WS2811 nur Data, sollte also doch 
passen, nur wozu?

Wer wirklich für jede LED den Dimmstatus auswerten will muss parallel 
alle Daten aufzeichnen. Es fällt mir kein Szenario ein wozu man diesen 
Chip am Ende einer WS2812B Kette brauchen soll!
Gast #6884892
Lesenswert?

Stefan ⛄ F. schrieb:
> Wie willst du denn in den Ausgang der letzten LED etwas "rein würgen"?
> Das ist ein Ausgang, kein Eingang.

Christian M. schrieb:
> Mario M. schrieb:
>> Die WS2812 werden, nachdem sie ihre Daten empfangen haben, den Eingang
>> auf den Ausgang weiter leiten, bis 50us L-Pegel einen Reset einleiten.

So einfach geht das nicht. Die Chips leiten das Signal nicht einfach 1:1 
durch sondern dekodieren es und erzeugen es neu. Deswegen muss man sich 
da schon ans Übertragungsprotokoll halten.

Ohne diese Aufbereitung des Signal wäre es nicht möglich, unendlich 
viele dieser LEDs hintereinander zu schalten.
OP #6884931
Lesenswert?

Al. K. schrieb:
> Habe jetzt mal auf die schnelle 8 WS2812B angesteuert.
> Mit vorhandenen Lib.
> Wenn ich den Daten Steuereingang Abschalte bleiben die Lichtmuster
> erhalten.
> Sende ich nur für 7 LEDs , kann ich die Lichtmuster ändern ohne das die
> achte Led beeinflusst wird.
>
> Das bedeutet, wenn ich jetzt 9 Leds definiere und anspreche, das nur 3
> Byte
> aus dem letzten Led Datenausgang ausgewertet werden müssen.
> Oder eben nur ein Byte um es einfacher zu machen.

Ist meine Schlussfolgerung richtig?


Wenn ich also 12 LEDs definiere bei 8 LEDs extern werden 4*3 Byte aus 
dem 8 LED Ausgang geschickt?
Gast #6885382
Lesenswert?

Stefan ⛄ F. schrieb:

> So einfach geht das nicht. Die Chips leiten das Signal nicht einfach 1:1
> durch sondern dekodieren es und erzeugen es neu. Deswegen muss man sich
> da schon ans Übertragungsprotokoll halten.

Ja. Allerdings "regenerieren" die WS28xx nicht wirklich das gesamte 
Timing (dazu müssten sie die Daten buffern), sondern nur die beiden 
Zeiten T0H und T1H.

Die Zykluszeit hat hingegen weitgehend derjenigen unter Kontrolle, der 
den Kram ansteuert, so lange er nur weit genug weg bleibt von Trst.

D.h.: das Konzept von Mario M. geht grundsätzlich und ist bezüglich der 
Verringerung der Anforderungen an den Empfänger so dermaßen attraktiv, 
das es sehr wohl lohnt, weiter darüber nachzudenken.

Wenn man das Signal hardwaremäßig invertiert, bevor es RXD des 
Empfänger-Arduino erreicht, ist die Sache sogar ziemlich einfach 
umzusetzen. Voraussetzung ist halt nur, dass man auf der Arduino auf der 
Sendeseite auch für eine konstante Zykluszeit der WS28xx-Bits sorgt.

Das ist bei Timerhardware-basierten Umsetzungen des WS28xx-Protokolls 
kein Problem. Bei in C hingepfuschtem Bitbanging natürlich schon...
#6885425
Lesenswert?

c-hater schrieb:
> .h.: das Konzept von Mario M. geht grundsätzlich und ist bezüglich der
> Verringerung der Anforderungen an den Empfänger so dermaßen attraktiv,
> das es sehr wohl lohnt, weiter darüber nachzudenken.

Bei genauerer Betrachtung scheinen die Teile wirklich eine Statemachine 
mit eigenem Takt zu haben, was ein Abweichen vom vorgesehenen Protokoll 
zumindest erschwert.

https://cpldcpu.wordpress.com/2014/01/14/light_ws2812-library-v2-0-part-i-understanding-the-ws2812/
Gast #6885446
Lesenswert?

Mario M. schrieb:

> Bei genauerer Betrachtung scheinen die Teile wirklich eine Statemachine
> mit eigenem Takt zu haben, was ein Abweichen vom vorgesehenen Protokoll
> zumindest erschwert.

Haben sie. Aber effektiv tun sie halt nur eins: T0H und T1H in den Daten 
möglichst sauber separiert zu halten (also die kurzen High-Pulse, deren 
Dauer die eigentliche Information ist).

Für mehr Eingriffsmöglichkeiten fehlt der Statemachine der 
Hardware-Wumms, eben ein Buffer. Und weil das so ist, kontrolliert der 
Sender immer die Bit-Zykluszeit.

Zumindest bis zu der Grenze, die Trst setzt. Sprich: ein T0L oder T1L, 
welches Trst erreicht, mutiert zu einem tatsächlichen Reset der LED, die 
ihn erkannt hat (und aller folgenden LEDs).
OP #6885486
Lesenswert?

..zu meinen Verständnis:
wenn ich einen Sender generiere welchen nach Ausgabe eines H Pegels am 
pin
welcher zum DI der  Leds geht.
Danach Treset als Low >=50 ys ausgebe
danachfolgt 24 mal ein TOH (0,35yS) oder T1H (0,7yS) Impuls, gefolgt von 
dem
L Pegel von >2yS  50yS<  um die 3 Farbbytes R/G/B zu füllen.

Das könnte man vielleicht mit der IDE zu Fuß programmieren.
#6885612
Lesenswert?

Al. K. schrieb:
> Der Arduino soll am letzten WS2812B angeschlossen werden und
> verschiedene Schaltvorgänge realisieren.
> Im einfachsten Falle, ein Byte  zur Portausgabe.
> Keine Weiterleitung des Datenstroms.

Hier eine kleine Anregung. Ich wollte sehen, ob ich das mit einem Attiny 
hinkriege. Obwohl das ja eigentlich gar nicht funktionieren kann, weil 
das ein AVR ist und nicht in Assembler programmiert ist, bin ich mir 
immer noch sicher, daß das funktioniert hat. Ist aber schon ein paar 
Jahre her. Was nicht funktionierte, ist das Weiterleiten an einen 
nachfolgenden WS2812. Ein weiterer WS25 funktionierte allerdings. Glaube 
ich. Wie schon gesagt, ist etwas länger her. Aber dein Controller soll 
ja auch der letzte in der Reihe sein.

Die erste while-Schleife dekodiert die Daten, die zweite leitet das, was 
danach kommt, weiter. Danach werden dann die Bits sortiert und in die 
PWM-Register geschrieben. Wenn man sie stattdessen auf einen Port 
schreibt, sollte das das sein, was du machen willst.

Dass die Delay-Zeiten gar nicht so zum WS2812-Timing passen, liegt 
daran, dass die Latenzen der jeweiligen Schleifen auch ihren Anteil 
liefern.
Angehängte Dateien:
Gast #6885681
Lesenswert?

Falk B. schrieb:
> Bist du blind oder auf Entzug? Das ist taktgenau reproduzierbar!

Mal behauptet er, dass der gcc das Programm aus immer gleichen 
vorgefertigten Bausteinen zusammenfügt, an anderen Tagen behauptet er, 
dass der gcc zufälligen Code erzeugt.

Das ist halt seine Rolle, die er hier spielt: Null Ahnung vortäuschen 
und maximal lästern. Leider schnallt er nicht, dass er der einzige ist, 
der das unterhaltsam findet.
Gast #6885737
Lesenswert?

Falk B. schrieb:

> c-hater schrieb:
>> OK, man kann natürlich in jeder Sprache pfuschen. In Assembler
>> allerdings könnte man zumindest AUCH auch mit Bitbanging
>> REPRODUZIERBAR konstante Zykluszeiten umsetzen...
>
> Bist du blind oder auf Entzug? Das ist taktgenau reproduzierbar!

Naja, genau das sagte ich doch: in Asm geht das prinzipiell, in C 
prinzipiell nicht. Ich verstehe dein Problem nicht.

Ah, jetzt ja: Du hast meine Aussage auf den konkret geposteteten 
Asm-Code bezogen. Nein, war sie nicht. Den hatte ich mir nicht einmal 
angeschaut, weil für mich uninteressant.

WS28xx steuere ich seit vielen Jahren an, mit meinem eigenen Code. Der 
allerdings je nach Target und konkreten Anforderungen der Anwendung 
durchaus massiv variiert. Von Bitbanging über Timer, USART(SPI), 
USART(native) bis hin zum USI und den SPIs der 441/841 habe ich alles 
schonmal gebraucht und umgesetzt.
Gast #6885743
Lesenswert?

Stefan ⛄ F. schrieb:

> Mal behauptet er, dass der gcc das Programm aus immer gleichen
> vorgefertigten Bausteinen zusammenfügt

Das macht er definitiv. So arbeiten Compiler nunmal, der GCC ist da 
keine Ausnahme.

> an anderen Tagen behauptet er,
> dass der gcc zufälligen Code erzeugt.

Das habe ich nirgendwo behauptet. Er erzeugt nur bezüglich des 
Timingverhaltens unvorhersehbaren Code. Weil von Version, 
Optimierungseinstellungen und Kontext abhängig.

> Das ist halt seine Rolle, die er hier spielt: Null Ahnung vortäuschen
> und maximal lästern. Leider schnallt er nicht, dass er der einzige ist,
> der das unterhaltsam findet.

Labersack.
OP #6885771
Lesenswert?

Al. K. schrieb:
> ..zu meinen Verständnis:
> wenn ich einen Sender generiere welchen nach Ausgabe eines H Pegels am
> pin
> welcher zum DI der  Leds geht.
> Danach Treset als Low >=50 ys ausgebe
> danachfolgt 24 mal ein TOH (0,35yS) oder T1H (0,7yS) Impuls, gefolgt von
> dem
> L Pegel von >2yS  50yS<  um die 3 Farbbytes R/G/B zu füllen.
>
> Das könnte man vielleicht mit der IDE zu Fuß programmieren.

wenn nicht muss ich vielleicht doch noch ein bissel ASM
versuchen.
Habe noch genug Pics und AVRs rumliegen.
..aber erst mal mit der IDE!
Angehängte Dateien:
OP #6885964
Lesenswert?

@Stefan
Zitat:
Nachdem alle LEDs ihre Helligkeitswerte erhalten haben, halte die 
Daten-Leitung für mindestens
280 μs auf LOW. In diesem Moment ändert sich die Helligkeit aller LEDs 
auf den vorher
festgelegten Wert.

Du sendest sofort die Bitinformtion und danach machst du Reset/Pause
von mindestens 280 μs auf LOW.
Gast #6885978
Lesenswert?

Al. K. schrieb:
> Weil ich immer dachte das zuerst der TResetimpuls gesendet wird.

Laut Datenblatt dient der Reset dazu, die übertragenen Werte in die 
internen PWM Timer zu übertragen.

Mit einem Initialen Reset wie beim Mikrocontroller hat das nichts zu 
tun. Ich finde den Begriff "Reset" an dieser Stelle deswegen auch 
ziemlich irreführend.

Dass man nach dem Einschalten der Stromversorgung eine gewisse Zeit lang 
warten muss, sollte klar sein. Dafür sorgt ja normalerweise schon die 
interne Reset-Schaltung im steuernden Mikrocontroller.

Ist dir aufgefallen, dass ich einen "1" Impuls etwas länger als 0,7 µs 
mache? Ich habe das aus den Datenblättern vom WS2812 und WS2812B v1 bis 
v5 abgeleitet.
OP #6886565
Lesenswert?

Habe ein wenig mit dem ESP32 experimentiert, mit der Arduino IDE

digitalWrite(DatOut,HIGH);    116 ns
digitalWrite(DatOut,LOW);     116 ns

Davon habe ich alles ableiten können.

Jedenfalls kann ich die LEDs definiert ansteuern.
Bis jetzt nur Vollfarben.
Morgen vielleicht mal eine Funktion machen mit Übergabe der Led Nr. und 
der Farbwerte.

MfG
alterknacker
OP #6886781
Lesenswert?

Christian M. schrieb:
> Ja ja, Du wolltest aber:
>
> Al. K. schrieb:
>> Jetzt aber der Arduino NANO als Protokollempfänger und Auswertung

Das ist vielleicht erst möglich wenn das Sendeprotokoll vollständig
mit seinen Grenzen verständlich ist.

Es scheint so das ich das ohne Assembler Einbindung nicht hinbekomme.

Wenn ich einen WS2811 und Arduino dranhänge bekomme ich das mit der IDE 
hin, wird eben ein wenig langsamer.

MfG
Gast #6886870
Lesenswert?

Eigentlich wollte ich ja was anderes machen ... da ich aber gerade Lust 
zum Basteln habe:

Hier mal die Signale am Ende der NEOPixel-Kette.
1
/*
2
 * 
3
 * Sender for NeoPixel stripe
4
 * last LED is used as data container (24bit)
5
 * 
6
 * 21.11.2021 chris_
7
 * 
8
 */
9
#include <Adafruit_NeoPixel.h>
10
#ifdef __AVR__
11
#include <avr/power.h>
12
#endif
13

14
#define PIN            6
15

16
#define NUMPIXELS      12
17

18
// NUMPIXEL increase by 1 because last pixel is the data transmission message
19
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS + 1, PIN, NEO_GRB + NEO_KHZ800);
20

21

22
void setup()
23
{
24
  pixels.begin();
25
}
26

27

28
void loop()
29
{
30
  static uint8_t ledPos = 0;
31
  static uint32_t data = 0; // data to be tranmitted after the last pixel (only 24bits available)
32

33
  for (int n = 0; n < NUMPIXELS; n++)
34
  {
35
    if (ledPos == n)    pixels.setPixelColor(n, pixels.Color(0, 150, 0));
36
    else                pixels.setPixelColor(n, pixels.Color(0, 0, 0));
37
  }
38
  const uint8_t dataPos = NUMPIXELS;
39

40
  pixels.setPixelColor(NUMPIXELS, data);
41
  pixels.show();
42

43

44
  data++; // increase test data transmittet after last LED
45

46
  // NeoPixel Lauflicht
47
  ledPos++;
48
  if (ledPos >= NUMPIXELS)ledPos = 0;
49

50
  delay(20);
51
}
Angehängte Dateien:
Gast #6886900
Lesenswert?

chris_ schrieb:
> Eigentlich wollte ich ja was anderes machen ... da ich aber gerade Lust
> zum Basteln habe:

[...]

Der Herr bewahre mich vor Ardui...

Wenn du was dazulernen oder kompetent zum Thema dieses Threads beitragen 
willst, dann musst du dir anschauen, was pixels.show() im Detail tut. Da 
tun sich erst die Probleme auf, um die es hier geht.

Das ist garnicht so schwer: der Quelltext liegt auf deiner HD/SSD. Du 
musst ihn dir nur anschauen und verstehen, was da passiert...
Gast #6886937
Lesenswert?

Al. K. schrieb:

> Das ist vielleicht erst möglich wenn das Sendeprotokoll vollständig
> mit seinen Grenzen verständlich ist.

Wie Stefan F. korrekt angemerkt hat, gab es dazu im Laufe der Jahre 
diverse Updates der Specs.

Tatsächlich relevant sind aber nur genau zwei Sachen (eigentlich die 
Grenze, die jeweils dazwischen liegt):

T0Hmax vs. T1Hmin
TxLmax vs. Trst

die allerdings gerade nicht in den Specs stehen. Wahrscheinlich war der 
Hersteller hier der Meinung, dass dadurch sein "hochinnovatives" 
intellectual property leaken würde...

> Tatsächlich
>
> Es scheint so das ich das ohne Assembler Einbindung nicht hinbekomme.

Unter Zuhilfenahme von Peripherie ist das auch in C möglich. Senden ist 
deutlich einfacher als Empfangen (immer).

Das würde dann auch das Senden mit konstanter Bitzeit ermöglichen, was 
wiederum die Voraussetzung ist, dass dann auch für den Empfänger auch 
eine Lösung in C möglich wird. Auch hier wieder, indem die Peripherie 
benutzt wird.

Der Trick ist also im Wesentlichen immer, vorhandene Peripherie sinnvoll 
zu benutzen. Das ist allerdings gegen dieses idiotische Arduino-Konzept, 
wo jeder Pin nach Möglichkeit alles können soll...

Sprich: Mit Bitbanging hast du keine Chance, das umzusetzen, was du 
erreichen willst.
Gast #6886954
Lesenswert?

c-hater schrieb:
> Das ist allerdings gegen dieses idiotische Arduino-Konzept,
> wo jeder Pin nach Möglichkeit alles können soll...

Auch wenn du mit Sicherheit auf deinem hohen Roß begraben wirst, dein 
Bashing kannst du dir echt mal klemmen. Die Leute die Arduino Libs 
programmieren sind nicht alle Vollpfosten und viele Libs sind über die 
Zeit auch durch die Community verbessert worden. Arrogante Einzelkämpfer 
sitzen da heute auf dem absterbenden Ast.

Das einzig richtige war die Anmerkung das die Quellen der Arduino Libs 
frei verfügbar sind. Und wenn man da reinschaut, sieht man das die 
Adafruit Neopixel sehr wohl targetspezifische Implementierungen hat. 
Beim ESP32 wird das RMT verwendet, beim RP2040 die PIO.
Gast #6886957
Lesenswert?

Ich habe die Senderoutine noch ein wenig verändert, um die Daten im 
Oszilloscopebild besser separieren zu können.

Auf dem Oszilloscopebild ist der Dateneingang und der Datenausgang des 
12 NeoPixel LED Rings zu sehen.
Interessant dabei ist, dass die Neopixel scheinbar einen Buffer von 2 
Bit haben, da das Signal am Ausgang des letzten Pixels um 2 Bit 
verschoben ist.
1
/*
2
 * 
3
 * Sender for NeoPixel stripe
4
 * last LED is used as data container (24bit)
5
 * 
6
 * 21.11.2021 chris_
7
 * 
8
 */
9
#include <Adafruit_NeoPixel.h>
10
#ifdef __AVR__
11
#include <avr/power.h>
12
#endif
13

14
#define PIN            6
15

16
#define NUMPIXELS      12
17

18
// NUMPIXEL increase by 1 because last pixel is the data transmission message
19
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS + 1, PIN, NEO_GRB + NEO_KHZ800);
20

21

22
void setup()
23
{
24
  pixels.begin();
25
}
26

27

28
uint32_t TestData[]={0x000000,0x0000FF,0x00FF00,0xFF0000};
29

30
void loop()
31
{
32
  static uint8_t ledPos = 0;
33
  static uint32_t data = 0; // data to be tranmitted after the last pixel (only 24bits available)
34
  static uint8_t idx=0;
35

36
  
37
  for (int n = 0; n < NUMPIXELS; n++)
38
  {
39
    if (ledPos == n)    pixels.setPixelColor(n, pixels.Color(0, 150, 0));
40
    else                pixels.setPixelColor(n, pixels.Color(0, 0, 0));
41
  }
42
  const uint8_t dataPos = NUMPIXELS;
43

44
  data=TestData[idx];
45

46
  pixels.setPixelColor(NUMPIXELS, data);
47
  pixels.show();
48

49
  idx++;
50
  if(idx>=sizeof(TestData)/sizeof(uint32_t))idx=0;
51
  //data++; // increase test data transmittet after last LED
52

53
  // NeoPixel Lauflicht
54
  ledPos++;
55
  if (ledPos >= NUMPIXELS)ledPos = 0;
56

57
  delay(2000);
58
}
Angehängte Dateien:
Gast #6886966
Lesenswert?

Hier die Empfangsroutine.
1
/*
2
 * NeoPixel data receiver
3
 * 
4
 * connect the output of a neopixel stripe to D11 of an Arduino Nano
5
 * 
6
 * This programm will wait for a high level and than sample the input pin with maximum speed
7
 * After 256 bytes are sampled, they will printed to the serial output
8
 * 
9
 * 21.11.2021 chris_
10
 * 
11
*/
12
// compiler flags changed to O3 ( maximum speed ) line 23-28 in
13
// ~/tools/Arduino/arduino-1.8.5/hardware/arduino/avr$
14
// avr-objdump -D -S MCNET_NeoPixelReceiver.ino.elf > dump.txt
15

16

17
// PB3 is D11 on Arduino Nano
18
#define INPUTPIN (1<<PB3) //
19
#define PINVALUE (PINB&INPUTPIN)
20
#define PINLOW (PINVALUE==0)
21
#define PINHIGH (!PINLOW)
22

23
void setup()
24
{
25
  Serial.begin(115200);
26
}
27

28
#define BUFFERLENGTH 256 // must be 256
29
uint8_t Buffer[BUFFERLENGTH];
30

31
void recordSignal()
32
{
33
  uint8_t n = 0;
34
  uint8_t *pointer;
35
  pointer = Buffer;
36
  cli();
37
  while (PINLOW); // wait for the pin
38
  do {
39
    *pointer = PINB;
40
    pointer++;
41
    n++;
42
  } while (n != 0);
43
  sei();
44
}
45

46
void loop()
47
{
48
  uint8_t n = 0;
49

50
  recordSignal();
51
  do {
52
    uint8_t bitData = Buffer[n] & (1 << PB3);
53
    Serial.println(bitData);
54
    delay(1);        // delay in between reads for stability
55
    n++;
56
  } while (n != 0);
57

58
  delay(1000);
59
}

Ich habe den Optimierungslevel in der "platform.txt" auf O3 umgestellt, 
in der Annahme, dass das den schnellsten Code ergibt ( .. stimmt das? ).

Der Objdump ergibt folgendes:
1
void recordSignal()
2
{
3
  uint8_t n = 0;
4
  uint8_t *pointer;
5
  pointer = Buffer;
6
  cli();
7
 692:  f8 94         cli
8
  while (PINLOW); // wait for the pin
9
 694:  1b 9b         sbis  0x03, 3  ; 3
10
 696:  fe cf         rjmp  .-4        ; 0x694 <main+0x11e>
11
 698:  ef e1         ldi  r30, 0x1F  ; 31
12
 69a:  f1 e0         ldi  r31, 0x01  ; 1
13
  do {
14
    *pointer = PINB;
15
 69c:  83 b1         in  r24, 0x03  ; 3
16
 69e:  81 93         st  Z+, r24
17
  uint8_t n = 0;
18
  uint8_t *pointer;
19
  pointer = Buffer;
20
  cli();
21
  while (PINLOW); // wait for the pin
22
  do {
23
 6a0:  92 e0         ldi  r25, 0x02  ; 2
24
 6a2:  ef 31         cpi  r30, 0x1F  ; 31
25
 6a4:  f9 07         cpc  r31, r25
26
 6a6:  d1 f7         brne  .-12       ; 0x69c <main+0x126>
27
    *pointer = PINB;
28
    pointer++;
29
    n++;
30
  } while (n != 0);
31
  sei();
 6a8:  78 94         sei
}
Gast #6886969
Lesenswert?

Johannes S. schrieb:

> Das einzig richtige war die Anmerkung das die Quellen der Arduino Libs
> frei verfügbar sind. Und wenn man da reinschaut, sieht man das die
> Adafruit Neopixel sehr wohl targetspezifische Implementierungen hat.
> Beim ESP32 wird das RMT verwendet, beim RP2040 die PIO.

Es geht aber nunmal in diesem Thread um einen Arduino NANO, sprich: 
AVR8, siehe OT!

Dein dümmliches tendenzielles Geschwalle geht also vollkommen am Problem 
vorbei!
Gast #6887187
Lesenswert?

Hier das erste funktionierende Beispiel mit zwei Arduino-Nano.

Es ist zwar ein etwas unaufgeräumter Quick-Hack und ziemlich langsam, 
aber zumindest zeigt es, dass es mit zwei Arduino-Nanos geht.

Die Datenübertragung geht über 12 NeoPixel-LEDs und der Ausgang der 
letzten LED ist an D11 des Empfänger-Arduinos angeschlossen. Die Ausgabe 
erfolgt über den seriellen Port des Arduinos. Das Ergebnis ist im 
Screenshot zu sehen.
Gast #6887797
Lesenswert?

>Empfänger funktioniert!

Super :-)

>Jetzt muss ich mit meinen Sender ein Byte als Überlauf senden welches
>als Datenbyte ausgewertet wird.
>..denke ich

Schau mal in der Senderoutine (Zeile 81):
1
sendByte(Message[counter++]);

Dort kannst Du auch
1
sendByte(88);
2
sendByte(123);

oder
1
sendByte(counter++); // jetzt wird nicht die Nachricht, sondern der Zähler gesendet

oder ähnliches schreiben.

Im Empfänger solltest Du dann aber die Zeile 161 auskommentieren und 
statt dessen die Zeile 160 verwenden, damit die Zahlen und nicht die 
Ascci-Zeichen sichtbar werden:

Zeile 160
1
Serial.print("==>");Serial.write(ReceivedByte);Serial.print(" - ");Serial.println(ReceivedByte);
OP #6887943
Lesenswert?

Das habe ich soweit schon verstanden.

Es wäre natürlich besser wenn ein "Normaler Sender genutzt werden kann.

Definiere  z.B.13 Leds, habe aber extern nur 12, damit sollen die
3 Farbbyte der Dateninhalt sein.

Mal sehen ob ich meinen ESP32 Testsenden auf dein Protokoll um setzen 
kann.
Setze  im Sender keine Lib ein, alles zu Fuß.

Aufbauend auf den Befehl
digitalWrite(DatOut,HIGH);    116 ns
digitalWrite(DatOut,LOW);     116 ns
Damit kann ich das normale Sendeprotokoll zusammenbasteln


Gibt es noch schnellere reproduzierbare Befehle?

MfG
#6888271
Lesenswert?

Al. K. schrieb:
> Welche Zeit brauch z.B delay(0)

schau auf einen Oszi oder LA, 2 Ports nehmen high low schalten 
nacheinander und dazwischen mit / ohne delay(0);
wobei delay(0) sinnlos ist und eigentlich auch wegoptimiert werden 
könnte.
Was weiss ich was der Compiler daraus macht.

Ich war  ja fast bereit den ESP32 anzuwerfen samt Arduino IDE.
Manches solltest du aber selber schaffen so weit wie du schon gekommen 
bist.
Gast #6888335
Lesenswert?

Al. K. schrieb:
> Setze  im Sender keine Lib ein, alles zu Fuß.
>
> Aufbauend auf den Befehl
> digitalWrite(DatOut,HIGH);    116 ns

kann man so machen, dann ist es halt Sch*ße. Wurde doch schon 
geschrieben das Bitganging viel schlechter ist als vorhandene hardware 
devices zu nutzen. Und das machen die ESP Libs, auch wenn es hier von 
verschiedenen immer wieder schlechtgeredet wird.

Al. K. schrieb:
> Gibt es noch schnellere reproduzierbare Befehle?

das sind keine Befehle, sondern Funktionen die aufgerufen werden. 
'Arduino Befehle' gibt es sowieso nicht.

Al. K. schrieb:
> Welche Zeit brauch z.B delay(0)

Muss man nicht messen, die Arbeit kann man sich sparen weil diese 
Funktion denkbar ungeeignet ist. Das delay(n) ruft vTaskDelay auf und 
wartet n ms. Da die ESP Arduino Implementierung das FreeRTOS als Basis 
nutzt hat man da also den Overhead des RTOS am Hals. delay(0) ist dazu 
noch ein Sonderfall der den Scheduler aufruft und dann in einem 
taskYield() endet, das macht man also nur um Rechenzeit an andere 
wartende Task gleicher Priorität abzugeben.

Das die WS Lib mit Hardwarhilfe arbeitet hat noch einen Grund: das Wifi 
im ESP verlangt strenges Timing und hat eine höhere Prio als deine 
Applikation. Also kann es dein Bitbanging beliebig durcheinanderhauen. 
Und wenn man kein Wifi benötigt ist der ESP einfach mit Kanonen auf 
Spatzen.

Selbst ein delayMicroseconds() hat nur Mikrosekunden Auflösung und 
eignet sich also nicht für 0,1 µs genaues Timing.

Ergo: völlig falscher Ansatz, gehe zurück auf Los.
OP #6888337
Lesenswert?

Joachim B. schrieb:
> schau auf einen Oszi oder LA, 2 Ports nehmen high low schalten
> nacheinander und dazwischen mit / ohne delay(0);
> wobei delay(0) sinnlos ist und eigentlich auch wegoptimiert werden

Laufzeiten von Befehlen zu ermitteln ist mir bekannt.

Es geht nur um den Aufwand.
Vor30/40 Jahren war dies zwingend zu wissen,zu messen oder zu erlesen.

Jetzt Frage ich einfach, da bestimmt auch Andere Leser die hier 
diskutierten Probleme interessieren.
Wer die Lösung parat hat, kann sie nennen. Keiner muss danach suchen.

OsZi habe ich nicht mehr, auch kein Imp,Freque,Perioden Messgerät.

Könnte mir ein Messgerät Programmieren.

Was ist ein LA?

P.S.
Das wenigste was ich teste,suche und bastle ist für mich.



MfG
alterknacker
OP #6888344
Lesenswert?

Johannes S. schrieb:
> Das die WS Lib mit Hardwarhilfe arbeitet hat noch einen Grund: das Wifi
> im ESP verlangt strenges Timing und hat eine höhere Prio als deine
> Applikation. Also kann es dein Bitbanging beliebig durcheinanderhauen.
> Und wenn man kein Wifi benötigt ist der ESP einfach mit Kanonen auf
> Spatzen.

Das ist bekannt und wurde schon mehrfach geschrieben.

Das Delay(0) war ein ersichtliches Beispiel.

Für mich war es ein Versuch zu Fuß mit dem ESP32 die WS anzusteuern.
Ist aber nicht Lebenswichtig.

Ich wollte auch nur erfragen ob es ein Befehl mit Kleinerer Laufzeit wie
0,116 yS  gibt.. wenn ja, kann man genauere Protokolle basteln.

altekinacker
Gast #6888359
Lesenswert?

Es gibt nur Maschinenbefehle in Assembler.
Als Dummy nimmt man da NOP, das ist hier per #define verfügbar und kann 
mit NOP() im Code verwendet werden.
Mit den immer noch bestehenden Nachteilen das es kein sicheres Timing 
auf einem Multicore mit RTOS ermöglicht.
Und das Bitbanging per Code ist abhängig vom CPU Takt und wenn es im 
Flash ausgeführt wird, dann noch von der Flash Latency. Also alles 
maximal ungünstig.
#6888423
Lesenswert?

Al. K. schrieb:
> ..und selbst basteln ist wegen der begrenzten Lebenszeit nicht mehr
> drin.

aber auf Antwort im Forum warten?
In der Zeit hättest du längst messen können!
Sogar ich hatte mir dies Jahr noch ein Rigol 5104 zugelegt, ich glaube 
zwar nicht das ich es noch viel nutze, aber man weiss ja nie.

Al. K. schrieb:
> Wer die Lösung parat hat, kann sie nennen.

und nun wie lange in µs dauert denn nun

Al. K. schrieb:
> Welche Zeit brauch z.B delay(0)

wo ist die Antwort?
Gast #6888501
Lesenswert?

Al. K. schrieb:
> Werde mir mal so was zulegen, leider bei dem benannten Teil keine
> richtige Beschreibung.

Die erkennt man am Bild, werden unter gefühlt 100 Namen verkauft. Da ist 
immer das gleiche drin. Im Grunde nur ein Mikrocontroller, ein 
Bustreiber 74LVC245 oder 74HC245, und eine primitive Schutzschaltung für 
die 8 Eingänge. Ich benutze dazu das Programm PulseView.

Weiss jemand wozu der Bustreiber gut ist? Warum hängen die Eingänge 
nicht direkt am Mikrocontroller?
Angehängte Dateien:

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren