Interactively test WS2812 NeoPixel LEDs with Tachyon and serial terminal +Matrix demo
Peter Jakacki
Posts: 10,193
Yesterday I was asked if I could interface to the WS2812 LEDs so I had a look at the datasheet and implemented a very simple addition to the kernel. I've checked all the timing and it is very good and all that is needed is a byte array in memory and a size which is passed to the WS2818 driver. In fact the driver doesn't use a special cog, it will just run from whichever it is called from, normally the console cog. So this allows for interacting with LEDs and that is exactly what I would be doing now, ..... if I had any that is.
So if you are game, if you adventurous, if you want to see what you can do then grab the latest Tachyon binary, F11 it into your favorite board, hook up a serial terminal at 230,400 baud and go over to this code document where you can just select all, copy, then paste it in through the terminal.
I have included a demo called CHASE where you can tell it to go faster or slower (FASTER or SLOWER) or whatever speed as it is running.
If you are cluey though you can change the pattern on the fly as well and even modulate the brightness as it moves but the code isn't there for that although it is extremely simply to do.
Terminal settings are 230,400 8N1 and 15ms LINE delay (not character delay). Recommended terminals are TeraTerm or minicom.
Latest Tachyon binary (works automatically with 5 or 10MHz crystals)
TACHYON.binary
BTW, although I can't see the LEDs I can look at the buffer while it is running (using ^X to repeat the last operation each time):
rgbleds $40 DUMP
0000_45D4: 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 ................
0000_45E4: 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 ................
0000_45F4: FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 ................
0000_4604: FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 00 ................ ok
0000_45D4: 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF ................
0000_45E4: 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 ................
0000_45F4: 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 ................
0000_4604: 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 ................ ok
0000_45D4: 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF ................
0000_45E4: 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 ................
0000_45F4: 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 ................
0000_4604: 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 ................ ok
0000_45D4: 00 FF 00 FF 00 00 00 FF 00 FF 00 00 00 00 FF 00 ................
0000_45E4: FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 00 ................
0000_45F4: FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 ................
0000_4604: 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF ................ ok
0000_45D4: 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF ................
0000_45E4: 00 00 00 00 FF 00 FF 00 FF 00 00 00 FF 00 FF 00 ................
0000_45F4: 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 ................
0000_4604: FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 ................ ok
0000_45D4: FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 00 ................
0000_45E4: FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 ................
0000_45F4: 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF ................
0000_4604: 00 00 00 00 FF 00 FF 00 FF 00 00 00 FF 00 FF 00 ................ ok
0000_45D4: 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 ................
0000_45E4: 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 ................
0000_45F4: 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 ................
0000_4604: FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 ................ ok
So if you are game, if you adventurous, if you want to see what you can do then grab the latest Tachyon binary, F11 it into your favorite board, hook up a serial terminal at 230,400 baud and go over to this code document where you can just select all, copy, then paste it in through the terminal.
I have included a demo called CHASE where you can tell it to go faster or slower (FASTER or SLOWER) or whatever speed as it is running.
If you are cluey though you can change the pattern on the fly as well and even modulate the brightness as it moves but the code isn't there for that although it is extremely simply to do.
Terminal settings are 230,400 8N1 and 15ms LINE delay (not character delay). Recommended terminals are TeraTerm or minicom.
Latest Tachyon binary (works automatically with 5 or 10MHz crystals)
TACHYON.binary
BTW, although I can't see the LEDs I can look at the buffer while it is running (using ^X to repeat the last operation each time):
rgbleds $40 DUMP
0000_45D4: 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 ................
0000_45E4: 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 ................
0000_45F4: FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 ................
0000_4604: FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 00 ................ ok
0000_45D4: 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF ................
0000_45E4: 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 ................
0000_45F4: 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 ................
0000_4604: 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 ................ ok
0000_45D4: 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF ................
0000_45E4: 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 ................
0000_45F4: 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 ................
0000_4604: 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 ................ ok
0000_45D4: 00 FF 00 FF 00 00 00 FF 00 FF 00 00 00 00 FF 00 ................
0000_45E4: FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 00 ................
0000_45F4: FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 ................
0000_4604: 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF ................ ok
0000_45D4: 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF ................
0000_45E4: 00 00 00 00 FF 00 FF 00 FF 00 00 00 FF 00 FF 00 ................
0000_45F4: 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 ................
0000_4604: FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 ................ ok
0000_45D4: FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 00 ................
0000_45E4: FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 ................
0000_45F4: 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF ................
0000_4604: 00 00 00 00 FF 00 FF 00 FF 00 00 00 FF 00 FF 00 ................ ok
0000_45D4: 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 ................
0000_45E4: 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 FF 00 ................
0000_45F4: 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 FF 00 ................
0000_4604: FF 00 00 00 00 FF 00 FF 00 FF 00 00 00 00 FF 00 ................ ok
Comments
I have some 2812's on a slow boat from China.
It looks like I deprecated KEYPOLL at some stage and forgot about it as most of the time the "keypoll" variable is set directly from user code rather than from user console. In code you would say:
' myfunction keypoll W!
to set keypoll with the address of the function.
You can call CHASE directly as that is basically what happens in the background with "keypoll" when it's waiting for user input from the console.
I was unable to make the CHASE word work. If I just enter CHASE, it does nothing but goes off to hang my system. If I enter
' CHASE keypoll W!
it goes off to do it's thing but I don't see anything on the LED.
Just to make sure the hardware was OK (and a WS2811 worked like a WS2812), I loaded up JonnyMac's WS2812 demo and it worked just fine with the WS2811.
I haven't had a chance to play more with the Tachyon version yet.
When I set WSTXD outset, my led comes on.
When I use LED, my led goes off.
I can follow the change in the array with ^x on the terminal, but there is nothing on the output?
Could it be something with to use or is there someting else to setup.
I can not test it, since I don't have the LEDs, but from reading the code
you need this line first the ' kind of returns the function pointer of the LEDS word which is them stored in the keypoll word variable.
This is a vector that if not 0 is called in the keypoll loop.
KEYPOLL is not defined, and keypoll is just a variable (its address actually) - therefore written in lowercase by convention.
inside CHASE here the alarm callback is installed, which is the function pointer to (CHASE)
- looks strange, but a function name surounded by () is just to mark an internal function (by convention)
the () really is part of the function / WORD name. Everything separated by a SPACE is a word ...
an other option to having the keypoll set up would be to put LEDS directly at the end of (CHASE) - so it is automatically called,
when the colors have been changed.
The benefit of the keypoll variant is that you can then interactively just modify colors and speed
and the update is automatic.
so do not see, why it is not working for you.
yes the RUNMOD needs a MASK, and the OUTCLR as well so
looks correct
too bad without HW ...
http://youtu.be/os6fUiua4D8
First then Thanks to @David and @MJB
and the color words just modify the colors array directly.
@fride - whoops, faster should be less of a delay. LEDs could be called from CHASE if you want and then just keypoll CHASE.
The main thing was to make sure that bit of code was handling the bit timing correctly, then it should be possible to do some fancy stuff at the high level interactively, even just typing in one line loops without actually creating a definition, as is possible in Tachyon.
This started off when I noticed that as I played with the colors and the CHASE, I was seeing colors introduced in my LED string that I had never entered.
I looked at the (CHASE) routine and saw that it is shifting the color array 1 byte with each iteration, NOT 3 bytes. This means that each time through, the BLUE value for the last LED becomes the GREEN value for the first LED, GREEN for LED1 become RED for LED1 and RED for LED1 goes to BLUE for LED1. So if you have a 2 LED setup with LED 1 set to green ($FF0000) and LED2 set to blue ($0000FF)
$FF0000 0000FF after one trip through (CHASE) will look like this: $FFFF00 000000; trip 2 will yield $$00FFFF 000000 and finally, trip #3 will yield $0000FF FF0000 - at this point, you have really moved the color from LED1 to LED2 and LED2 to LED1. I've called the 8 bit shift a (SLIDE) and fixed (CHASE) to do a 24 bit shift.
(CHASE) contains my changes, (SLIDE) is Peter's original (CHASE) just renamed.
Once I did this, I was hooked and started playing (darn LEDs and Tachyon!!!!)
I set up a staging array so you can set a pattern in the staging area and then move it to the active array (RELOAD).
Created some TIMER controls: STARTLEDS, STOPLEDS, STEP8 and STEP24. The last two do a 8 bit or 24 bit single step.
Added words to set the colors into the two arrays: STGLED and ACTLED. These will plug the GRB values into the proper array based on an LED# offset, for example,
will place the proper G ($FF) R($FF) and B(0) values for YELLOW into the staging array for LED #2.
After this , I needed colors so I could RED and get $00 $FF $00 on the stack and YELLOW would put $FF $FF $00 on the stack.
I borrowed more complex colors from Jonny Mac's WS2812 spin program - most of them need to be tuned for my WS2811 8MM diffused LEDs ( I think the need for a color tools has arisen so you can play with the GRB values to find values for your LEDs.)
This all led to a highly modified (and butchered) version of Peter's original demo code. It still uses the roots of his work but is hacked up a bit. I've attached it for you playtime if you so desire. (it's good for a laugh, just to see how I write Tachyon!)
Once you load it, you still need to do
to get things started. From there you can try CHASE or SLIDE or stop the CHASE with STOPLEDS and then go manipulate the colors with ACTLED or STGLED and RELOAD and then start it all again with STARTLEDS.
If you want to see the difference between Peter's (CHASE) and mine, get to the point where CHASE is running and then STOPLEDS, look at the pattern, do STEP24 and you should see each LED color move to the right, then do a STEP8 and you will see some new colors introduced.
It's all good fun and blinking lights!
Thanks Peter for getting me started in Tachyon again!!
Inefficient or not, it works and it's fun
Without making too many real changes here is a slight optimization as a suggestion. I mainly put the colors into a long but there are other subtle changes too but beware I've written it blind so it may be full of little bugs!
It could be cleaner too by reducing STGLEDS to STG LEDS so that it works likes STG DUMP and STG ERASE etc. The idea is to create a language that is more like English rather than concatenatedtechnicalgerman.
Tachyon has grown up so much since I last played. I forgot things like the entry into a pub for step8 and step24.
I'm brute forcing my way back in here with my old brute Forth mentality. I need to dig through the Tachyon thread and code to pick up on all the elegance you have added.
You'll really start having fun if you ever get any LEDs!!
I've just ordered 5 sticks of 8 LEDs locally although I wanted more and some discrete component LEDs as well but I'm looking at the flexible strips on eBay and thinking that I could line these up in rows of 7 or so to form a really long flexible message board that I might even use to read email on from my Prop! Howzat!
OK, I appear to have broken the timer somehow. I implemented your improvements (maybe modified and added a few) but I think I captured the needed parts.
The individual pieces all seem to work. I can load the arrays with colors for the specified LEDs, SHOW them on the LEDs, (CHASE) them or (SLIDE) them. The only thing not working is the timer. It appears to stop or run very, very slowly. It looks good when you do .TIMERS but it never fires. I've been staring at it for a couple hours now, and trying things to no avail. Obviously, I'm missing something and/or don't understand the timers (they seemed pretty straight forward).
I'm open to suggestions from anyone.
There are a couple of conflicts that I discovered, first off the TIMERTASK cog is the one that needs to initialize the LED pin and RUNMOD for it to be able to call it automatically. However the WAITCNT used by the RUNMOD also upsets the WAITCNT that is used to synch the TIMERTASK so the RUNMOD either has to be changed or just get it to run under keypoll. Here's code that will work ( just type CHASE or SLIDE to start ):
I'll give this a try with some LEDs when my morning rolls around.
I like how you refine and tune the code as you iterate through the versions. I may accidently learn something yet!
There's lots of things that can be added very easily, such as synchronizing the updates for instance, just change this and add the REFRESH word to the end of the (CHASE) and (SLIDE) defs:
So the other thing I would add would be brightness modulation at the refresh level so that you can run a timer and extract it's current value, convert it to triangle or sine even and use that value to vary the brightness every time the LEDs are refreshed which would also not need to be synchronized then. To keep it efficient the modulation index could just be applied either as a shift or added/subtracted and clipped, this will produce some stroboscopic effects on top of the current pattern with some LEDs appearing to glow brighter before fading etc.
Also of course we can just have a file or an array set up to produce any pattern that we want. Once I get enough rows and columns I will do that scrolling message display or a digital clock at least!.
BTW, even though I don't have any LEDs yet I just tie the transmit pin to the scope through a 1M resistor to analog the signal (RC filter) so I can see the pattern moving across the screen.
The code cleanup was mainly because I decided to check it and then I discovered the WAITCNT problem so I tidied everything up in the process. So you can change individual LEDs on the fly of course with the <color> <led> ACT LED! command etc or just stop it with OFF LEDS and use STEP1 or STEP3 etc.
(I noticed a bit more streamlining - cool tricks!)
I'll get to play if I ever finish my chores today.
Great, and remembering that it's interactive means you could type $C000 ACT CMOVE while it's running to introduce a pattern from ROM for instance. In fact RELOAD could be redone as a more general load with:
So now you just say 0 LOAD or $C000 LOAD etc. In the next couple of days I when I get to actually try this stuff hands on I will add modulation and twinkling to the standard chaser. Can't wait to get those long strings though to do a message display, but I'm still selecting suitable ones, thinking maybe the higher density 2m strips in rows of 7 or 8 would be awesome.
The # prefix forces a number to decimal and I allow symbols to be mixed with digits so you could say 13 or #13 or #P13 or even #PORT13 as it all resolves the same way but #P13 is much more recognizable as a port number rather than just some constant.
Here are a few commented examples:
$13120520 .LONG 1312.0520 ok
force hex
$13.12.05.20 .LONG 1312.0520 ok
force hex with separators
$13:12:05:20 .LONG 1312.0520 ok
force hex
#13:12:05:20 .LONG 0D0C.0514 ok
force decimal with BCD clock style notation
$1312_0520 .LONG 1312.0520 ok
force hex with separators
#13120520 .LONG 00C8.3408 ok
force decimal
#1312_0520 .LONG 00C8.3408 ok
force decimal with separators
#80,000,000 .LONG 04C4.B400 ok
force decimal with commas etc
01_1100 .BYTE 9C ok
force binary
&192.168.16.1 .LONG C0A8.1001 ok
specify an IP address
#P26 .BYTE 1A ok
specify a port number
#P26:25:19:18 .LONG 1A19.1312 ok
packing pin numbers into a long (used to set device pinouts)
BTW, I looked at getting the 8x8 matrix but figured that 8 of the 8 way strips were better value and more flexible, although they only had 5 left in stock. If I am going to do a matrix I am better off with rows of the LED ropes.
EDIT: Just created a blog entry in regards to numeric notation