Getting Started with the WS2801 3-Channel RGB LED Driver with PWM output

westaust55

Moderator
The WorldSemi WS2801 chip has been around for some time and is relatively simple to connect to the PICAXE range of chips including the older 18X, together with the X1, X2 and M2 parts.

These 3-channel constant current LED drivers are great for controlling strings of RGB LEDs. The WS2801 is controlled by a 2-wire serial control scheme (SPI like) that allows multiple WS2801 chips to be daisy chained together.
Use a handful of these chips in conjunction with some RGB LEDs can create a colour displays, or with regular LEDs for a monochrome display a display that is three times the size. It would even be possible to just the WS2801 as a source of some simple PWM outputs to free up PWM pins on your PICAXE by controlling multiple LEDs with only two pins.

WS2801 features include:
  • 3.3 V to 5.5 V Power supply
  • 2-wire control scheme reduces no of PICAXE IO required
  • Built-in PWM dimming scheme for each channel with free running PWM
  • Supports both constant current drive mode (most frequently used scheme) and constant voltage drive mode
  • Wide constant current range from 5-150mA (total of 3 channels) - NOTE: As a constant current driver, each channel is limited to 30 mA.

The Attached tutorial provides some details about the WS2801 that might not be immediately clear to newcomers including:
  • how the data is clocked through when there are multiple WS2801 daisy chained together
  • calculating the resistor valve for current limiting
  • typical schematic for connection of several WS2801 chips to a PICAXE
  • program examples for X1, X2, M2 and 18X PICAXE parts.

PICAXE BASIC program files are included in the following 2 posts

For the M2 parts, the serial data transfer routine is based upon that previously posted by hippy
This makes for a compact looping routine for the M2 parts which do not have the SHIFTOUT commands available in the X1 and X2 parts.
The looping structure does however require the PICAXE to be run at a higher clock speed (16 MHz) to meeting the WS2801 timing requirements.

By comparison, with the SHIFTOUT command and a short string of WS2801 chips, the X1 and X2 parts can be operated at 4 MHz clock speed and still meet the WS2801 timing requirements,

Hopefully others will find this information useful to avoid problems and get a WS2801 based RGB LED string up and running quickly.
 

Attachments

westaust55

Moderator
Attached are the BASIC programs suitable for the PICAXE X1 and X2 parts.

Remember:
With respect to the X1 and X2 parts, when there are more WS2801 chips in a string and additional SHIFTOUT commands are used such as:
going from
Code:
; Subroutine to serially clock out the data through the SW2801 chips for THREE RGB LEDs
; NOTE this is limited to three WS2801 chips without adding more variables/field to the SHIFTOUT command
SendData:
	Ptr = 0
	SHIFTOUT SClock,SData,MSBFirst_L,(@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc)
	RETURN
to
Code:
; Subroutine to serially clock out the data through the SW2801 chips for THREE RGB LEDs
; NOTE this is limited to three WS2801 chips without adding more variables/field to the SHIFTOUT command
SendData:
	Ptr = 0
	SHIFTOUT SClock,SData,MSBFirst_L,(@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc)
	SHIFTOUT SClock,SData,MSBFirst_L,(@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc)
	RETURN
that the minimum clock speed MUST be increased to 8 MHz.

With the X2 parts where even higher clock speeds are possible a looping structure can also be used with a single SHIFTOUT command.


A further note with respect to the SHIFTOUT command:
From some past work done with colour gLCD displays from mobile phones, have 2 or 3 data bytes in/with a single SHIFTOUT command will see at least 25% speed increase compared with a single data byte. From memory, the speeds plateaus around 3 or 4 bytes and thereafter no speed improvement was identified.
Thus having the data for one RGB LED in a single SHIFTOUT command even when looping will achieve better speed.
 

Attachments

Last edited:

westaust55

Moderator
Attached are the BASIC programs suitable for the PICAXE M2 and 18X parts


EDIT: (re: 08M2)

For the 08M2, the additional memory available for storage of byte variable data is from location 28 to lcoation 127 ($1C to $7F)
For the 18M2 (early version) the memory range is 28 to 255 ($1C to $FF)
For the 14M2, 20M2 and 18M2+ the memory range is 28 to 511 ($1C to $1FF)

