Skip to content

APA102 LED "n+1" is lighted on write() #3037

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
darkmattercoder opened this issue Apr 23, 2017 · 10 comments
Closed

APA102 LED "n+1" is lighted on write() #3037

darkmattercoder opened this issue Apr 23, 2017 · 10 comments

Comments

@darkmattercoder
Copy link

I just installed micropython:
MicroPython v1.8.7-7-gb5a1a20a3 on 2017-01-09; ESP module with ESP8266
onto my NodeMCU.

I tried the example code for APA102 driver at: https://docs.micropython.org/en/latest/esp8266/esp8266/quickref.html#apa102-driver

whenever I call the write()-method, the LED that comes after the nth led configured with
apa = APA102(clock, data, n) will light up white.

for example:

apa = APA102(clock, data, 2)
apa[0] = (255, 0, 0, 31)
apa.write()

will result in a red first LED and a white third LED. The second LED stays off.

Any Ideas what could happen here?

Thanks in advance

@dpgeorge
Copy link
Member

Does anyone have an APA102 that they can test this with?

@mcauser
Copy link
Contributor

mcauser commented Jul 20, 2017

I do. I have one of these: https://www.adafruit.com/product/2240
I'll see if I can replicate the issue on my ESP8266.

@mcauser
Copy link
Contributor

mcauser commented Jul 20, 2017

I can reproduce this bug on my Wemos D1 Mini v2.1.0 ESP8266.
MicroPython v1.9-1-ge5e49be-dirty on 2017-06-09; ESP module with ESP8266

Wemos D1 mini -- 1m APA102 strip with 60x LEDs
D1 GPIO5 ------- CI
D2 GPIO4 ------- DI
GND ------------ GND
5V ------------- VCC
>>> from machine import Pin
>>> from apa102 import APA102
>>> clock = Pin(5, Pin.OUT)
>>> data = Pin(4, Pin.OUT)

Test 1 👎

>>> apa = APA102(clock, data, 2)
>>> apa[0] = (255, 0, 0, 31)
>>> apa.write()
strip[0] red
strip[2] white (bug)
strip[12] cyan (bug)

Test 2 👎

>>> apa[0] = (255, 0, 0, 10)
>>> apa.write()
strip[0] light red
strip[2] white (bug)
strip[12] cyan (bug)

Test 3 👎

>>> apa = APA102(clock, data, 4)
>>> apa[0] = (255, 0, 0, 31)
>>> apa[1] = (0, 255, 0, 31)
>>> apa[2] = (0, 0, 255, 31)
>>> apa.write()
strip[0] red
strip[1] blue
strip[2] green
strip[4] white (bug)
strip[12] cyan (bug)

Test 4 👎

>>> apa = APA102(clock, data, 2)
>>> apa[0] = (255, 0, 0, 31)
>>> apa.write()
strip[0] red
strip[2] white (bug)
strip[4] white (bug)
strip[12] cyan (bug)

(disconnect and reconnect led strip)

Test 5 👎

>>> apa = APA102(clock, data, 4)
>>> apa[0] = (255, 0, 0, 31)
>>> apa[1] = (0, 255, 0, 31)
>>> apa[2] = (0, 0, 255, 31)
>>> apa.write()
strip[0] red
strip[1] blue
strip[2] green
strip[4] white (bug)
strip[6] light white (bug)
strip[16] light blue (bug)

Test 6 👎

>>> apa = APA102(clock, data, 7)
>>> apa[0] = (255, 0, 0, 31)
>>> apa[2] = (0, 255, 0, 31)
>>> apa[4] = (0, 0, 255, 31)
>>> apa.write()
strip[0] red
strip[2] blue
strip[4] green
strip[7] white (bug)

(disconnect and reconnect led strip)

Test 7 👎

>>> apa = APA102(clock, data, 1)
>>> apa[0] = (255, 0, 0, 31)
>>> apa.write()
strip[0] red
strip[1] white (bug)
strip[13] blue (bug)
strip[27] light green (bug)

(disconnect and reconnect led strip)

Test 8 👎

>>> apa = APA102(clock, data, 3)
>>> apa[0] = (0, 255, 0, 31)
>>> apa[1] = (0, 0, 255, 31)
>>> apa[2] = (255, 0, 0, 31)
>>> apa.write()
strip[0] blue
strip[1] green
strip[2] red
strip[3] white (bug)

(disconnect and reconnect led strip)

Test 9 👎

