Controlling WS2812 device (RGB LED strip)
Theodore Borromeo last edited by
@Pavils-Jurjans Did you see the post on hackaday, where some guy figured out a way to send precisely timed VGA signals to the led strip? It was pretty dope, and, if there is a way to send analog frequencies in the same manner over any combo of pins, it'd be interesting to simplify what you are doing to get it under the time constraints needed.
Alternatively: precise digital timing could work.
I found this driver just now, in a second round of googling the topic in the evening - as my hardware is in the office, I could not try it yet.
But before, I already spent the afternoon experimenting with bitbanging the WS2812 timing on the Onion and measuring the results on a scope.
With interrupts disabled, the timing (350nS pulse for a 0 bit, 700nS for a 1 bit) can be met quite easily, especially when you know that the specified pause time between bit pulses (600/800nS) is a minimum, not an exact requirement, contrary to what the worldsemi datasheet says. The pause length must only be kept well below the reset time of 50µS.
However, I found keeping the pauses reliably below 50µS is not possible without blocking the interrupts during the entire WS2812 chain update, which amounts to multiple milliseconds for an average 200 LED chain. Doing so will certainly ruin the accuracy of hrtimers etc. But apparently, one can usually get away with that - the ws2812_draiveris driver from github implements it that way.
I'll try that driver tomorrow, however I'm a bit reluctant to actually using it, because I have other drivers relying on hrtimer accuracy in the 500µS range. Keeping IRQs blocked for so long is certainly not good kernel programming practice.
On the other hand, are there any better options? To meet the timing without blocking IRQs, we'd need a DMA based solution. Maybe i2s or SLIC can be misused to produce the WS2812 timing somehow?
Update: In the meantime, I tried the ws2812-draiveris driver from github and it works fine on the Omega!
For those who want to try - you can download a installable driver package from my server and install it via console on your omega (--force-depends may be needed -> experimental!):
cd /tmp wget http://plan44.ch/downloads/experimental/kmod-ws2812-draiveris_3.18.29%2B0.1-9_ar71xx.ipk opkg install /tmp/kmod-ws2812-draiveris_3.18.29+0.1-9_ar71xx.ipk --force-depends
To activate the device for 256 LEDs with data pin connected to GPIO7:
insmod /lib/modules/3.18.29/ws2812-draiveris.ko gpios=7 leds_per_gpio=256
If you had two separate chains of 120 LEDs each connected to GPIO7 and 8, it would be:
insmod /lib/modules/3.18.29/ws2812-draiveris.ko gpios=7,8 leds_per_gpio=128
Now there's a new device /dev/ws2812 available. To set the colors of the connected LEDs, just write a string with 3 bytes (R,G,B) for each LED to /dev/ws2812. Within the limits of ASCII-Values (32..126 = space..}) this can be tested with echo. The following sets the first three leds to slightly pale red, green and blue:
echo "}!!!}!!!}" > /dev/ws2812
To test the driver with more load, I ported (q&d) my messagetorch project, originally written for the spark core, to the Omega.
This is a fire-like animation, intended to be shown on a WS2812 chain of ~200 LEDs, wound onto a tube:
cd /tmp wget http://plan44.ch/downloads/experimental/messagetorch_0.1-1_ar71xx.ipk opkg install /tmp/messagetorch_0.1-1_ar71xx.ipk
Assuming a "torch" with 18 windings of 13 LEDs each, start the torch with
messagetorch -W 13 -H 18 "Hello Omega"
See the github project for more information. In particular, you can post messages by sending UDP packets.
messagetorch updates all LEDs approx every 25mS, and the driver locks IRQs for about 6mS for every update. Although blocking IRQs for so long is certainly bad, it does not seem to affect working with the Omega noticeably.
Happy experimenting with WS2812 LEDs
@administrators : Is the solution proposed by @Lukas-Zeller the one to follow to work with WS2812 and the first Omega, or have you been able to finish your neopixel library ?
@Lukas-Zeller : There is a dependency error now, when we try to install the opkg.
It gives this :
root@Omega-XXXX:/tmp# opkg install /tmp/kmod-ws2812-draiveris_3.18.29+0.1-9_ar71 xx.ipk Installing kmod-ws2812-draiveris (3.18.29+0.1-9) to root... Collected errors: * satisfy_dependencies_for: Cannot satisfy the following dependencies for kmod-ws2812-draiveris: * kernel (= 3.18.29-1-ec3c73d5690ecfdba6d7368603798b4e) * * opkg_install_cmd: Cannot install package kmod-ws2812-draiveris.
There probably has been some updates to the linux kernel since you posted, but I don't know how to lake it work.
@Brice-Parent This is an issue that has been around for quite some time. Generally it means that the kernel version the package was compiled for does not match the kernel version on the Omega.
This issue occurs for some other packages as well and has been drawn to the attention of the Omega guys though a resolution is still awaited.
It may be worth trying the command
opkg --force-depends install <package>to do the install ignoring dependency issues.
This may work OK so long as the kernel differences are not significant for the package.
AFAIK there's no way yet (due to a few missing files) to setup an OpenWrt build environment that exactly matches the official builds, so that's a problem we have to live with for now.
The WS2812 driver is very simple regarding kernel infrastructure it uses, so the kernel version mismatch is not a problem here.
The real problem one should be aware of when using this driver is that it blocks interrupts for several milliseconds when updating the LED chain (see my post above). This might break timing in other parts of the system - probably streaming audio would not work in parallel, and maybe it will also affect network performance.
In my experiments with an Omega not doing much except nice LED animations, I didn't notice any side effects, though
Hi...as per my knowledge the Omega has General Purpose and Watchdog timers that you should be able to use to get the timing down.However, an easier option might be to use the Arduino Dock since the ATmega can very precisely control its output timing with probably less hassle than the above. Then you can use the Omega to send the Arduino chip instructions on what colors to set and the Arduino chip will do all of the low-level stuff.
youlian troyanov last edited by
awesome work @Lukas-Zeller. should start saving for a big roll of ws2812 asap
[Updated because of confusion between WS2813 and APA102]
@youlian-troyanov Before investing into WS2812 LEDs, you might want to check out
Only very recently a colleague told me about the
WS2813APA102, I wasn't aware of these before.
The big advantage of the
WS2813APA102 is that it uses standard SPI protocol, which almost any SOC can generate without dirty tricks, including Omega1 and 2. In addition, the WS2813APA102 seem to have a much higher PWM rate, which means that they are now suitable for POV (persistence of vision, fast moving LEDs e.g. mounted along fan blades creating the illusion of an image).
That's what I've read and have been told so far - I just ordered a WS2813 based LED strip to try it out, hopefully it will arrive soon
[Update: I meant to get the APA102, but I ordered WS2813 and so I got exactly these. Only then I found out about the confusion with the APA102, aka DotStar. The WS2813 also has two data lines, but the second is a backup line that keeps a chain working even when some LEDs fail. Otherwise, WS2813 uses the same data format as WS2812, with a few improvements: 2kHz PWM rate vs 400Hz, longer reset time of 250µS vs 50µS.]
@Ira-Burns yes, the AR9331 in the Omega1 has some timers, but unfortunately (being designed for WLAN routers, not IoT) it does not have PWM outputs that can be controlled by these timers.
Using the timers for generating interrupts does not work either because that's way too slow to meet the tight WS2812 timing. So for the Onion1, the only way to do it is blocking interrupts and then bit-banging output lines as the ws2812-draiveris driver does, or using the Arduino dock as you suggested.
But I don't like spending room and power for operating a second, much inferior CPU, just to move the ugly stuff (block IRQs, bitbang data, there's no other way to do it on the Arduino either) outside.
The Omega2's MT7688 chip however was designed for IoT and does have PWM outputs - I guess it will be possible to create a WS2812 driver using timers, PWM and DMA that works without blocking interrupts. We'll see when the Omega2 arrives…
For the Omega1, using
WS2813APA102 instead might be a elegant solution.
youlian troyanov last edited by
thank you @Lukas-Zeller. excellent advice, especially about pov, that's something i wanted to experiment with, you just read my mind
Eric last edited by Eric
@Lukas-Zeller Great, looking forward to hear from your test. I'm planning to install lots of LED STRIP (Addressable) in my house but didn't find a low cost controller expendable to connect all my sensors until I saw Omega1. Now with Omega2 power and even cheaper with Led Strip WS2813 sound like a perfect match for my project. Did you also look at the SK6812 who support RGBW (True white not RGB composite which take way less power)?
@Eric I recently bought a SK6812 based strip but haven't found the time yet to try it out. Having RGBW should make these much more suitable for actual lighting, not only decoration. I will post a followup here once I have tried these, probably I'll do it along with the WS2813 tests.
@luz : I'm really interested about your feedback about those WS2813 and the ability to use them directly from our Omegas. I've just order a few of them, but they'll be sent from China to Europe and won't arrive until a few weeks, so in the meantime, if you can make it work, I'd be glad to know how you did.
And if not, or if you needed extra components, I'm all hears too!
@Brice-Parent I just tested my SK6812 strip and it works fine!
As each LED now needs 4 bytes of data (instead of 3 with WS2812), I had to modify the ws2812-draiveris kernel driver to add an option for RGBW LEDs.
insmod /lib/modules/4.1.23/ws2812-draiveris.ko gpios=7 leds_per_gpio=20 rgbw=1
Please note that I falsely thougth the WS2813 LEDs were the new SPI interfaced ones - they are not, just improved WS2812 using same data format with an additional wire (keeps chains working when one chip fails). The new SPI ones are called APA102 (of which I now also ordered some samples, but will take another few weeks to arrive). I edited my earlier posts above accordingly.
So the status is:
- WS2812 (RGB, 3 wires) : works with original ws2812-draiveris
- WS2813 (RGB, 4 wires) : also works with original ws2812-draiveris
- SK6812 (RGBW, 3 wires) : work with my modified ws2812-draiveris with extra "rgbw" module parameter
- APA102 or "DotStar" (RGB, 4 wires, SPI) : should work with standard SPI, but can't test until I get samples in a few weeks.
@luz Too late for me, I've ordered the WS2813 (but I won't get them until some weeks).
So, it means that I need an interface between my Omega and the led strips, like an Arduino for example? Or is it still possible to drive the strips directly from the Omega, even with some other running service which could make a synchronised communication hard?
I tried your cool way to control leds.
Driver is working correct, and I can echo some colors to the leds.
But sadly messagetorch is not working for me.
Installation was ok, but start fails with "-ash: messagetorch: not found"
Binary is in "/usr/bin/" folder.
Same message appears if I try to open it via "/usr/bin/messagetorch".
I'm on latest 0.1.4 b330 version of omega and also resetted it to factory. But still the same.
Do you have an idea what else I can try?
Thanks in advance.
@Brice-Parent No need for extra hardware, you can drive WS2812 and WS2813 directly from the Omega, using the ws2812_draiveris kernel module. I mentioned the fact that the driver blocks the kernel for relatively long time because it will affect other kernel timing that is in the sub-millisecond range.
In practice however, I haven't noticed any delays in the usual services running in parallel on the Omega (ssh, onion desktop etc.).
So it's basically just a thing to keep in mind, in case you experience strange behaviour with other peripherals that might rely on tight timing. But otherwise, just use ws2812_draiveris and enjoy the colors