Accordingly in addition to changing the IO pin declarations to suit the particular PICAXE chip, for the 08M2 only, the program line:
SYMBOL DataBaseAddr = $80
needs to be changed to a lower starting address such as
SYMBOL DataBaseAddr = $30
 

Attachments

Last edited:

2gttalon

New Member
Attached are the BASIC programs suitable for the PICAXE M2 and 18X parts
Thank you very much for spreading this information. I have been working with the ws2801 chip for a few months. I would like to try the code you have for the 18m2. I am still learning with conversions from chip to chip. What items would need to be changed in that code to allow it to work for a 14m2 ?
 

westaust55

Moderator
Thank you very much for spreading this information. I have been working with the ws2801 chip for a few months. I would like to try the code you have for the 18m2. I am still learning with conversions from chip to chip. What items would need to be changed in that code to allow it to work for a 14m2 ?
The only changes needed to use with the 14M2 is to assign new IO pins.
With the 18M2 there are 8 PortB pins whereas the 14M2 only has 6 PortB pins but you can use any combination of 3 IO pins whether from portB or PortC.

so near the top of my program listing ther are the lines:
Code:
; -----[ I/O Definitions ]-------------------------------------------------- 

; - - - DIGITAL INPUT PINS  - - -
; none used
;
; - - - DIGITAL OUTPUT PINS - - - 
SYMBOL SData	= [COLOR="#FF0000"]pinB.6[/COLOR] ; SDI Pin on WS2801 - used to transfer 1 bit of data to a pin
SYMBOL S_Data	=[COLOR="#FF0000"] B.6[/COLOR] ; SDI Pin	- also defined this way to use with the LOW command in Init:
SYMBOL SClock	= [COLOR="#FF0000"]B.7[/COLOR] ; CKI Pin on WS2801
You will need to change the IO pins allocated as identified in red text and wire accordingly.
This is the advantage of using SYMBOL declarations as you only need to go to one place in the program and make changes that are in effect global to the program

EDIT:
Note SDATA and S_Data reference the same physical IO pin. Both needed as means of addressing the pin by different commands.
 
Last edited:

tony_g

Senior Member
the thought of using this to gain more pwm outputs is appealing especially as these seem to be relatively cheeap.

the only issue for me is that i have not played with shift registers before so am having some issues understanding the full ins and outs of using these.
the only thing i really dont understand and cant seem to get from the datasheet or reading around online is the data input for each colors bits, i.e bits 7 - 0 how do they correlate to led brightnes or pwm and how do i calculate the data i need to put in them to use these chips for either led driving of rgb or for extra pwm channels?
 

westaust55

Moderator
The WS2801 has a free running oscillator for the base frequency of the PWM channels. The datasheet sugegsts the PWM frequency is 2.5 kHz.

What you are changing with the data sent to the WS2801 is the duty cycle or on-time relative to the total time of one cycle.

You must clock out three bytes for each WS2801 in series. Those bytes represent the red, green and blue channels respectively.
For each channel/colour the value of the byte 0 to 255 determines the duty/on time of the LED driver output.
0 is basically off and 255 is maximum output.
 

tony_g

Senior Member
thanks westy, after i asked that i started searching around for code examples to try and see how others were using them.

i guess the whole use of each individual bit value as opposed to the whole byte is what threw me off so i just used a quick PE sketch putting different values in B0 then watching the output in simulator with the value and the individual bits change with each different number i put into B0.

i guess im so used to doing just basic things with the picaxe that i have not really branched out into more interesting ideas that teach me to use something im used to in a different way.
 
thanks Westaust55 for the easy to follow code examples. Even I can understand them! I will certainly be messing around with these chips. I see them on eBay in lots of 10 or 50 for a very cheap price. And I happen to have some PLCC RGB chips laying around. I'm wondering if you have any idea how the folks are using these to create the cool "chase sequence" as in this video:
http://www.youtube.com/watch?v=xjdXM1D_fHQ

I realize this is using Arduino, but I'm wondering if this can be done with a pixaxe 20x2.

Thanks again for the excellent write-up. I'm looking forward to playing around with these WS2801's.

Regards,
Brian Andonian
 

Jamster

Senior Member
aviatorbja: You may have just tempted me to spend some money, which isn't good considering I'm spending a lot recently... :confused:

I would guess at 64Mhz you could get a 1m strip of that running quite quickly and possibly more at a push, you could just Daisy-Chain PICAXEs for a similar effect.

Jamster
 

westaust55

Moderator
I suggest that if you are going to try and drive long strips of RGB LEDs with the WS2801 chips at something approaching the speeds shown in the YouTube video it will be necessary to us an X1 or X2 chip.

Then with the X1/X2 chips you have the inbuilt SHIFTOUT command which is faster than any form of bit-banged code for the M2 parts.
From my own past speed checks SHIFTOUT is around 4 time fastern than a bit-bang routine in a FOR...NEXT loop.

The next step if you are not also using i2c comms for EEPROM or RTC access is to consider the hardware SPI commands (HSPISETUP, HSPIOUT, HSPIIN) which are faster then the firmware based SHIFTOUT command.
 
thank you westaust. I will be building a board with 5 WS2801 chips and 5 LED's just to see if I can do cool things like the video sequence. I have a 20x2 set aside for the task.
As soon as my WS2801 chips arrive from China, I'll be making some crazy colors (hopefully). Your tutorial will be at my side.

My wife already thinks I've gone mad playing around with these controllers, this will only make things worse. My 11 year-old daughter on the other hand, is just as fascinated by this stuff as I am. I plan to implement this into a clock/nighlight design of some sort.
 

westaust55

Moderator
By way of another example for driving WS2801 controlled RGB LED's, below is some code to drive a string of (just) six WS2801 chips.
This code is for a 40X1 (easily altered for an X2 part) and after slowly (1 sec increments so the observer can see the steps) stepping throught to illuminate the six RBG LEDs in sequence with different colours, then rapidly (well as fast as a 40X1 can at 8 Mhz) cycles six colours around the six WS2801/RGB LED modules.

This code occupies almost 1 kByte of program space and defines a relatively limited number of colour sequences in a loop.
Using EEPROM memory to hold the data as per some of my previous examples would reduce the program size but the sequence will be limited to the 256 bytes of EEPROM space unless an external EEPROM is used.
If random of other sequences are sought then using math equations involving commands such as RANDOM, SIN, COS, << or >>, etc, will likely achieve results involing far less program space.

In terms of maximum speed, as a guide only, with the 40X1 using the SHFITOUT command and clocked at 8 MHz, 4 frames per second are sent to the string of WS2801 chips.
So as a guide, using an X2 PICAXE part at 32 Mhz one would achieve around 16 frames per second.

If your project does not have any i2c parts connected then the HSERSETUP/HSEROUT commands can be used which may get the frame rate up to say 50 or 60 per second (untested as yet by me).
However, as you add more WS2801 chips to the string, the frame rate for updates to the entire strip of WS2801 chips will drop inversely.

Code:
; =================================================
;   File....... 40X1 6xWS2801
;   Purpose.... A demo program to show control of a string of six WS2801 RGB LED drivers
;   Author..... Westaust55
;   E-mail.....
;   Started.... 09-02-2013
;   Updated.... DD-MM-YYYY
; =================================================
;
; -----[ Program Description ]---------------------------------------------
; A program to to demonstrate the control of a short string of six WS2801 RGB LED driver chips
;  
; -----[ Revision History ]---------------------------------------------------
;
; A = 09-02-2013	First release	total program size = 1013 bytes
; =================================================

#PICAXE 40X1

SETFREQ M8 	     ; 8 Mhz is minimum speed when there are multiple SHIFTOUT commands
SYMBOL SData	= 6 ; SDI Pin
SYMBOL SClock	= 7 ; CKI Pin 

SYMBOL LED_Data	= b0
SYMBOL MemAddr 	= b4
SYMBOL Index 	= b11


; Define genral constants
SYMBOL LongDelay  = 1000
SYMBOL ShortDelay = 1
; Define EEPROM locations for colour data
SYMBOL Red 		= $24
SYMBOL Green 	= $27
SYMBOL Blue 	= $2A
SYMBOL Magenta 	= $2D
SYMBOL Yellow 	= $30
SYMBOL Cyan 	= $33
SYMBOL White	= $36
SYMBOL Black	= $39

; Define some colours with 3 Bytes per colour at quarter intensity - $FF for max intensity
EEPROM $24, ($3F, $00, $00) ; Red
EEPROM $27, ($00, $3F, $00) ; Green
EEPROM $2A, ($00, $00, $3F) ; Blue
EEPROM $2D, ($3F, $00, $3F) ; Magenta
EEPROM $30, ($3F, $3F, $00) ; Yellow
EEPROM $33, ($00, $3F, $3F) ; Cyan
EEPROM $36, ($3F, $3F, $3F) ; White
EEPROM $39, ($00, $00, $00) ; Black / Off

Init:
	Low SData
	Low Sclock
	
Main:
    DO
; first clear all WS2801's then illuminate in white and next back to cleared/black/off
; second clock through in six steps to provide a progressive range of colours until all RGB LEDs are illiminated
  		ptr = 0
  		MemAddr = Black  : GOSUB FetchColour ; first WS2801/RGB LED data
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour ; sixth WS2801/RGB LED data
		GOSUB SendData
  		PAUSE LongDelay
   		ptr = 0
  		MemAddr = White  : GOSUB FetchColour
  		MemAddr = White  : GOSUB FetchColour
  		MemAddr = White  : GOSUB FetchColour
  		MemAddr = White  : GOSUB FetchColour
  		MemAddr = White  : GOSUB FetchColour
  		MemAddr = White  : GOSUB FetchColour
		GOSUB SendData
  		PAUSE LongDelay
  		ptr = 0
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
		GOSUB SendData
  		PAUSE LongDelay
  		ptr = 0
  		MemAddr = Red    : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
		GOSUB SendData
  		PAUSE LongDelay
  		ptr = 0
  		MemAddr = Yellow : GOSUB FetchColour
  		MemAddr = Red    : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
		GOSUB SendData
  		PAUSE LongDelay
   		ptr = 0
  		MemAddr = Green : GOSUB FetchColour
  		MemAddr = Yellow : GOSUB FetchColour
  		MemAddr = Red   : GOSUB FetchColour
  		MemAddr = Black : GOSUB FetchColour
  		MemAddr = Black : GOSUB FetchColour
  		MemAddr = Black : GOSUB FetchColour
		GOSUB SendData
  		PAUSE LongDelay 
   		ptr = 0
  		MemAddr = Cyan  : GOSUB FetchColour
  		MemAddr = Green : GOSUB FetchColour
  		MemAddr = Yellow : GOSUB FetchColour
   		MemAddr = Red   : GOSUB FetchColour
  		MemAddr = Black : GOSUB FetchColour
  		MemAddr = Black : GOSUB FetchColour
		GOSUB SendData
  		PAUSE LongDelay		
   		ptr = 0
  		MemAddr = Blue  : GOSUB FetchColour
   		MemAddr = Cyan  : GOSUB FetchColour
  		MemAddr = Green : GOSUB FetchColour
  		MemAddr = Yellow : GOSUB FetchColour
   		MemAddr = Red   : GOSUB FetchColour
  		MemAddr = Black : GOSUB FetchColour
  		GOSUB SendData
  		PAUSE LongDelay
    		ptr = 0
  		MemAddr = Magenta : GOSUB FetchColour
  		MemAddr = Blue  : GOSUB FetchColour
   		MemAddr = Cyan  : GOSUB FetchColour
  		MemAddr = Green : GOSUB FetchColour
  		MemAddr = Yellow : GOSUB FetchColour
   		MemAddr = Red   : GOSUB FetchColour
  		GOSUB SendData
  		PAUSE LongDelay 
  		
; Now cycle the six colours rapidly in a loop around the six WS2801/RGB LED modules
 	FOR Index = 0 to 32 		
      	ptr = 0
   		MemAddr = Red   : GOSUB FetchColour
   		MemAddr = Magenta : GOSUB FetchColour
  		MemAddr = Blue  : GOSUB FetchColour
   		MemAddr = Cyan  : GOSUB FetchColour
  		MemAddr = Green : GOSUB FetchColour
  		MemAddr = Yellow : GOSUB FetchColour
  		GOSUB SendData
  		PAUSE ShortDelay	
      	ptr = 0
  		MemAddr = Yellow : GOSUB FetchColour
   		MemAddr = Red   : GOSUB FetchColour
   		MemAddr = Magenta : GOSUB FetchColour
  		MemAddr = Blue  : GOSUB FetchColour
   		MemAddr = Cyan  : GOSUB FetchColour
  		MemAddr = Green : GOSUB FetchColour
  		GOSUB SendData
  		PAUSE ShortDelay
      	ptr = 0
  		MemAddr = Green : GOSUB FetchColour
  		MemAddr = Yellow : GOSUB FetchColour
   		MemAddr = Red   : GOSUB FetchColour
   		MemAddr = Magenta : GOSUB FetchColour
  		MemAddr = Blue  : GOSUB FetchColour
   		MemAddr = Cyan  : GOSUB FetchColour
  		GOSUB SendData
  		PAUSE ShortDelay
      	ptr = 0
   		MemAddr = Cyan  : GOSUB FetchColour
  		MemAddr = Green : GOSUB FetchColour
  		MemAddr = Yellow : GOSUB FetchColour
   		MemAddr = Red   : GOSUB FetchColour
   		MemAddr = Magenta : GOSUB FetchColour
  		MemAddr = Blue  : GOSUB FetchColour
  		GOSUB SendData
  		PAUSE ShortDelay
      	ptr = 0
  		MemAddr = Blue  : GOSUB FetchColour
   		MemAddr = Cyan  : GOSUB FetchColour
  		MemAddr = Green : GOSUB FetchColour
  		MemAddr = Yellow : GOSUB FetchColour
   		MemAddr = Red   : GOSUB FetchColour
   		MemAddr = Magenta : GOSUB FetchColour
  		GOSUB SendData
  		PAUSE ShortDelay  		
    		ptr = 0
  		MemAddr = Magenta : GOSUB FetchColour
  		MemAddr = Blue  : GOSUB FetchColour
   		MemAddr = Cyan  : GOSUB FetchColour
  		MemAddr = Green : GOSUB FetchColour
  		MemAddr = Yellow : GOSUB FetchColour
   		MemAddr = Red   : GOSUB FetchColour
  		GOSUB SendData
  		PAUSE ShortDelay  		
  	NEXT Index	
    LOOP ; repeat the entire sequence
;
; ***** Subroutine to fetch the data from EEPROM and save into Scratchpad for one RGB LED colour
  
  FetchColour:
	READ MemAddr, LED_Data
	@PtrInc = LED_Data
	INC  MemAddr
	READ MemAddr, LED_Data
	@PtrInc = LED_Data
	INC  MemAddr
	READ MemAddr, LED_Data
	@PtrInc = LED_Data
  	RETURN
  
  ;
  ; Subtoutine to serially clock out the data through/to a string of six SW2801 chips as two groups of three RGB LEDs	
  SendData:	
	Ptr = 0
  	SHIFTOUT SClock,SData,MSBFirst_L,(@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc)
  	SHIFTOUT SClock,SData,MSBFirst_L,(@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@Ptr)
  	RETURN
 
Very ,Very Helpful westaust. I still dont have my WS chips, but I do have a 20x2 dedicated, so I'll try the hardware spi mode.
thanks again for the well written code.
 

westaust55

Moderator
Getting Started with the WS2801 3-Channel RGB LED Driver with PWM output - more demo

I did some further work today based on my string of six WS2801 drivers with RGB LED’s.

With a forecast max of 41 degC today [as paid work, I have worked in up to 54 degC but not paid work today :rolleyes: ],
it was a good day to be out early in the morning to wash a car and then head indoors :)

This time, rather than a rolled out linear string of BASIC commands to set the colour and position of each RGB LED, I have used a loop with maths to determine what colour is used at what LED position. In addition the intensities of the LEDs rises and falls in a sinusoidal fashion so in fact there is more presented to the observer than in the example given in post 13.

I did leave the initial part of the code the same as that provided in Post 13 above so that folks can see both the linear and rolled up/looping methodologies.

Two advantages have flowed out of this change in programming concept:
1. A reduced program size – down from 1013 bytes to 786 bytes ( a saving of 227 bytes or 22.4% program space with greater visual variation) :)
2. A faster frame rate. Now running at 12 to 13 frames per second with 40X1 at 8 MHz (as opposed to 4 frames per second). :)

I have checked the speeds several times for both programs (post 13 and below) with 360 loops of the program for both. The linear sequence takes around 85 seconds where as the looped structure with extra math for sinusoidal intensity dimming takes about 29 seconds using a 40X1 at 8 MHz.
In fact at 12 to 13 frames it is difficult to ascertain the variation in intensities for the 6 LEDs as they are 30 degree phase shifted and I had to change the PAUSE from ShortDelay (1 ms) to LongDelay (1 sec) in the second program for the loop to see it was really happening..

So with a PICAXE X2 part at 32 Mhz we might achieve of the order of 60 frames per second with the second method – still only using the SHIFTOUT command. Final frame rates will always be dependent upon the complexities of the math in the FOR…NEXT loop.

Code:
; =================================================
;   File....... 40X1 6xWS2801
;   Purpose.... A demo program #2 to show control of a string of six WS2801 RGB LED drivers
;   Author..... Westaust55
;   E-mail.....
;   Started.... 10-02-2013
;   Updated.... DD-MM-YYYY
; =================================================
;
; -----[ Program Description ]---------------------------------------------
; A program to to demonstrate the control of a short string of six WS2801 RGB LED driver chips
; using Looping structures and maths to determine colour for each RBG LED with varying intensities
;  
; -----[ Revision History ]---------------------------------------------------
;
; A = 10-02-2013	First release	total program size = 786 bytes
; =================================================

#PICAXE 40X1

SETFREQ M8 		; 8 Mhz is minimum speed when there are multiple SHIFTOUT commands
SYMBOL SData	= 6 ; SDI Pin
SYMBOL SClock	= 7 ; CKI Pin 

SYMBOL TotalMods	= 3
SYMBOL Data_Sets	= 4

SYMBOL LED_Data	= b0
SYMBOL MemAddr 	= b4
SYMBOL Index 	= w6
SYMBOL Angle	= w7
SYMBOL Intensity	= b16
SYMBOL Colour	= b17
SYMBOL RGBLEDNo	= b18

; Define genral constants
SYMBOL LongDelay  = 1000
SYMBOL ShortDelay = 1
; Define EEPROM locations for colour data
SYMBOL Red 		= $24
SYMBOL Green 	= $27
SYMBOL Blue 	= $2A
SYMBOL Magenta 	= $2D
SYMBOL Yellow 	= $30
SYMBOL Cyan 	= $33
SYMBOL White	= $36
SYMBOL Black	= $39

; Define some colours with 3 Bytes per colour at half intensity - $FF for max intensity
EEPROM $24, ($80, $00, $00) ; Red
EEPROM $27, ($00, $80, $00) ; Green
EEPROM $2A, ($00, $00, $80) ; Blue
EEPROM $2D, ($80, $00, $80) ; Magenta
EEPROM $30, ($80, $80, $00) ; Yellow
EEPROM $33, ($00, $80, $80) ; Cyan
EEPROM $36, ($3F, $3F, $3F) ; White
EEPROM $39, ($00, $00, $00) ; Black / Off

Init:
	Low SData
	Low Sclock
	
Main:
    DO
; first clear all WS2801's then illuminate in white and next back to cleared/black/off
; second clock through in six steps to provide a progressive range of colours until all RGB LEDs are illiminated
  		Intensity = 100
  		ptr = 0
  		MemAddr = Black  : GOSUB FetchColour ; first WS2801/RGB LED data
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour ; sixth WS2801/RGB LED data
		GOSUB SendData
  		PAUSE LongDelay
   		ptr = 0
  		MemAddr = White  : GOSUB FetchColour
  		MemAddr = White  : GOSUB FetchColour
  		MemAddr = White  : GOSUB FetchColour
  		MemAddr = White  : GOSUB FetchColour
  		MemAddr = White  : GOSUB FetchColour
  		MemAddr = White  : GOSUB FetchColour
		GOSUB SendData
  		PAUSE LongDelay
  		ptr = 0
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
		GOSUB SendData
  		PAUSE LongDelay
  		ptr = 0
  		MemAddr = Red    : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
		GOSUB SendData
  		PAUSE LongDelay
  		ptr = 0
  		MemAddr = Yellow : GOSUB FetchColour
  		MemAddr = Red    : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
		GOSUB SendData
  		PAUSE LongDelay
   		ptr = 0
  		MemAddr = Green : GOSUB FetchColour
  		MemAddr = Yellow : GOSUB FetchColour
  		MemAddr = Red   : GOSUB FetchColour
  		MemAddr = Black : GOSUB FetchColour
  		MemAddr = Black : GOSUB FetchColour
  		MemAddr = Black : GOSUB FetchColour
		GOSUB SendData
  		PAUSE LongDelay 
   		ptr = 0
  		MemAddr = Cyan  : GOSUB FetchColour
  		MemAddr = Green : GOSUB FetchColour
  		MemAddr = Yellow : GOSUB FetchColour
   		MemAddr = Red   : GOSUB FetchColour
  		MemAddr = Black : GOSUB FetchColour
  		MemAddr = Black : GOSUB FetchColour
		GOSUB SendData
  		PAUSE LongDelay		
   		ptr = 0
  		MemAddr = Blue  : GOSUB FetchColour
   		MemAddr = Cyan  : GOSUB FetchColour
  		MemAddr = Green : GOSUB FetchColour
  		MemAddr = Yellow : GOSUB FetchColour
   		MemAddr = Red   : GOSUB FetchColour
  		MemAddr = Black : GOSUB FetchColour
  		GOSUB SendData
  		PAUSE LongDelay
    		ptr = 0
  		MemAddr = Magenta : GOSUB FetchColour
  		MemAddr = Blue  : GOSUB FetchColour
   		MemAddr = Cyan  : GOSUB FetchColour
  		MemAddr = Green : GOSUB FetchColour
  		MemAddr = Yellow : GOSUB FetchColour
   		MemAddr = Red   : GOSUB FetchColour
  		GOSUB SendData
    		PAUSE LongDelay
  		ptr = 0
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
  		MemAddr = Black  : GOSUB FetchColour
		GOSUB SendData
  		PAUSE LongDelay
  		
; Now cycle one of the six colours on each WS2801 driven RGB LED in a sinusoidal (rising and falling) fashion 
 	FOR Index = 0 to 359 		
      	ptr = 0 
      	For RGBLEDNo = 0 to 5									; for each RGB LED in the string
      		Colour = Index // 6 + RGBLEDNo // 6						; determine which colour in which RGB LED
      		LOOKUP Colour, (Red,Yellow,Green,Cyan,Blue,Magenta), Memaddr	; fetch the appropriate colour
      		Angle = Colour * 30 + Index : Intensity = Sin Angle AND $7F : GOSUB FetchColour ; AND $7F to remove -ve sign
 	   	NEXT RGBLEDNo
 		GOSUB SendData
  		PAUSE ShortDelay
  	NEXT Index	
    LOOP ; repeat the entire sequence
;
; ***** Subroutine to fetch the data from EEPROM and save into Scratchpad for one RGB LED colour
  
  FetchColour:
	READ MemAddr, LED_Data
	@PtrInc = LED_Data * Intensity / 100
	INC  MemAddr
	READ MemAddr, LED_Data
	@PtrInc = LED_Data * Intensity / 100
	INC  MemAddr
	READ MemAddr, LED_Data
	@PtrInc = LED_Data * Intensity / 100
  	RETURN
  
  ;
  ; Subtoutine to serially clock out the data through/to a string of six SW2801 chips as two groups of three RGB LEDs	
  SendData:	
	Ptr = 0
  	SHIFTOUT SClock,SData,MSBFirst_L,(@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc)
  	SHIFTOUT SClock,SData,MSBFirst_L,(@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@PtrInc,@Ptr)
  	RETURN

EDIT:

attached a photo showing the six RGB LEDs as illuminated at the end of the intialisation phase with red, yellow, green, cyan, blue, magenta colours
 

Attachments

Last edited:
Very nice indeed! First time I've seen SIN used in picaxe code. Can't wait to start experimenting with these chips. I've noticed you can get 1M string of these with the LED's for about $30US.
41°C sounds nice right now. In Michigan, we're at 0°C right now. On second thought, 41C is pretty damn hot!!

Looking at your code it does give some appreciation for the amount of math involved in moving 1900x1280 RGB pixels at 30FPS as with our televisions.
 
My WS2801 Chips have arrived! Soldering these buggers was a challenge, but I got all five connected as well as the LED's. As it turns out, programming these chips could not be easier with the Shiftout command.
Westaust's code was very helpful and I was up and running in no time. For some reason, I am most amused by the chase sequence with alternating colors. So that's what I did.
http://www.youtube.com/watch?v=LsFFdkwtwnk

No problems with a 20x2 running at 32Mhz. I plan to program some additional color codes into EEPROM and make some more interesting effects.

Thanks again for the code samples Westaust!

-Brian
 

2gttalon

New Member
I am trying to use the attached code with 3 meters (94 LEDs, each with IC) of ws2801 strip and I can not seem to get it to turn on any LEDs past the 32 LED mark . I modified the line :