>>> apa = APA102(clock, data, 9)
>>> apa[0] = (255, 0, 0, 31)
>>> apa[1] = (0, 255, 0, 31)
>>> apa[2] = (0, 0, 255, 31)
>>> apa[3] = (255, 0, 0, 31)
>>> apa[4] = (0, 255, 0, 31)
>>> apa[5] = (0, 0, 255, 31)
>>> apa[6] = (255, 0, 0, 31)
>>> apa[7] = (0, 255, 0, 31)
>>> apa[8] = (0, 0, 255, 31)
>>> apa.write()
strip[0] red
strip[1] blue
strip[2] green
strip[3] red
strip[4] blue
strip[5] green
strip[6] red
strip[7] blue
strip[8] green
strip[9] white (bug)

(disconnect and reconnect led strip)

Test 10 - Works! 👍

>>> apa = APA102(clock, data, 60)
>>> apa[0] = (255, 0, 0, 1)
>>> apa[1] = (0, 255, 0, 1)
>>> apa[2] = (0, 0, 255, 1)
>>> apa.write()
strip[0] red
strip[1] blue
strip[2] green

Test 11 👎

>>> apa = APA102(clock, data, 59)
>>> apa[0] = (255, 0, 0, 1)
>>> apa[1] = (0, 255, 0, 1)
>>> apa[2] = (0, 0, 255, 1)
>>> apa.write()
strip[0] red
strip[1] blue
strip[2] green
strip[59] white (bug)

@mcauser
Copy link
Contributor

mcauser commented Jul 20, 2017

It appears my strip is one of the newer strips with APA102C's with a different colour order, RBG.

@mcauser
Copy link
Contributor

mcauser commented Jul 20, 2017

Recorded the first 3 tests using a logic analyser: apa102-tests-saleae-logic.zip
I couldn't find a protocol analyser for the APA102 / Dotstar strips.

There is one for Neopixel strips.
https://github.com/Marcus10110/neopixel-saleae
I might try writing one for the APA102

@mcauser
Copy link
Contributor

mcauser commented Jul 20, 2017

Oh, it's just SPI!

Test 1:

[
  0,0,0,0, (start frame)
  255,0,0,255, (red)
  224,0,0,0, (off)
  255,255,255,255 (white)
]

Test 2:

[
  0,0,0,0, (start frame)
  234,0,0,255, (light red)
  224,0,0,0, (off)
  255,255,255,255 (white)
]

Test 3:

[
  0,0,0,0, (start frame)
  255,0,0,255, (red)
  255,0,255,0, (blue)
  255,255,0,0, (green)
  224,0,0,0, (off)
  255,255,255,255 (white)
]

http://hackaday.com/2014/12/09/digging-into-the-apa102-serial-led-protocol/
Is the last 255,255,255,255 the end frame?

https://cpldcpu.com/2014/11/30/understanding-the-apa102-superled/

In summary, each update of an APA102 based LED string should consist of the following:
A start frame of 32 zero bits (<0x00> <0x00> <0x00> <0x00>)
A 32 bit LED frame for each LED in the string (<0xE0+brightness> )
An end frame consisting of at least (n/2) bits of 1, where n is the number of LEDs in the string.

Perhaps sending 1,1,1,1 as the end frame would fix it.

@mcauser
Copy link
Contributor

mcauser commented Jul 20, 2017

Sending the 32-bit end frame as 0x01,0x01,0x01,0x01 or 0x00,0x00,0x00,0x00 fixed it.
There is no longer a trailing white pixel.

/esp8266/espapa102.c:94
a) _esp_apa102_send_byte(clockPinMask, dataPinMask, 0x01);
b) _esp_apa102_send_byte(clockPinMask, dataPinMask, 0x00);

Reading more about it and it seems the datasheet may be wrong. You don't actually need to send the end frame, as long as you are sending the additional padding bits, which we are in the _esp_apa102_append_additionial_cycles call above.

I tried commenting out _esp_apa102_end_frame(clockPinMask, dataPinMask); inside void esp_apa102_write and it still worked, and without the trailing white pixel.

Init strip of 6 pixels, set to R,G,B,R,G,B - no extra white pixel
Init strip of 3 pixels, set to G,B,off - 4th+ pixels remain in previous state

Send 0s or 1s as the end frame, or omit the end frame?!

¯\_(ツ)_/¯

There's also typo in the _esp_apa102_append_additionial_cycles method.
additionial -> additional

@mcauser
Copy link
Contributor

mcauser commented Jul 20, 2017

Actually no. Omitting the end frame causes the next apa.write() on the 3 pixel strip to overwrite the 4th pixel. Needs more testing...

@mattytrentini
Copy link
Contributor

It's interesting that FastLED's APA102 implementation appears to send 0xFF000000 for every 32 LED's in the strip as the end frame.

This seems to make some sense as this will 'turn off' any LED's in the event that the number of LED's don't fall on a neat boundary - or if sync is somehow lost? (Guessing here!) It also ensures that the clock is toggled sufficiently in the way that Tim identified in his "Understanding the APA102 Superled" blog post that you referred to.

@dpgeorge
Copy link
Member

Closing due to inactivity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants