Skip to content
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

fix STM32 neopixel timing #1459

Merged
merged 1 commit into from Jun 13, 2018
Merged

Conversation

plisiecki
Copy link
Contributor

STM32 Neopixel timing is incorrect. The 0/1 bit values should start with a high level and end low. The current jsspiSend4bit values "1" and "3" result in the high level at the end of the period because SPI is running in MSB-first mode. Changing these values to "8" and "12" corrects this timing. I also found that I needed to flush the FIFO to ensure the output didn't get stuck high. My guess is that the cleanup code is shutting down SPI while there is still data in the FIFO. Sending an extra 32 bits of 0 bits ensures that all useful data in the 32-bit FIFO has been drained.
Prior to this fix, my Neopixel LED was randomly producing incorrect colors, and the LED was entirely black for any color consisting of just single "1" in the entire bit pattern (other than the very first bit). With this fix, I get reliable and correct colors.

@plisiecki
Copy link
Contributor Author

FWIW, my hardware is Espruino WIFI.

@gfwilliams
Copy link
Member

Hi, thanks! I'm really surprised about this as the code has been running for years on multiple different boards and it has always seemed to work fine.

What kind of neopixel lights are you using? WS2811/2/APA106/etc?

The issue you're encountering sounds exactly like you'd get with improper grounding or trying to run the neopixels off the 3.3v signal while powering them off 5v though.

@plisiecki
Copy link
Contributor Author

I am using one of Adafruit's NeoPixel Diffused 5mm Through-Hole LED which they say is either WS2812B or SK6812.

I agree this sounds exactly like a power, level, or interference issue, and I worked for several days to address those sorts of issues without significant improvement. My first circuit used TXB0104 level shifter. I noticed some overshoot on the scope, so I added tried adding 100, 235, and 470 ohm series resistors on the data line. 235 looked the cleanest. I tried twisting my ground and data lines to reduce external interference. I added the recommended 1000uF cap across the power and ground. (I have used many other types of Neopixels with many other controllers, and never had problems without the resistor and capacitor, but I know they can help, so I added them. I have always used a level shifter, though.) There were still some small extra wiggles in the transitions, so I switched to 74AHCT125. The output now looked very clean, but the problem persisted.

The test where I was setting just a single bit at a time made it clear on the oscilloscope that something was off in the timing: as the "1" moved right across the bit pattern, the pulse that got wider was getting wider on the left instead of the right. I had noticed much earlier that something was wrong with the first bit since the entire waveform shifted over when the first bit changed, but initially I guessed that was a scope triggering problem or an initialization issue with the pin. In the end, the "triggering" issue was just that the first bit was actually starting sooner/later when the bit was 1 vs. 0, so the rest of the waveform moved right/left to compensate.

Given that this code had clearly been used many times, it took a while to believe it could be a firmware bug, and besides, I didn't want it to be a firmware bug because rebuilding and flashing firmware is a huge pain. Well, it turns out that building and flashing the firmware was quite easy (thanks!!), and this change actually fixed my problem.

My first attempt just changed the 1,3 to 8,12. The output timing looked good, but the output would stick high, so it only worked if I always set the pin low right after. My guess is that the cleanup code was shutting down SPI just a tad early. Adding the extra 32 bits of 0's fixed that issue.

As for why this has never been noticed, perhaps the timing is "close enough" for the majority of pixels but this one unit just happens to operate on the fast or slow end of the tolerance such that the short low between a "0" and a "1" was not getting recognized properly. I didn't try any other pixels because I had already spent a bit of time squeezing my LED inside a button.

Here is a photo of the bad timing, with an "early" 1 bit circled in red:
img-2975

@gfwilliams
Copy link
Member

Thanks - and thanks for the detailed explanation! I'll merge it in and give it a try.

I just took a look at the nRF52 driver for neopixels and that appears to use the MSB-aligned bit patterns too, so it looks like STM32 was the odd one out.

I believe those Adafruit leds are called APA106. They light up blue when you first apply power?

It's odd because I actually have those in my kitchen - powered by an STM32F1s (the original Espruino) - some of the LED strip also comes with APA106 controllers on. Maybe something about the higher clock speed on the F411 nudged it off though.

@gfwilliams gfwilliams merged commit fcccdcc into espruino:master Jun 13, 2018
@plisiecki
Copy link
Contributor Author

They light up blue when you first apply power?

Yes, blue does seem to be their favorite power up color.

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

Successfully merging this pull request may close these issues.

None yet

2 participants