Symbol RAM_START = 256 - 57 ( changed 57 to accommodate 3 bytes for each LED. It works up to 32 LEDs (256-96) but nothing past that)

If anyone can offer any advice , I would greatly appreciate it.

Using 08m2 picaxe, 3 meters ws2801 strip and a 5v 1A transformer.
 

Attachments

westaust55

Moderator
From the first line in your code:
' Demo Code for PICAXE08M2 LED Chaser control of WS2801 LED strip
you are using an 08M2 which has 99 bytes of RAM available from Address 28 to 127 (ie $1C to 7F)


with your symbol statement:
Symbol RAM_START = 256 - 57 'Start of RAM Storage for 20 LED Data sets. 3 bytes per LED in order BGR
The first address is 256-57 = 99 limiting the usable RAM space to 127 - 99 = 28 bytes

then you have:
Symbol LED1 = RAM_START - 3 'start of data for 1st LED in pattern
and further on:
FIRST_LED = LED1 'First LED in strip
so the RAM address for the first LED is 99 - 3 = 96

For the last RAM location there are the lines:
Symbol LED_TOT = 20 'Number of LEDs in pattern
and further on:
LAST_LED = LED_TOT - 1 * 3 + FIRST_LED 'Last LED in strip
so the LAST defined RAM location becomes (20 - 1)*3 + 96 = 153 which is outside the 08M2 memory range.

Had you been using any other M2 part the above RAM upper limit would not have casued a concern as the other M2 parts have RAM to location 511.

127 (upper 08M2 RAM limit) - 96 (your starting address) = 31 so 0 to 31 ==> 32 LEDs

to use the 08M2 with 94 LEDs then the LED1 and thus First_LED values must be set for a lower RAM location:
127 = 94 = 33 so maybe start at RAm lcoation 32.

I have not looked into your entire code to see if there are other values or variables that might clash with a starting RAM locaiton of 32 or 33.
Seemingly you highest defined byte variable is b27 by the line
Symbol GET_COL = b26 ' Current LED status
so tentatively you can safely reduce the RAM first address location.
 
Last edited:

johnhr

New Member
Hi Westaust,

I started the post using a 40X2 chip, the AXE022 protoboard, and lighting 10 RGB LEDs using the WS2803 LED driver. I finally have all my parts and have read and reread your posts about you using the WS2801 and REB100s posts using the WS2803 and have some questions.

When you define Symbol SData and SClock, are the pins are the ones on the WS chip? Mine on the 2803 are pins 4 and 5, or do you mean the pins that send data to those pins from the 40X2 chip, mine being C.4 and C.3?

Since I'm lighting 6RGB LEDs, using 18 pins on the 2803, would my data set be 18? And what would my mods be = 6?

What would the delay be for 32MHz?

How else would your above program, post #15, be changed for the 40X2 and the WS2803? I also have a 24LC512 EEPROM chip onboard.

If I can get one 2803 lighting 6 LEDs I plan on adding 2 more 2803s to light 12 more.

I'm absolutely new at this so I need help.

Thanks
 

westaust55

Moderator
The PICAXE pin is defined by the symbol statements so SData is PICAXE pin C.2 and this is connected to the SDI (serial data in) pin on the WS280x chip.
Same situation for the clock signal.

For 1 chip, mods = 1
Each datasets comprises 18 bytes of data as one byte per LED output pin.
The number of datasets is equal to the number of steps in your lighting sequence.

Edit:
I though I had answered this question this morning and my answer had disappeared.
Now I realise that you have posted much the same question twice in different threads.!
http://www.picaxeforum.co.uk/showthread.php?23145-WS2803/page2
 
Last edited:

RonnS

Member
many Greetings from Germany, and many thanks to Mr. Westaust for sharing his good tutorial.Bright lightning lights and my soul is happy
i used it with an picaxe 401 and the RGB Power board from Phenoptix , my first experience with an 28x2

Ron
 

westaust55

Moderator
many Greetings from Germany, and many thanks to Mr. Westaust for sharing his good tutorial.Bright lightning lights and my soul is happy
i used it with an picaxe 401 and the RGB Power board from Phenoptix , my first experience with an 28x2

Ron
@Ron,

Welcome to the PICAXE forum.

Glad to be able to provide information that can help others.
Also great to read that your RBG LED project was completed successfully.
 
Top