Liebes Forum,
ich krieg das einfach nich gebacken. Hab einen ESP8266 (WROOM-02 und
AIThinker ESP-12e), der mit Arduino (1.6.7) in "Native-C" Arduino SDK
Version 2.0.0 einen WS2812-Streifen (60 LEDs) füttern soll.
Dazu hab ich ein popeliges Programm geschustert, das einfach seriell 180
Bytes entgegennimmt und diese mit der folgenden Routine auf den GPIO
schreibt:
1 | static inline uint32_t _getCycleCount(void) {
|
2 | uint32_t cycles;
|
3 | __asm__ __volatile__("rsr %0,ccount":"=a" (cycles));
|
4 | return cycles;
|
5 | }
|
6 | static void ICACHE_RAM_ATTR ws2812_write(uint8_t *pixels, uint32_t len) {
|
7 | uint8_t *p, *end, pixel, mask;
|
8 | uint32_t t, t0h, t1h, ttot, c, start_time, pin_mask;
|
9 | pin_mask = 1 << LEDOUT_PIN;
|
10 | p = pixels;
|
11 | end = p + len;
|
12 | pixel = *p++;
|
13 | mask = 0x80;
|
14 | start_time = 0;
|
15 | t0h = (1000 * system_get_cpu_freq()) / 3022; // 0.35us (spec=0.35 +- 0.15)
|
16 | t1h = (1000 * system_get_cpu_freq()) / 1477; // 0.70us (spec=0.70 +- 0.15)
|
17 | ttot = (1000 * system_get_cpu_freq()) / 800; // 1.25us (MUST be >= 1.25)
|
18 | while (true) {
|
19 | if (pixel & mask) {
|
20 | t = t1h;
|
21 | } else {
|
22 | t = t0h;
|
23 | }
|
24 | while (((c = _getCycleCount()) - start_time) < ttot); // Wait for the previous bit to finish
|
25 | GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pin_mask); // Set pin high
|
26 | start_time = c; // Save the start time
|
27 | while (((c = _getCycleCount()) - start_time) < t); // Wait for high time to finish
|
28 | GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pin_mask); // Set pin low
|
29 | if (!(mask >>= 1)) { // Next bit/byte
|
30 | if (p >= end) {
|
31 | break;
|
32 | }
|
33 | pixel= *p++;
|
34 | mask = 0x80;
|
35 | }
|
36 | }
|
37 | }
|
Die Funktion rufe ich wie folgt auf:
1 | uint8_t ledBuf[180];
|
2 | //...
|
3 | noInterrupts();
|
4 | ws2812_write( ledBuf, sizeof(ledBuf) );
|
5 | interrupts();
|
Das funktioniert meistens. Leider kommen treten sporadisch LED-Glitches
auf, bei denen Farbwerte teilweise in die Farbe der nächsten LED
rutschen (also blau 1->grün2 usw.), insbesondere (aber nicht nur) bei
den mittleren bis hinteren LEDs. Und gefühlt tritt es beim schnellen
Senden häufiger auf.
Es liegt wohl nicht an Fehlern an der seriellen (PC->ESP) Übertragung,
das ganze passiert auch, wenn ich einfach einen statischen Buffer mit
100Hz sende, Hardcore-Test mit:
1 | memset(ledBuf, 0xAA, sizeof(ledBuf));
|
2 | noInterrupts(); ws2812_write( ledBuf, sizeof(ledBuf) ); interrupts();
|
3 | memset(ledBuf, 0x55, sizeof(ledBuf));
|
4 | noInterrupts(); ws2812_write( ledBuf, sizeof(ledBuf) ); interrupts();
|
Ich kann das mangels Logic-Analyser nicht elektrisch in ganzer Länge
debuggen. Am Oszi schaut das Timing mit 330ns kurz, 680ns lang und
insgesamt 1,2µs gut (siehe 1.jpg) aus, ich habe aber viel Ringing (siehe
2.jpg).
Mit 50 Ohm in Reihe ist das Ringing weg, das Signal schaut "perfekt"
aus, nur der Streifen tut nichts mehr.
Deswegen die Frage: Hat schon mal jemand diese Kombination erfolgreich
und "langzeitstabil" am Laufen und könnte sagen, wie das elektrisch und
wie in Software gelöst ist?
Danke, Christoph