LPC810 ws2811 driver routine

For Adafruit customers who seek help with microcontrollers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
rick_kimball
 
Posts: 13
Joined: Thu Mar 11, 2010 7:05 pm

LPC810 ws2811 driver routine

Post by rick_kimball »

I picked up one of those lpc810 mini starter kits from the store. Not sure what I will use it for. However I was intrigued
by the idea of being able to use single cycle GPIO. I've found that driving those ws2811 led chips seems to tax most
chips ability to keep up. Below you can find the cycle counting ASM routine I came up with that seems to work.

I configured my lpc810 for single cycle flash access and set the CPU to 12MHz so I don't have to use an external
xtal. I'm powering 4 leds from a ws2811 strip using the 5 volt off the PL2303HX power and using the 3.3v to
power the LPC810. I used P0_2 as the output pin and connected that to the ws2811 DIN pin.

Here is the arm asm code:

Code: Select all

@--------------------------------------------------------------------------------
@ ws2811_routines.S - write pixel data to ws2811 leds
@--------------------------------------------------------------------------------
@
@ lpc810 cortex-m0+ ARM ASM routine for streaming pixels data @400k (low speed)
@
@ assumes interrupts are disabled when called
@ assumes 12MHz system clock, flash wait state set to 0
@ assumes P0_2 configured as OUTPUT connected to ws2811 DIN pin
@
@ Author: [email protected]
@   Date: 21-Jul-2013
@   Desc: this code is part of the fabooh framework
@
@
	.cpu cortex-m0plus
	.thumb
	.fpu softvfp
	.syntax unified

	.file	"ws2811_utils.S"

@--------------------------------------------------------------------------------
@ void ws2811_write(uint8_t *pixel_data, unsigned byte_cnt)
@
@ Desc: Stream Green Red Blue data to a ws2811 chip with timing based on
@       cycle counting. See ws2811 data sheet for timing details. NOPS
@       are used to fill the time between turning P0_2 on and off to
@       achieve precise timings.
@
@ Example:
@
@      // 3 color bytes for each ws2811 ic chip
@      // light up 4 ws2811 leds pixels
@      static const uint8_t pixel_data[] = {
@        0x00,0x3F,0x00, // red
@        0x3F,0x3F,0x3F, // white
@        0x00,0x00,0x3F, // blue
@        0x3F,0x00,0x00, // green
@      };
@
@      ws2811_write((uint8_t *)&pixel_data[0],12);
@      delay_usec(50);
@
@
	.text
	.align	1
	.global	ws2811_write
	.thumb_func
	.type	ws2811_write, %function

ws2811_write:
	push	{r4, r5, r6, lr}		@ save off registers we affect

	movs	r2, #0b100			@ led pin mask P0_2
	ldrb	r3, [r0, #0]			@ work byte from pixel_data[0]
	ldr	r4, =0xA0002200			@ &LPC_GPIO_PORT->SET0
	ldr	r5, =0xA0002280			@ &LPC_GPIO_PORT->CLR0
	movs	r6, #0x80			@ mask bit msb -> lsb

.L_loop:					@ loop through each pixel_data byte a bit at a time MSB->LSB
	str	r2, [r4, #0]			@ set P0_2 high - start of on cycle
	nop
	nop
	nop
	ands	r3, r3, r6			@ check if bit is high or low
	bne	.L_set1				@ if 1 then


.L_set0:					@--- Off bit is 500ns on / 2000ns off
	str	r2,[r5,#0]			@ set P0_2 low  - end of on duration, begin off cycle
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	b	.L2

.L_set1:					@--- On bit is 1200ns on /  1300ns off
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	str	r2,[r5,#0]			@ set P0_2 low - end of on duration, begin off cycle

.L2:
	nop
	nop
	nop
	nop
	ldrb	r3, [r0, #0]
	lsrs	r6, r6, #1
	beq	.L3_outer

.L3_inner:
	nop					@ one extra nop because we didn't branch
	nop
	nop
	nop
	b	.L_loop

.L3_outer:
	movs	r6, #0x80			@ start again at most significant bit of pixel
	adds	r0, #1				@ pixel_data++
	subs	r1, #1				@ cnt--
	bne	.L_loop

.L_done:
	pop	{r4, r5, r6, pc}		@ restore registers and return to caller

	.size	ws2811_write, .-ws2811_write
Enjoy
-rick

User avatar
adafruit_support_mike
 
Posts: 67485
Joined: Thu Feb 11, 2010 2:51 pm

Re: LPC810 ws2811 driver routine

Post by adafruit_support_mike »

Nicely done.. the ws28xx communication protocol is isn't the friendliest thing in the world.

I don't have one of the LPC dev boards on me, so I can't test the code to see how well it stands up to abuse, but making it work at all is impressive. Bravo!

User avatar
rick_kimball
 
Posts: 13
Joined: Thu Mar 11, 2010 7:05 pm

Re: LPC810 ws2811 driver routine

Post by rick_kimball »

Probably the right way to do this is to use the SCT or the SPI peripherals. I have an SPI implementation I did for the LPC1114. I need to learn about the SPI peripheral on this chip and see if I can use the same code.

Code for LPC1114 ws2811 driver using SPI:

https://github.com/RickKimball/fabooh/b ... s/ws2811.h

-rick

User avatar
rick_kimball
 
Posts: 13
Joined: Thu Mar 11, 2010 7:05 pm

Re: LPC810 ws2811 driver routine

Post by rick_kimball »

Here is the right way to do it:

http://www.lpcware.com/content/forum/co ... nt-1131398

That solution uses SPI to send the pixel data and pipes it into the SCT which reshapes the values into pulses.
Very slick!.


-rick

User avatar
adafruit_support_mike
 
Posts: 67485
Joined: Thu Feb 11, 2010 2:51 pm

Re: LPC810 ws2811 driver routine

Post by adafruit_support_mike »

That is neat. It involves hardware I'm not as familiar with at the moment (I'm still trying to master the various chips on the BBB.. did you know the microprocessor on that thing has two embedded-yet-independent microcontrollers?) but the SCT sounds like an interesting device.

Locked
Please be positive and constructive with your questions and comments.

Return to “Microcontrollers”