Shop OBEX P1 Docs P2 Docs Learn Events
Interactively test WS2812 NeoPixel LEDs with Tachyon and serial terminal +Matrix demo — Parallax Forums

Interactively test WS2812 NeoPixel LEDs with Tachyon and serial terminal +Matrix demo

Peter JakackiPeter Jakacki Posts: 10,193
edited 2015-07-11 23:05 in Propeller 1
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

«1

Comments

  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-14 18:30
    I tried to try this but was unsuccessful because my Mac terminal program doesn't seem to work correctly with the line delays. Is there any way to write the code to an SD card and load it from their rather than pasting it into the terminal?
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-14 18:49
    I think I figured out how to set the delay correctly. Does this look like a sensible output after loading your sample program?
    0055  ok
    END 
    0056 
    
    00:00:12  End of source code, 0057 lines processed and 0000 errors found 
    MODULES LOADED: 
    34F4: WS2812.fth          WS2812 Intelligent RGB LED driver V1.0 1410131230.0000 
    1900: EXTEND.fth          Primary extensions to TACHYON kernel - 140905-173O
    
    
      Propeller .:.:--TACHYON--:.:. Forth V24140928.1630
    Clock frequency = 80,000,000
    NAMES:  $5BD9...7470 for 6295 (217 bytes added)
    CODE:   $0000...364F for 7608 (347 bytes added)
    CALLS:  0429 vectors free
    RAM:    9610 bytes free
    . ok
    Published
    
    Should I just be able to type CHASE to get the demo to work? I change the pin to P15 near the start and the size to 48 since I have a 16 LED ring. Or do I have to type LEDS first to get the refresh going?
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-14 18:57
    Clearly, I'm not getting the hang of this. I loaded and then typed a few commands:
    KEYPOLL  --> KEYPOLL <-- not found .
    LEDS  ok
    KEYPOLL --> KEYPOLL <-- not found .
    keypoll  ok
    ' LEDS keypoll W!  ok
    CHASE  ok
    
    Looks like "KEYPOLL" is not defined but "keypoll" is. However, when I tried the command that starts with a single quote nothing happened even after I ran the CHASE word. I guess I need to read over the Tachyon word descriptions so I understand what is going on here.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-15 13:42
    Has anyone else tried this? Any idea what I'm doing wrong?
  • mindrobotsmindrobots Posts: 6,506
    edited 2014-10-15 14:09
    I don't have any 2812 LEDs but I did just find a bag of 2811 LEDs. Tomorrow, I can try plugging one into a breadboard and see if I can blow it up while playing with Tachyon. I don't know if I will get to it tonight.

    I have some 2812's on a slow boat from China.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-10-16 05:49
    David Betz wrote: »
    Clearly, I'm not getting the hang of this. I loaded and then typed a few commands:
    KEYPOLL  --> KEYPOLL <-- not found .
    LEDS  ok
    KEYPOLL --> KEYPOLL <-- not found .
    keypoll  ok
    ' LEDS keypoll W!  ok
    CHASE  ok
    
    Looks like "KEYPOLL" is not defined but "keypoll" is. However, when I tried the command that starts with a single quote nothing happened even after I ran the CHASE word. I guess I need to read over the Tachyon word descriptions so I understand what is going on here.

    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.
  • mindrobotsmindrobots Posts: 6,506
    edited 2014-10-16 11:48
    I loaded the latest binary to a Prop BOE with a WS2811 LED wired up to it.

    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.
  • fridafrida Posts: 155
    edited 2014-10-16 12:54
    Should
    #P14 == WSTXD
    
    not be
    #P14 MASK == WSTXD
    
    only this way I can do WSTXD outset and see my output goes high with a led on my output.
    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
    WSTXD 4 COGREG!           --- setup the I/O pin for the RUNMOD
    
    to use or is there someting else to setup.
  • MJBMJB Posts: 1,235
    edited 2014-10-16 13:52
    David Betz wrote: »
    Clearly, I'm not getting the hang of this. I loaded and then typed a few commands:
    KEYPOLL  --> KEYPOLL <-- not found .
    LEDS  ok
    KEYPOLL --> KEYPOLL <-- not found .
    keypoll  ok
    ' LEDS keypoll W!  ok
    CHASE  ok
    
    Looks like "KEYPOLL" is not defined but "keypoll" is. However, when I tried the command that starts with a single quote nothing happened even after I ran the CHASE word. I guess I need to read over the Tachyon word descriptions so I understand what is going on here.
    Hi David,
    I can not test it, since I don't have the LEDs, but from reading the code
    you need this line first
    ' LEDS keypoll W!  ok
    
    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
    ' (CHASE) ledtimer ALARM
    
    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.
  • MJBMJB Posts: 1,235
    edited 2014-10-16 14:03
    frida wrote: »
    Should
    #P14 == WSTXD
    
    not be
    #P14 MASK == WSTXD
    
    only this way I can do WSTXD outset and see my output goes high with a led on my output.
    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
    WSTXD 4 COGREG!           --- setup the I/O pin for the RUNMOD
    
    to use or is there someting else to setup.
    just now see the other posts ...

    yes the RUNMOD needs a MASK, and the OUTCLR as well so
    #P14 MASK == WSTXD
    
    looks correct

    too bad without HW ...
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-16 14:51
    The missing MASK word was a good tip. I now get LEDs to light up. Now I just have to figure out how the words actually work. I typed "CHASE" followed by "LEDS" and a bunch of LEDs lit up. I figured I could get chase to move ahead one step by typing it again followed by LEDS but that put me into an infinite reset loop. Since I'm now able to see something in my LEDs, I guess it's time for me to start really trying to understand Peter's code! :-)
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-16 14:59
    Okay, I typed "CHASE" followed by this:
    ' LEDS keypoll W!
    
    This got my LEDs animating. Not sure if they're displaying what was intended but they are certainly changing once a second or so. I had to add an external power supply to my ActivityBoard because USB wasn't enough to power my 16 LED ring.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-16 15:06
    Here's the video:

    http://youtu.be/os6fUiua4D8
  • fridafrida Posts: 155
    edited 2014-10-16 15:27
    I now have it working.
    First
    ' LEDS keypoll W!
    
    then
    CHASE
    
    Thanks to @David and @MJB
  • fridafrida Posts: 155
    edited 2014-10-16 15:35
    FASTER and SLOWER are doing the opposite.
  • MJBMJB Posts: 1,235
    edited 2014-10-17 02:05
    frida wrote: »
    I now have it working.
    First
    ' LEDS keypoll W!
    
    yes this sets LEDS as the display update routine which is called whenever the key inputs are checked
    then
    CHASE
    
    this is the initialization - needs to be called only once - it sets up a timer to call (CHASE) which advances the LEDs
    Thanks to @David and @MJB
    FASTER and SLOWER just change the timer timeout variable
    and the color words just modify the colors array directly.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-10-17 03:10
    David Betz wrote: »
    Yeah, it was a quick and blind hack and not quite what I intended but it's doing something at least. I may get some LEDs next week and try this out for real but it's fun seeing what everyone comes up with :)
    @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.
  • mindrobotsmindrobots Posts: 6,506
    edited 2014-10-23 07:55
    (**WARNING** My Tachyon code is ugly and most likely inefficient!)

    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.
    pub (CHASE)                                                --- perform a single chase step (move to next LED )
    
             spd W@ ledtimer TIMEOUT                        --- reload timer with current speed
    
             rgbactv rgbsz + 1- C@                        --- save last LEDs BLUE value on stack 
    
             rgbactv rgbsz + 2- C@                        --- save RED value onto STACK
    
             rgbactv rgbsz + 3 - C@                       --- save GREEN value onto stack ( bvalue rvalue gvalue )
    
             rgbactv rgbactv 3 + rgbsz 3 - <CMOVE        --- shift them all along (in reverse)
    
             rgbactv C!                                        --- write saved GREEN byte into LED #1 GREEN
    
             rgbactv 1+ C!                                     --- write saved RED byte into LED #1 RED
    
             rgbactv 2+ C!                                     --- write saved BLUE byte into LED #1 BLUE
    
             ;
    
    pub (SLIDE)                                                --- perform a single chase step (move to next LED )
    
             spd W@ ledtimer TIMEOUT                        --- reload timer with current speed
    
             rgbactv rgbsz + 1- C@                        --- save last LEDs BLUE value on stack 
    
             rgbactv rgbactv 1+ rgbsz 1 - <CMOVE        --- shift them all along (in reverse)
    
             rgbactv C!                                        --- write saved GREEN byte into LED #1 GREEN
             ;
    

    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,
    $FF $FF 0 2 STGLED 
    

    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
    ' LEDS keypoll W!
    

    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!!
    ( WS2812.fth )
    
    TACHYON
    
    [~
    
    FORGET WS2812.fth
    
    pub WS2812.fth         PRINT" WS2812 Intelligent RGB LED driver V1.0 1410131230.0000 " ;
    
    IFNDEF [WS2812]                        --- use newer name for module in case this had the old name
    
    ALIAS [TXRGB] [WS2812]
    
    }
    
    { WS2812 timing
    
    Screenshot from 2014-10-13 12:41:48.png
    
    A zero is transmitted as 350ns high by 800ns low (+/-150ns)
    
    A one is transmitted as 700ns high by 600ns low
    
    RET is >50us
    
    Screenshot from 2014-10-13 12:51:03.png
    
    Screenshot from 2014-10-13 12:51:52.png
    
    A zero is transmitted as 350ns high by 800ns low (+/-150ns)
    
    A one is transmitted as 700ns high by 600ns low
    
    RET is >50us
    
    }
    
    --- UPDATE - WS2812 RUNMOD added to current 2.4 kernel, this is all that is needed now to run it
    
    ( define I/O and an array )
    #P14     MASK == WSTXD               --- define our transmit pin
    
    #12      == rgbsz               --- specify the size of the array as a constant 
                                    --- set to 3 * the number of LEDs (e.g. 4 LEDS, rgbsx = 12)
    
    rgbsz    BYTES rgbactv          --- define our byte array
    rgbsz    BYTES rgbstage         --- define BYTE array for staging LED colors
    
    pub LEDS 
    
          WSTXD OUTCLR              --- Start a RET to synch the chips
    
          WSTXD 4 COGREG!           --- setup the I/O pin for the RUNMOD to use
    
          [WS2812]                   --- select the WS2812 module for RUNMOD (needs to be renamed yet to [WS2812] )
    
          #10 us                    --- still need a bit of extra delay for a minimum RET op while txd is low
    
          rgbactv rgbsz RUNMOD      --- pass the address of the array and the byte count to the RUNMOD
    
          ;
    
    { executing LEDS will update a 96 byte display in 1 ms
    
    The WS2812 LEDs can also be updated in the background of the main console cog this way:
    
    KEYPOLL LEDS
    
    or
    
    ' LEDS keypoll W!
    
    Or called regularly from the timer cog this way:
    
    TIMER ledtimer                 --- create a timer for the LEDs
    
    #20 ledtimer TIMEOUT           --- set it to trip in 20 ms (add this method to LEDS as well to reload)
    
    ' LEDS ledtimer ALARM          --- what to do when the timer expires
    
    }
    
    --- COLOR Definitions 
    
    { From JonnyMac's jm_ws2812.spin demo
      borrowed from Gavin Garner's TM1804 LED driver
      -- additional colors by Lachlan   
      -- some alterations by JM
    }
    
    
    --- the more complex colors really need to be tuned
    --- they are way off for the WS2811 8MM LEDs I'm using
    
    pub RED ( -- gvalue rvalue bvalue) 0 $FF 0 ;    
    
    pub GREEN ( -- gvalue rvalue bvalue)    $FF 0 0 ;
    
    pub BLUE ( -- gvalue rvalue bvalue)   0 0 $FF ;
    
    pub YELLOW ( --- gvalue rvalue bvalue) $FF $FF 0 ;
    
    pub CYAN ( -- gvalue rvalue bvalue)  $FF 0 $FF ;
    
    pub MAGENTA ( -- gvalue rvalue bvalue) 0 $FF $FF ;
    
    pub CHARTREUSE ( --- gv rv bv ) $FF $7F 0 ;
    
    pub ORANGE ( --- gv rv bv ) $60 $FF 0 ;
    
    pub AQUAMARINE ( --- gv rv bv ) $FF $7F $D4 ;
    
    pub PINK ( --- gv rv bv ) $5F $FF $5F ;
    
    pub TURQUOISE ( --- gv rv bv ) $E0 $3F $C0 ;
    
    pub REALWHITE ( --- gv rv bv ) $FF $C8 $FF ; 
    
    pub INDIGO ( --- gv rv bv ) $00 $3F $7F ;
    
    pub VIOLET ( --- gv rv bv ) $7F $BF $BF ;
    
    pub MAROON ( --- gv rv bv ) $00 $32 $10 ;
    
    pub BROWN ( --- gv rv bv ) $06 $0E 0 ;
    
    pub CRIMSON ( --- gv rv bv ) $28 $DC $3C ;
    
    pub PURPLE ( --- gv rv bv )  0 $8C $FF ;
    
    pub WHITE ( -- gvalue rvalue bvalue ) $FF $FF $FF ;
    
    pub BLACK ( --- gvalue rvalue bvalue ) 0 0 0 ;
    
    --- words to work with the two LED color arrays - ACTxxxx affects the ACTive array
    --- STGxxx affects teh staging array
    
    pub STGCLEAR      rgbstage rgbsz ERASE ;
    
    pub ACTCLEAR      rgbactv rgbsz ERASE ;
    
    pub STGDUMP rgbstage rgbsz DUMP ;
    
    pub ACTDUMP rgbactv rgbsz DUMP ;
    
    pub STGLED ( gvalue rvalue bvalue lednum -- )
      1- 3 * rgbstage +         --- calc address of array plus offset for LED
      DUP ROT SWAP           --- ( gv rv bv  addr --- gv rv addr bv addr) 
      2+ C!                 --- put TOS into BLUE byte for this LED
      DUP ROT SWAP           --- ( vg rv addr --- gv addr rv addr )
      1+ C!                 --- put TOS into RED byte for this LED
      C!                     --- put TOS into GREEN byte for this LED
      ;
    
    pub ACTLED ( gvalue rvalue bvalue lednum -- )
      1- 3 * rgbactv +         --- calc address of array plus offset for LED
      DUP ROT SWAP           --- ( gv rv bv  addr --- gv rv addr bv addr) 
      2+ C!                 --- put TOS into BLUE byte for this LED
      DUP ROT SWAP           --- ( vg rv addr --- gv addr rv addr )
      1+ C!                 --- put TOS into RED byte for this LED
      C!                     --- put TOS into GREEN byte for this LED
      ;
    
    
    pub RELOAD rgbstage rgbactv rgbsz CMOVE ;   --- copy the staging byte array to the active byte array
    
    ( Simple DEMO code to make RGB LEDs chase each other )
    
    DECIMAL
    
    TIMER ledtimer                                        --- create a timer structure variable
    
    WORD spd                                                --- allow for the speed to be varied interactively
    
    pub (CHASE)                                                --- perform a single chase step (move to next LED )
    
             spd W@ ledtimer TIMEOUT                        --- reload timer with current speed
    
             rgbactv rgbsz + 1- C@                        --- save last LEDs BLUE value on stack 
    
             rgbactv rgbsz + 2- C@                        --- save RED value onto STACK
    
             rgbactv rgbsz + 3 - C@                       --- save GREEN value onto stack ( bvalue rvalue gvalue )
    
             rgbactv rgbactv 3 + rgbsz 3 - <CMOVE        --- shift them all along (in reverse)
    
             rgbactv C!                                        --- write saved GREEN byte into LED #1 GREEN
    
             rgbactv 1+ C!                                     --- write saved RED byte into LED #1 RED
    
             rgbactv 2+ C!                                     --- write saved BLUE byte into LED #1 BLUE
    
             ;
    
    pub (SLIDE)                                                --- perform a single chase step (move to next LED )
    
             spd W@ ledtimer TIMEOUT                        --- reload timer with current speed
    
             rgbactv rgbsz + 1- C@                        --- save last LEDs BLUE value on stack 
    
             rgbactv rgbactv 1+ rgbsz 1 - <CMOVE        --- shift them all along (in reverse)
    
             rgbactv C!                                        --- write saved GREEN byte into LED #1 GREEN
             ;
    
    --- DEBUG words to manipulate the timer and single step through the ACTIVE array
    
    pub STARTLEDS spd W@ ledtimer TIMEOUT ;  --- set the ledtimer to the curent speed
    
    pub STOPLEDS 0 ledtimer TIMEOUT ;  --- set the ledtimer to 0 (stop the chase)
    
    pub SPEED ( n -- )  1 MAX 10000 MIN spd W! ;
    
    pub FAST                50 SPEED ;
    
    pub SLOW                500 SPEED ;
    
    pub FASTER                spd W@ 80 * 100 / SPEED ;
    
    pub SLOWER                spd W@ 120 * 100 / SPEED ;
    
    pub STEP8                    --- shift the array 1 color BYTE (like a (SLIDE) )
             spd W@                    --- save the current speed to the stack
            0 spd W!                   --- set speed to 0 so you can use (SLIDE)
            (SLIDE)
            spd W!                     --- restore the current speed
             ;
    
    pub STEP24                  --- shift the active array 3 bytes (an LED's worth)
    
             spd W@                    --- save the current speed to the stack
             0 spd W!                  --- set speed to 0 so you can use (CHASE)
             (CHASE)
             spd W!                    --- restore teh current speed
    
             ;
    
    --- demo words ---
    
    pub CHASE ( --- )
    
            GREEN 1 STGLED      --- set first LED to GREEN
            RED 2 STGLED      --- set second LED to RED
            BLUE 3 STGLED      --- set third LED to BLUE
            WHITE 4 STGLED    --- set fourth LED to WHITE
            RELOAD            --- move the staging array to the active array
    
             ' (CHASE) ledtimer ALARM                        --- set action for timer
    
            10 ledtimer TIMEOUT                                --- kick off timer
    
             100 SPEED                                        --- set initial chase speed
    
            ;
    
    pub SLIDE ( --- )
    
            GREEN 1 STGLED      --- set first LED to GREEN
            RED 2 STGLED      --- set second LED to RED
            BLUE 3 STGLED  --- set third LED to BLUE
            WHITE 4 STGLED    --- set fourth LED to WHITE
            RELOAD            --- move the staging array to the active array
    
             ' (SLIDE) ledtimer ALARM                        --- set action for timer
    
            10 ledtimer TIMEOUT                                --- kick off timer
    
             100 SPEED                                        --- set initial chase speed
    
            ;
    
    ]~
    
    END
    
    
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-10-23 09:12
    mindrobots wrote: »
    (**WARNING** My Tachyon code is ugly and most likely inefficient!)



    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,
    $FF $FF 0 2 STGLED 
    

    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
    ' LEDS keypoll W!
    

    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!

    [FONT=courier new]TACHYON
    [~
    
    FORGET WS2812.fth
    
    pub WS2812.fth         PRINT" WS2812 Intelligent RGB LED driver V1.0 1410131230.0000 " ;
    
    IFNDEF [WS2812]                        --- use newer name for module in case this had the old name
    ALIAS [TXRGB] [WS2812]
    }
    
    ( define I/O and an array )
    #P14     MASK == WSTXD               --- define our transmit pin
    
    #12      == rgbsz               --- specify the size of the array as a constant 
                                    --- set to 3 * the number of LEDs (e.g. 4 LEDS, rgbsz = 12)
    
    rgbsz    BYTES rgbactv          --- define our byte array
    rgbsz    BYTES rgbstage         --- define BYTE array for staging LED colors
    
    
    pub !LEDS
          WSTXD OUTCLR              --- Start a RET to synch the chips
          WSTXD 4 COGREG!           --- setup the I/O pin for the RUNMOD to use
          [WS2812]                   --- select the WS2812 module for RUNMOD (needs to be renamed yet to [WS2812] )
      ;
    pub SHOW
          rgbactv rgbsz RUNMOD      --- pass the address of the array and the byte count to the RUNMOD
          #50 us                    --- the RET is specified at 50us so this will ensure it is synched even if LEDS is called again without delay 
          ;
    
    
    --- COLOR Definitions 
    
    \ G R B
    $00FF00        == RED 
    $FF0000        == GREEN
    $0000FF        == BLUE
    $FFFF00        == YELLOW
    $FF00FF        == CYAN
    $00FFFF        == MAGENTA
    $FF7F00        == CHARTREUSE
    $60FF00        == ORANGE
    $FF7FD4        == AQUAMARINE
    $5FFF5F        == PINK
    $E03FC0        == TURQUIOSE
    $FFC8FF        == REALWHITE
    $003F7F        == INDIGO
    $7FBFBF        == VIOLET
    $003210        == MAROON
    $060E00        == BROWN
    $28DC3C        == CRIMSON
    $008CFF        == PURPLE
    $FFFFFF        == WHITE
    $000000        == BLACK
    
    
    --- words to work with the two LED color arrays - ACTxxxx affects the ACTive array
    --- STGxxx affects teh staging array
    
    
    pub STGCLEAR      rgbstage rgbsz ERASE ;
    pub ACTCLEAR      rgbactv rgbsz ERASE ;
    
    
    pub STGDUMP    rgbstage rgbsz DUMP ;
    pub ACTDUMP    rgbactv rgbsz DUMP ;
    
    
    [COLOR=#FF0000]{ alternative is just to say ACT DUMP or STG DUMP or STG ERASE or ACT ERASE
    pub STG        rgbstage rgbsz ;
    pub ACT        rgbactv rgbsz ;
    }[/COLOR]
    
    
    [COLOR=#FF0000]--- perhaps a CMOVE method could work better by first storing the long in a variable
    LONG rgb
    
    pub STGLED ( gvalue.rvalue.bvalue  lednum -- )
        rgbstage
    pub SETLED ( g.r.b lednum buffer --- )
      SWAP 1- 3 * +            --- calc address of array plus offset for LED
      SWAP rgb ! rgb SWAP 3 CMOVE
      ;
    
    pub ACTLED ( gvalue rvalue bvalue lednum -- )
      rgbactv SETLED
      ;
    [/COLOR]
    
    pub RELOAD rgbstage rgbactv rgbsz CMOVE ;   --- copy the staging byte array to the active byte array
    
    ( Simple DEMO code to make RGB LEDs chase each other )
    
    DECIMAL
    
    TIMER ledtimer                                        --- create a timer structure variable
    
    WORD spd                                                --- allow for the speed to be varied interactively
    
    pub (CHASE)                                                --- perform a single chase step (move to next LED )
             spd W@ ledtimer TIMEOUT                        --- reload timer with current speed
    [COLOR=#FF0000]\ pub STEP24[/COLOR]
             rgbactv rgbsz + 1- C@                        --- save last LEDs BLUE value on stack 
             rgbactv rgbsz + 2- C@                        --- save RED value onto STACK
             rgbactv rgbsz + 3 - C@                       --- save GREEN value onto stack ( bvalue rvalue gvalue )
             rgbactv rgbactv 3 + rgbsz 3 - <CMOVE        --- shift them all along (in reverse)
             rgbactv C!                                        --- write saved GREEN byte into LED #1 GREEN
             rgbactv 1+ C!                                     --- write saved RED byte into LED #1 RED
             rgbactv 2+ C!                                     --- write saved BLUE byte into LED #1 BLUE
             [COLOR=#ff0000]SHOW                                         --- just write this all to the LEDs right now rather than using KEYPOLL[/COLOR]
             ;
    
    pub (SLIDE)                                                --- perform a single chase step (move to next LED )
             spd W@ ledtimer TIMEOUT                        --- reload timer with current speed
    [COLOR=#FF0000]\ pub STEP8[/COLOR]
             rgbactv rgbsz + 1- C@                        --- save last LEDs BLUE value on stack 
             rgbactv rgbactv 1+ rgbsz 1 - <CMOVE        --- shift them all along (in reverse)
             rgbactv C!                                        --- write saved GREEN byte into LED #1 GREEN
    [FONT=courier new]         [COLOR=#ff0000]SHOW                                         --- just write this all to the LEDs right now[FONT=courier new][COLOR=#ff0000] rather than using KEYPOLL[/COLOR][/FONT]
    [/COLOR][/FONT]         ;
    
    --- DEBUG words to manipulate the timer and single step through the ACTIVE array
    
    pub STARTLEDS        spd W@ ledtimer TIMEOUT ;  --- set the ledtimer to the curent speed
    
    pub STOPLEDS        0 ledtimer TIMEOUT ;  --- set the ledtimer to 0 (stop the chase)
    
    [COLOR=#FF0000]{
    Or use this:
    pub LEDS ( on/off -- )    spd W@ AND ledtimer TIMEOUT !LEDS ;
    
    \ so you can say ON LEDS or OFF LEDS
    
    }
    [/COLOR]
    
    --- percentage of speed increase or decrease so 80 % will run 80% of the current speed
    pub % ( n -- )        200 SWAP - spd W@ * 100 / 
     pub SPEED ( n -- )    1 MAX 10000 MIN spd W! ;
    
    pub FAST                50 SPEED ;
    
    pub SLOW                500 SPEED ;
    
    pub FASTER              120 % ;
    
    pub SLOWER              80 % ;
    [COLOR=#800080]
    ( NOTE: could STEP8 and STEP24 just be an entry into (CHASE) and (SLIDE) as shown above ? )
    
    pub STEP8                    --- shift the array 1 color BYTE (like a (SLIDE) )
            spd W@                    --- save the current speed to the stack
            0 spd W!                   --- set speed to 0 so you can use (SLIDE)
            (SLIDE)
            spd W!                     --- restore the current speed
             ;
    
    pub STEP24                  --- shift the active array 3 bytes (an LED's worth)
             spd W@                    --- save the current speed to the stack
             0 spd W!                  --- set speed to 0 so you can use (CHASE)
             (CHASE)
             spd W!                    --- restore teh current speed
             ;
    [/COLOR]
    --- demo words ---
    
    pub CHASE ( --- )
             ' (CHASE) ledtimer ALARM                        --- set action for timer
     pub LIGHT
            GREEN 1 STGLED      --- set first LED to GREEN
            RED 2 STGLED      --- set second LED to RED
            BLUE 3 STGLED      --- set third LED to BLUE
            WHITE 4 STGLED    --- set fourth LED to WHITE
            RELOAD            --- move the staging array to the active array
    
             100 SPEED                                        --- set initial chase speed
    [COLOR=#ff0000]        ON LEDS  
    [/COLOR]        ;
    
    pub SLIDE ( --- )
            ' (SLIDE) ledtimer ALARM                        --- set action for timer
            LIGHT
            ;
    
    ]~
    
    END[/FONT]
    

    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.
  • mindrobotsmindrobots Posts: 6,506
    edited 2014-10-23 09:29
    Nifty!! I like the optimizations! Thank you, I will implement and test mein Propellertachyongetestenmachine!

    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!! :lol:
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-10-23 21:43
    mindrobots wrote: »
    Nifty!! I like the optimizations! Thank you, I will implement and test mein Propellertachyongetestenmachine!

    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!! :lol:

    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!
  • mindrobotsmindrobots Posts: 6,506
    edited 2014-10-24 20:06
    Those look like fun LED sticks!

    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.
    ( WS2812.fth )
    
    TACHYON
    
    [~
    
    FORGET WS2812.fth
    
    pub WS2812.fth         PRINT" WS2812 Intelligent RGB LED driver V1.0 1410131230.0000 " ;
    
    IFNDEF [WS2812]                        --- use newer name for module in case this had the old name
    
    ALIAS [TXRGB] [WS2812]
    
    }
    
    { WS2812 timing
    
    Screenshot from 2014-10-13 12:41:48.png
    
    A zero is transmitted as 350ns high by 800ns low (+/-150ns)
    
    A one is transmitted as 700ns high by 600ns low
    
    RET is >50us
    
    Screenshot from 2014-10-13 12:51:03.png
    
    Screenshot from 2014-10-13 12:51:52.png
    
    A zero is transmitted as 350ns high by 800ns low (+/-150ns)
    
    A one is transmitted as 700ns high by 600ns low
    
    RET is >50us
    
    }
    
    --- UPDATE - WS2812 RUNMOD added to current 2.4 kernel, this is all that is needed now to run it
    
    ( define I/O and an array )
    #P14     MASK == WSTXD               --- define our transmit pin
    
    #12      == rgbsz               --- specify the size of the array as a constant 
                                    --- set to 3 * the number of LEDs (e.g. 4 LEDS, rgbsx = 12)
    
    rgbsz    BYTES rgbactv          --- define our byte array
    rgbsz    BYTES rgbstage         --- define BYTE array for staging LED colors
    
    pub  !LEDS 
    
          WSTXD OUTCLR              --- Start a RET to synch the chips
    
          WSTXD 4 COGREG!           --- setup the I/O pin for the RUNMOD to use
    
          [WS2812]                   --- select the WS2812 module for RUNMOD (needs to be renamed yet to [WS2812] )
         ;
    
    pub SHOW
          rgbactv rgbsz RUNMOD      --- pass the address of the array and the byte count to the RUNMOD
            #50 us
    
          ;
    
    \ executing !LEDS will update a 96 byte display in 1 ms
    
    
    --- COLOR Definitions 
    
    { From JonnyMac's jm_ws2812.spin demo
      borrowed from Gavin Garner's TM1804 LED driver
      -- additional colors by Lachlan   
      -- some alterations by JM
    }
    
    
    --- the more complex colors really need to be tuned
    --- they are way off for the WS2811 8MM LEDs I'm using
    
    \ G R B
    $00FF00        == RED 
    $FF0000        == GREEN
    $0000FF        == BLUE
    $FFFF00        == YELLOW
    $FF00FF        == CYAN
    $00FFFF        == MAGENTA
    $FF7F00        == CHARTREUSE
    $60FF00        == ORANGE
    $FF7FD4        == AQUAMARINE
    $5FFF5F        == PINK
    $E03FC0        == TURQUIOSE
    $FFC8FF        == REALWHITE
    $003F7F        == INDIGO
    $7FBFBF        == VIOLET
    $003210        == MAROON
    $060E00        == BROWN
    $28DC3C        == CRIMSON
    $008CFF        == PURPLE
    $FFFFFF        == WHITE
    $000000        == BLACK
    
    --- words to work with the two LED color arrays: ACTIVE and STAGE
    
    pub ACTIVE      rgbactv rgbsz ;
    
    pub STAGE       rgbstage rgbsz ;
    
    --- SETLED places color values for a specific LED into ACTIVE or STAGE color arrays
    --- example: RED 3 ACTIVE SETLED --- sets LED#3 in ACTIVE buffer to RED
    
    LONG rgb   --- create a long to save the passed G.R.B into for CMOVE
    
    pub SETLED ( g.r.b lednum buffer bufsz --- )
    
      DROP                     --- extra parameter from using ACTIVE/STAGE words
    
      SWAP 1- 3 * +            --- calc address of array plus offset for LED
    
      SWAP rgb ! rgb SWAP 3 CMOVE
    
      ;
    
    
    pub RELOAD rgbstage rgbactv rgbsz CMOVE ;   --- copy the staging byte array to the active byte array
    
    ( Simple DEMO code to make RGB LEDs chase each other )
    
    DECIMAL
    
    TIMER ledtimer                                        --- create a timer structure variable
    
    WORD spd                                                --- allow for the speed to be varied interactively
    
    pub (CHASE)                                                --- perform a single chase step (move to next LED )
    
             spd W@ ledtimer TIMEOUT                        --- reload timer with current speed
    
    pub STEP24
    
             rgbactv rgbsz + 1- C@                        --- save last LEDs BLUE value on stack 
    
             rgbactv rgbsz + 2- C@                        --- save RED value onto STACK
    
             rgbactv rgbsz + 3 - C@                       --- save GREEN value onto stack ( bvalue rvalue gvalue )
    
             rgbactv rgbactv 3 + rgbsz 3 - <CMOVE        --- shift them all along (in reverse)
    
             rgbactv C!                                        --- write saved GREEN byte into LED #1 GREEN
    
             rgbactv 1+ C!                                     --- write saved RED byte into LED #1 RED
    
             rgbactv 2+ C!                                     --- write saved BLUE byte into LED #1 BLUE
    
            SHOW
    
             ;
    
    pub (SLIDE)           --- slide the colors through the array one byte each time
    
             spd W@ ledtimer TIMEOUT            --- reload timer with current speed
    pub STEP8
    
             rgbactv rgbsz + 1- C@           --- save last LEDs BLUE value on stack 
    
             rgbactv rgbactv 1+ rgbsz 1 - <CMOVE        --- shift them all along (in reverse)
    
             rgbactv C!                                        --- write saved GREEN byte into LED #1 GREEN
    
            SHOW
    
             ;
    
    --- DEBUG words to manipulate the timer and single step through the ACTIVE array
    
    pub LEDS ( on/off -- )    spd W@ AND ledtimer TIMEOUT !LEDS ;
    
    pub SPEED ( n -- )  1 MAX 10000 MIN spd W! ;
    
    pub FAST                50 SPEED ;
    
    pub SLOW                500 SPEED ;
    
    pub FASTER                spd W@ 80 * 100 / SPEED ;
    
    pub SLOWER                spd W@ 120 * 100 / SPEED ;
    
    --- demo words ---
    
    pub CHASE ( --- )
    
            ' (CHASE) ledtimer ALARM
    
    pub LIGHT
    
            GREEN 1 STAGE SETLED      --- set first LED to GREEN
    
            RED 2 STAGE SETLED      --- set second LED to RED
    
            BLUE 3 STAGE SETLED      --- set third LED to BLUE
    
            WHITE 4 STAGE SETLED    --- set fourth LED to WHITE
    
            RELOAD            --- move the staging array to the active array
    
            SLOW               --- set initial chase speed
    
            ON LEDS
    
            ;
    
    pub SLIDE ( --- )
    
            ' (SLIDE) ledtimer ALARM             --- set action for timer
    
            LIGHT
    
            ;
    
    ]~
    
    END
    
    
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-10-24 20:26
    mindrobots wrote: »
    Those look like fun LED sticks!

    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 ):
    [FONT=courier new]TACHYON [~
    
    FORGET WS2812.fth
    
    pub WS2812.fth         PRINT" WS2812 Intelligent RGB LED driver V1.0 1410131230.0000 " ;
    
    IFNDEF [WS2812]                        --- use newer name for module in case this had the old name
    
    ALIAS [TXRGB] [WS2812]
    
    }
    
    DECIMAL
    
    ( define I/O and an array )
    #P8     MASK    == WSTXD                --- define our transmit pin
    
    8               == ledcnt               --- number of LEDs in string
    
    ledcnt 3 *      == rgbsz                --- specify the size of the array as a constant 
                                            --- set to 3 * the number of LEDs (e.g. 4 LEDS, rgbsx = 12)
    
    rgbsz    BYTES rgbactv                  --- define our byte array
    rgbsz    BYTES rgbstage                 --- define BYTE array for staging LED colors
    
    --- Setup the RUNMOD and port for the WS2812
    pub !LEDS
          WSTXD OUTCLR                      --- Start a RET to synch the chips
          WSTXD 4 COGREG!                   --- setup the I/O pin for the RUNMOD to use
          [WS2812]                          --- select the WS2812 module for RUNMOD (needs to be renamed yet to [WS2812] )
      ;
    
    
    --- Show the contents of rgbactv on the LEDs  
    pub SHOW 
          rgbactv rgbsz RUNMOD              --- pass the address of the array and the byte count to the RUNMOD
          #50 us                            --- the RET is specified at 50us so this will ensure it is synched even if SHOW is called again without delay 
          ;
    
    
    --- COLOR Definitions 
    
    \ G R B
    $00FF00         == RED 
    $FF0000         == GREEN
    $0000FF         == BLUE
    $FFFF00         == YELLOW
    $FF00FF         == CYAN
    $00FFFF         == MAGENTA
    $FF7F00         == CHARTREUSE
    $60FF00         == ORANGE
    $FF7FD4         == AQUAMARINE
    $5FFF5F         == PINK
    $E03FC0         == TURQUIOSE
    $FFC8FF         == REALWHITE
    $003F7F         == INDIGO
    $7FBFBF         == VIOLET
    $003210         == MAROON
    $060E00         == BROWN
    $28DC3C         == CRIMSON
    $008CFF         == PURPLE
    $FFFFFF         == WHITE
    $000000         == BLACK
    
    
    --- words to work with the two LED color arrays 
    --- ACT  affects the ACTive array
    --- STG affects teh staging array
    
    \ alternative is just to say ACT DUMP or STG DUMP or STG ERASE or ACT ERASE
    pub STG         rgbstage rgbsz ;
    pub ACT         rgbactv rgbsz ;
    
    
    
    LONG rgb        --- holding variable to allow CMOVE into array
    
    \ Usage: <color> led STG LED or <color> led ACT LED
    \ Example: RED 4 STG LED
    \ note: sz is redundant but passed as part of buffer parameter
    pub LED! ( g.r.b lednum buffer sz --- )
            DROP
            SWAP 1- 3 * +                   --- calc address of array plus offset for LED
            SWAP rgb ! rgb SWAP 3 CMOVE
            ;
    
    
    
    pub RELOAD      rgbstage rgbactv rgbsz CMOVE ;   --- copy the staging byte array to the active byte array
    
    ( Simple DEMO code to make RGB LEDs chase each other )
    
    
    TIMER ledtimer                                        --- create a timer structure variable
    
    WORD spd                                              --- allow for the speed to be varied interactively
    
    pub (CHASE)                                           --- perform a single chase step (move to next LED )
             spd W@ ledtimer TIMEOUT                      --- reload timer with current speed
     pub STEP3
            rgbactv rgbsz + 3 - U@ rgb !                  --- read last 3 colors unaligned as a long (only use 3 ls bytes)
            rgbactv rgbactv 3 + rgbsz 3 - <CMOVE          --- shift them all along (in reverse)
            rgb rgbactv 3 CMOVE                           --- write last 3 bytes back to start (wrap)
            ;
    
    pub (SLIDE)                                           --- perform a single chase step (move to next LED )
             spd W@ ledtimer TIMEOUT                      --- reload timer with current speed
     pub STEP1
             rgbactv rgbsz + 1- C@                        --- save last LEDs BLUE value on stack 
             rgbactv rgbactv 1+ rgbsz 1 - <CMOVE          --- shift them all along (in reverse)
             rgbactv C!                                   --- write saved GREEN byte into LED #1 GREEN
             ;
    
    --- DEBUG words to manipulate the timer and single step through the ACTIVE array
    
    
    --- starts or stops the timer using current speed
    : LEDS ( on/off -- )    spd W@ AND ledtimer TIMEOUT ;
    
    
    
    --- percentage of speed increase or decrease so 80 % will run 80% of the current speed
    
    pub % ( n -- )          200 SWAP - spd W@ * 100 / 
     pub SPEED ( n -- )     1 MAX 10000 MIN spd W! ;
    
    pub FAST                50 SPEED ;
    
    pub SLOW                500 SPEED ;
    
    pub FASTER              120 % ;
    
    pub SLOWER              80 % ;
    
    
    --- demo words ---
    
    pub CHASE ( --- )
             ' (CHASE) ledtimer ALARM               --- set alarm action for timer
     pub LIGHT
            !LEDS                                   --- allow timer task to setup the I/O and WS2812 RUNMOD
            STG ERASE
            GREEN 1 STG LED!                        --- set first LED to GREEN
            RED 2 STG LED!                          --- set second LED to RED
            BLUE 3 STG LED!                         --- set third LED to BLUE
            WHITE 4 STG LED!                        --- set fourth LED to WHITE
            RELOAD                                  --- move the staging array to the active array
            SLOW                                    --- set initial chase speed
            ON LEDS
            ' SHOW keypoll W!
            ;
    
    pub SLIDE ( --- )
             ' (SLIDE) ledtimer ALARM                        --- set action for timer
            LIGHT
            ;
    
    ]~ END
    [/FONT]
    
  • mindrobotsmindrobots Posts: 6,506
    edited 2014-10-24 21:28
    Thank you! That's interesting about the timers and WAITCNTs.

    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!
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-10-24 22:29
    mindrobots wrote: »
    Thank you! That's interesting about the timers and WAITCNTs.

    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:
    BYTE refresh                --- create a flag to indicate a synchronized refresh is requested
    pub REFRESH    refresh C~~ ;
    
    --- Show the contents of rgbactv on the LEDs  
    pub SHOW 
        refresh C@ 0EXIT
        refresh C~            --- clear refresh flag and uppdate the LEDs
        rgbactv rgbsz RUNMOD  --- pass the address of the array and the byte count to the RUNMOD
        #50 us                --- the RET is specified at 50us so this will ensure it is synched even if SHOW is called again without delay 
        ;
    

    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.
  • mindrobotsmindrobots Posts: 6,506
    edited 2014-10-25 09:06
    The new code works great!

    (I noticed a bit more streamlining - cool tricks!)

    I'll get to play if I ever finish my chores today.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-10-25 17:15
    mindrobots wrote: »
    The new code works great!

    (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:
    pub RELOAD      
         rgbstage 
     pub LOAD ( src -- )
         ACT CMOVE       --- copy the source array to the active byte array
         ;
    

    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.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-25 19:53
    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!
    I have one of those sticks. They come from AdaFruit, the same people who made the 16 LED ring I've been using. They're nice products! I'd like to order the AdaFruit 8x8 LED matrix but it's a bit expensive.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-25 20:47
    What does #P13 do? It seems to just push 13 on the stack just like 13 would do.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-10-25 22:09
    David Betz wrote: »
    What does #P13 do? It seems to just push 13 on the stack just like 13 would do.

    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
Sign In or Register to comment.