GE color effects assembly driver
EE351
Posts: 81
Hello all!
I am working on an assembly driver for the GE color effects rgb lights. This is my first attempt at writing any assembly code, so be kind please! I modified the driver originally written by Robert Quattlebaum so that a byte array could be passed to the assembly code. I have the code working but there is one part of the assembly routine that I can't figure out. I am passing the first address of a byte array to the assembly program; however, I have to offset the address by 4 to get it to align correctly with the first byte. Can anyone tell me what I'm doing wrong?
I am working on an assembly driver for the GE color effects rgb lights. This is my first attempt at writing any assembly code, so be kind please! I modified the driver originally written by Robert Quattlebaum so that a byte array could be passed to the assembly code. I have the code working but there is one part of the assembly routine that I can't figure out. I am passing the first address of a byte array to the assembly program; however, I have to offset the address by 4 to get it to align correctly with the first byte. Can anyone tell me what I'm doing wrong?
{{ TOP OBJECT FILE }} CON _clkmode = xtal1 + pll16x _xinfreq = 6_250_000 CON ON_PIN = 12 OBJ xmas : "xmas2" VAR long set_array byte rgb_array[108] PUB start xmas.start(ON_PIN) 'xmas.set_standard_enum 'xmas.stand_alone_test set_array := @rgb_array repeat BYTEFILL(@rgb_array,$FF,108) xmas.send_raw_command(@set_array) waitcnt(6250000 + cnt) BYTEFILL(@rgb_array,$00,108) xmas.send_raw_command(@set_array) waitcnt(6250000 + cnt)
{{ ** GE Color Effects Control Object ** Version 0.2, 2010-12-02 ** by Robert Quattlebaum <darco@deepdarc.com> ** ** http://www.deepdarc.com/2010/11/27/hacking-christmas-lights/ ** ** This object file is public domain. You may use it as you see fit. MODIFIED BY PAUL MATOS }} CON { General constants } CMD_LEN = 26 MAX_COLOR_VALUE = $F MAX_HUE = (MAX_COLOR_VALUE+1)*6-1 DEFAULT_INTENSITY = $CC ' Default controler never uses larger than this. MAX_INTENSITY = $FF MAX_BULB = $3E ' Theoretical last possible bulb address. Note ' that normally there are only 50 bulbs on a string. BROADCAST_BULB = $3F ' Intensity set on this bulb affects all bulbs. CON { Color convenience constants } COLOR_MASK = $FFF COLOR_BLACK = $000 COLOR_WHITE = $DDD ' Default controler uses this value for white. COLOR_BLUE = $F00 COLOR_GREEN = $0F0 COLOR_RED = $00F COLOR_CYAN = COLOR_GREEN|COLOR_BLUE COLOR_MAGENTA = COLOR_RED|COLOR_BLUE COLOR_YELLOW = COLOR_RED|COLOR_GREEN CON { These constants are needed only for the stand alone test mode. } _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 VAR long cog long command PUB stand_alone_test | i,j,b {{ Stand alone test. Used only when you run this object directly. }} ' Start up our cog. start(12) ' Give the attached string the default bulb enumeration. set_standard_enum ' This code makes an animated rainbow. repeat repeat until ina[16] i++ repeat j from 0 to MAX_BULB set_bulb(j,b,make_color_hue((i+j)//constant(MAX_HUE+1))) repeat 4 if b<DEFAULT_INTENSITY b++ set_bulb(BROADCAST_BULB,b,0) repeat while b i++ b-- set_bulb(BROADCAST_BULB,b,0) repeat 100 repeat while ina[16] repeat until ina[16] repeat while ina[16] PUB start(pin) {{ Starts the cog for the object using the given pin index for output. }} ' Stop the object if it is already running stop ' Set up pin output_pin_mask := |< pin ' Set up # of bulbs added by PJM no_bulbs := 36 'length of string ' ***FOR YBOX2 ONLY*** ' output_pin_mask := (|< 12)|(|< 13)|(|< 14) ' Set the timing information period_10_us := (clkfreq/1_000_000) * 10 ' Start the cog cog := cognew(@cog_init, @command) + 1 ' Make sure the cog actually started ifnot cog abort -1 return cog PUB stop {{ Stops the object. You must call start again before you can use this object. }} if cog cogstop(cog~ - 1) ' cog variable is cleared by this statement command~ PUB set_standard_enum | i {{ Performs the standard bulb enumeration for individual bulb control. }} repeat i from 0 to MAX_BULB set_bulb(i,DEFAULT_INTENSITY,COLOR_BLACK) PUB flush {{ Wait for any prior command to finish. }} repeat while command AND (cog > 0) PUB send_raw_command(x) {{ Sends a single command, consisting of the 26 least significant bits of x. }} ' We use the most significant bit ' to help us determine when the command ' has been sent by the cog. This works ' because the command length is only 26 ' bits, and the most significant bit won't ' be used otherwise. 'x |= constant(|<31) 'commented out by PJM ' Wait for any previous command to finish. flush 'commented out by PJM ' Set the command. The cog will notice this ' and send it automatically, clearing ' the command variable when it is finished. command := x PUB make_color_rgb(r,g,b) {{ Helper function for converting discrete red, green, and blue values into a single 12 bit color value. }} return (r&MAX_COLOR_VALUE)|((g&MAX_COLOR_VALUE)<<4)|((b&MAX_COLOR_VALUE)<<8) PUB make_color_hue(hue) {{ Helper function for creating a color based on a hue value. hue must be between 0 and MAX_HUE. }} case (hue>>4) 0: hue &= MAX_COLOR_VALUE return make_color_rgb(MAX_COLOR_VALUE,hue,0) 1: hue &= MAX_COLOR_VALUE return make_color_rgb((MAX_COLOR_VALUE-hue),MAX_COLOR_VALUE,0) 2: hue &= MAX_COLOR_VALUE return make_color_rgb(0,MAX_COLOR_VALUE,hue) 3: hue &= MAX_COLOR_VALUE return make_color_rgb(0,(MAX_COLOR_VALUE-hue),MAX_COLOR_VALUE) 4: hue &= MAX_COLOR_VALUE return make_color_rgb(hue,0,MAX_COLOR_VALUE) 5: hue &= MAX_COLOR_VALUE return make_color_rgb(MAX_COLOR_VALUE,0,(MAX_COLOR_VALUE-hue)) return 0 PUB set_bulb(bulb,intensity,color) | x {{ Convenience function for setting the intensity and color for the specified bulb index. }} send_raw_command(((bulb&$3F)<<20)|((intensity&$FF)<<12)|(color&COLOR_MASK)) DAT { Cog Implementation } org cog_init or dira, output_pin_mask ' Initialize output pin direction loop wrlong zero,par ' Clear out the previous command :waitforcmd rdlong array_ready,par wz ' Wait for next command if_z jmp #:waitforcmd mov array_ptr,array_ready mov bulb_counter,no_bulbs add array_ptr,#4 'offset byte array by 4 to get first byte? bulb_loop rdbyte red_byte,array_ptr 'read red byte and red_byte,#$f0 'mask the upper 4 bits add array_ptr,#1 'move the arrary pointer to get green byte rdbyte green_byte,array_ptr 'read green byte and green_byte,#$f0 'mask the upper 4 bits add array_ptr,#1 'move the arrary pointer to get blue byte rdbyte blue_byte,array_ptr 'read blue byte and blue_byte,#$f0 'mask the upper 4 bits shl blue_byte,#4 'shift the blue bits into the correct position shr green_byte,#4 'shift the green bits into the correct position or current_command,blue_byte 'place blue bits into current command or current_command,red_byte 'place red bits into current command or current_command,green_byte 'place green bits into current command or current_command,bulb_intensity 'place bulb intensisty bits into current command mov bulb_address,no_bulbs 'calculate bulb address sub bulb_address,bulb_counter shl bulb_address,#20 'shift the bulb address bits into the correct position or current_command,bulb_address 'place bulb address bits into current command ' Send the command 'call #send_cmd send_cmd ' Load number of data bits mov current_bit, #CMD_LEN ' Rotate the bits so that the next bit is at bit zero. rol current_command, #(32-CMD_LEN) ' Set up next_cnt mov next_cnt, period_10_us add next_cnt, cnt ' Send start pulse or outa, output_pin_mask ' Output high waitcnt next_cnt, period_10_us ' Wait 10 uSeconds andn outa, output_pin_mask ' Output low :output_loop rol current_command, #1 wc if_c waitcnt next_cnt, period_10_us ' Wait extra 10 uSeconds if one bit waitcnt next_cnt, period_10_us ' Wait 10 uSeconds or outa, output_pin_mask ' Output high if_nc waitcnt next_cnt, period_10_us ' Wait extra 10 uSeconds if zero bit waitcnt next_cnt, period_10_us ' Wait 10 uSeconds andn outa, output_pin_mask ' Output low ' Decrement current_bit ; jump if not Zero djnz current_bit, #:output_loop ' Finish up the frame with 30 uSecond quiet period. waitcnt next_cnt, period_10_us ' Wait 10 uSeconds waitcnt next_cnt, period_10_us ' Wait 10 uSeconds waitcnt next_cnt, period_10_us ' Wait 10 uSeconds waitcnt next_cnt, period_10_us ' Wait 10 uSeconds waitcnt next_cnt, period_10_us ' Wait 10 uSeconds waitcnt next_cnt, period_10_us ' Wait 10 uSeconds mov current_command,zero 'clear current command add array_ptr,#1 ''move the arrary pointer to get red byte djnz bulb_counter, #bulb_loop 'repeat for the next bulb ' Jump back to the start and wait for next command jmp #loop 'DAT { Send Command Subroutine } 'send_cmd_ret ret DAT { Constants } period_10_us long 0 ' Set at init time output_pin_mask long 0 ' Set at init time no_bulbs long 0 ' Set at init time zero long 0 bulb_intensity long %00000000_00001100_00110000_00000000 DAT { Variables } next_cnt res 1 current_command res 1 current_bit res 1 array_ptr res 1 red_byte res 1 green_byte res 1 blue_byte res 1 bulb_counter res 1 array_ready res 1 bulb_address res 1
Comments
Any other cool tips you'd like to share?
It looks like you're using the same starting code I used with my project using these LEDs. I arranged my LEDs in a 2D grid and wrote some code to scroll text on the array. In hindsight, I don't think a 2D array is the best use for these LEDs but it was still fun.
I'm thinking of programming in some Halloween messages and have the LEDs lit with orange hues (or any other colors I can think of to make Xmas lights look like Halloween lights).
In the off chance you're interested in using these LEDs in a 2D grid (I can't say I recommend it), I attached my code to this post.
BTW, xlights is pretty neat. It can do scrolling text, a bunch of cool patterns, and you can set the rgb colors very easily without modifying the prop code.
Based upon everything I read/watched yesterday, Vixen seemed to be involved but I don't understand why. Is it used to create pixel by pixel effects by hand from the ground up?
I would like to use xLights on my laptop direct to a controller (Prop/DMX or other) via USB or preferably ethernet E131 and I am open to any reasonable cost ethernet module (ESP8266????)
As far as ethernet goes, the enc28j60 module on ebay is about as cheap as it gets for adding ethernet to a project.
xLights does synchronize music with effects. I know they were/are working on or have the ability to import label files (for timing so you don't have to manually type in the start time for each event) from Audacity in addition to importing the mp3 file. I was just watching a video today where they imported Stars and Stripes Forever.
Yes it is hard to beat that price but my only concern is my ability (or lack thereof) to program for it as I can only spell "C", never liked it, but I will have to look at the trade off from cost to ability to program for it.
https://www.youtube.com/watch?v=YR-itnatUJY&feature=youtu.be
These are the ge color effects rgb leds. The array is 16 strings with 36 leds each.