NOTICE: This website will be shut down in the near future. Product content has moved to nxp.com. Forum content and FAQs have been moved to community.nxp.com. We encourage you to create a user account on nxp.com to use the new community forums and access NXP microcontroller content. We greatly appreciate your contributions and look forward to seeing you at our new web location.

 

Controlling WS2812 LED Strips with the LPC810

22 replies [最新文章]
cpldcpu
离线
Joined: 2013-06-23
文章: 55

I ported my light weight WS2812 to the LPC810. The WS2812 is an RGB LED with an integrated controller that uses a 800kHz serial NRZ protocol to transmit 24 bit RGB data. Due to the nature of the protocol, it is quite incompatible to what most SPI units support.

I implemented a bitbanging approach with active CPU waiting. This requires predictable code execution timing. Luckily the LPC810 supports zero waitstate code memory access up to 30 Mhz. One advantage of the LPC810 is the relatively large SRAM compared to the code memory. 1024 bytes of sram allow controlling a full strip. A full 4m strip contains 240 LEDS and requires 3*240=720 bytes of memory. Most of the small 8 bit controllers only have 512 bytes or less.

You can see my code in action here: http://www.youtube.com/watch?v=Uwxt7SuSV7Y
Current state of the library: https://github.com/cpldcpu/light_ws2812/tree/master/light_ws2812_ARM

I have been considering to use the SCT to get rid of the reliance on code exection timing. Unfortunately it seems that this will still not free up CPU timing, as the interrupt overhead would not allow 800kHz clocking. Maybe it is possible to use internal pin forwarding to combine SPI and SCT to implement this protocol?

预览附件大小
LPC810_ws2812.jpg47.5 KB
5
您的评定: 平均: 5 (2 votes)

评论查看选项

选择你喜欢的显示评论的模式,并点选“储存设置”,以启用你所做的变更。
rickta59
离线
Joined: 2013-01-11
文章: 24

Great stuff, thanks for sharing!

I'm also impressed with the single cycle I/O on these chips. I've liked everything about them so far.

It is possible to bend SPI to your will. I've done an SPI implementation for the LPC1114FN28 using C++ templates https://github.com/RickKimball/fabooh/blob/master/include/cortex-m0/core/drivers/ws2811.h
I'll look at doing an LPC810 version soon.

cpldcpu
离线
Joined: 2013-06-23
文章: 55

Nice, thank you for the SPI implementation. I believe a similar approach could be used with the state configurable timer (SCT) as well, where it is made to output a one or zero depending on the value of one input bit.

However, both of these approaches share one disadvantage: They are still reliant on active CPU waiting, meaning that the CPU usage is the same as for pure bitbanging.

One approach I have been considering is to chain SPI and SCT to free up the CPU. The SPI would output the serial bitstream to an external pin, that is otherwise unconnected. The SCT would be configured to use this pin as input and output a the sequence for '1' or '0' if the input is high or low. I attached a picture to illustrate this further.

预览附件大小
ws2812-hardware-only.gif5.14 KB
rickta59
离线
Joined: 2013-01-11
文章: 24

Using the SCT sounds like a great idea. I went off and started playing with the Red State Machine Tool inside of Code Red. I was easily able to make it generate the shortest wave form with great accuracy. However, it seems like the SCT with an lpc810 is limited to only 2 states ( the larger chips can have up to 32 states). Have you spent any more time on this idea?

-rick

cpldcpu
离线
Joined: 2013-06-23
文章: 55

I have to admit the I did not get very far when trying to implement it. I have been a bit put off by the confusing documentation of the SCT and the red state editor.

However there is an example that changes duty cycle of the output depending on the state of an input pin ("LPC812_SCT_um_pwm"). This is already close to what needs to be done and suggests that it should be indeed possible to use the SCT that way.

Purpose:
SCT program that implements a PWM with two different duty cycles.
CTIN_0 selects between these two states.
CTIN_0 = 1: Green LED flashes with large duty cycle
CTIN_0 = 0: Red LED flashes with small duty cycle.

Running mode:
* Compile, Flash the program and reset.
* Default project target set to Blinky_Release (executing from flash)

Note:
Tested on LPC800 LPCXpresso Board
LPC800 running at 24 MHz

Input:
PIO0_1 configured as CTIN_0 (available on UART connector)

Output:
PIO0_17 configured as CTOUT_0, Green LED
PIO0_7 configured as CTOUT_1, Red LED

gertk
离线
Joined: 2013-07-14
文章: 15

You can use the SPI to generate (almost) arbitrary length bitstreams, I have used this to generate video in my Pong project. You still need to busy wait for the SPI transfer to finish but output is at a fixed rate (my SPI output runs at 5 MHz)

LPChobbyist
离线
Joined: 2013-08-06
文章: 5

Assuming a bit modified WS2812 0/1 code timing (as in making 0 and 1 code last the same time), one can have the SPI and SCT working together to generate the right content.

The SPI should be set to operate as a 16-bit master (CPHA=1, CPOL=1, MISO data ignored) and its SCK and MOSI lines need to be connected to SCT’s inputs CTIN0 and CTIN1. SCT’s CTOUT0 will provide WS2812 readable content.

Here is my SCT configuration:

A falling edge on CTIN0 (SPI’s SCK) is a limiting event; on this event CTOU0 goes high. This event is enabled in all states.

One cycle later CTIN1 (MOSI) is sampled and if low the SCT switches to state 0 (i.e. code 0 has to be transmitted); if CTIN1 is high the SCT switches to state 1 (i.e. code 1 has to be transmitted). These two events are enabled in all states.

One match event controlling T0H is enabled in SCT’s state 0; one event controlling T1H is enabled in SCT’s state 1.

The remaining available event is a match event and is used to indicate that a RET code was sent (i.e. no SPI data was received for long enough that all LED modules have seen at least 50 microseconds of low input). This event stops the timer and is enabled in all states.

For a system running off the IRC T0H = 5 and T0L = 10 seem to be OK. This results with code 0 high/low state lasting 0.417/0.833 microseconds which is still within the WS2812 timing spec. Code 1 setup is T1H/T1L = 8/7 resulting in low/high states of 0.667 and 0.583 microseconds. All in all a single bit of information transmitted via the SPI+SCT combo takes 1.25 microseconds.

Once the SPI and SCT get interfaced and set up, the application “sees” the WS2812 modules as plain SPI peripherals. In a system running off the IRC’s 12 MHz it does not take more than 25% of CPU horsepower to service the SPI ISRs that feed data to the LEDs.

I have a string of 3 WS2812 modules connected to an 8-pin LPC810 (the mini-kit) and I vae attached some scope screenshots that illustrate the described SPI+SCI setup’s behavior.

rickta59
离线
Joined: 2013-01-11
文章: 24

That is great!

It seems you hand coded the SCT registers. Is the Red State tool capable of doing the same?

Thanks!
-rick

cpldcpu
离线
Joined: 2013-06-23
文章: 55

LPCHobbyist, great work! That is exactly what I hoped to implement. I like the idea of also forwarding SCK to the SCT. I planned to do this by software synchronization, but your approach is of course much more robust and also allows detection of the reset conditition.

I have to play a bit with the code to understand it more. The SCT is still a bit confusing to me.

rickta59
离线
Joined: 2013-01-11
文章: 24

Thanks! just what I was trying to do.

It looks like you hand coded up those register settings for the SCT. Do you think it would
be possible to replicate this using the Red State tool or is this too complex for the tool?

LPChobbyist
离线
Joined: 2013-08-06
文章: 5

Hello Rick,

Thank you!

Yes, I did hand code the SCT registers in this case. I know of the Red State tool but have not used it so far. I will try it and will let you know how it goes.

LPChobbyist
离线
Joined: 2013-08-06
文章: 5

cpldcpu wrote:
LPCHobbyist, great work! That is exactly what I hoped to implement. I like the idea of also forwarding SCK to the SCT. I planned to do this by software synchronization, but your approach is of course much more robust and also allows detection of the reset conditition.

I have to play a bit with the code to understand it more. The SCT is still a bit confusing to me.

Hello cpldcpu,

Thank you!

The SCT is a powerful peripheral on NXP’s micros and I used it on several projects. It takes a while to get used to it but once you become comfortable around it sky is the limit:-).

LPChobbyist
离线
Joined: 2013-08-06
文章: 5

Hi SCT guys,

Just realized I said “A falling edge on CTIN0...” in the description of the limiting event. This is not correct.

It is “A rising edge on CTIN0...”, as it was implemented in the demo (and mentioned in comments in main.c). For the selected SPI configuration (CPHA=1, CPOL=1) SCK’s rising edges are the sampling edges and this is when the MOSI data are guaranteed to be stable...

Here is a video showing my LPC810 SPI+SCT & WS2812 demo running. The rightmost LED is LED0, the central one is LED1 while the leftmost LED is LED2.

http://www.youtube.com/watch?v=uWiSp9bJei0

cpldcpu
离线
Joined: 2013-06-23
文章: 55

Hi LPChobbyist,

I played a bit around with your code. You developed this on an LPC812 board, right? There is some interference with the RS232 connection on the LPC810 mini-kit when using your pin assignments, since P0.04 is used for both the WS2812 data output and the RX connection. I fixed this by moving the data output to P0.02 and removing the two indicator outputs to save pins.

When moving around the pins used for the SPI/SCT connection I found something very interesting: It is also possible to use pins other than P0.00 to P0.05, which are available on the LPC810. In fact up to P0.17 can be successfully used to forward signals internally. P0.18 fails. This makes a lot of sense, since P0.17 is the highest GPIO pin on the LPC812. This finding is very useful, since it allows connecting peripheral devices internally without wasting output pins on the small pin count devices.

Is this undocumented feature something that can be used reliably? Or may it go away in future silicon revisions? Are the GPIO output drivers actually present on the die and are not bonded, or is the forwarding done in an energy saving way within the switch matrix? Can one of the NXP guys answer this?

This also begs the question, whether the LPC810 die also has 16kb flash and 4kb ram. Is the entire LPC800 series using the same die? This needs further poking around...

Please find attached my updated version of LPChobbyists code for the LPC810.

预览附件大小
main_LPC810.c11.93 KB
cpldcpu
离线
Joined: 2013-06-23
文章: 55

After consulting the manual a bit:

It is stated that the switch matrix is identical in all LPC800 devices. The GPIO output devices are apparently separate from the switch matrix and fixed per pin.
However, as shown in Figure 7 on page 16 of the datasheet, input and output of a pin are only connected after the output driver (which makes a lot of sense). So, that means that internal signals are also forwarded across GPIO drivers or is there an internal bypass? It would surprise me a bit if the LPC810 die had all the 18 GPIO output drivers as they are probably quite area intensive. But then again, the LPC810 is probably not the most optimized part of the family...

LPChobbyist
离线
Joined: 2013-08-06
文章: 5

Hi cpldcpu,

Since I have the LPC812 board and the LPC800-Mini-kit and I used both of them when developing the SPI+SCT WS2812 demo. I observed the same behavior regarding the pins not available on the 8-pin package as you have described here, however for the sake of illustrating the SPI+SCT interaction I decided to use the pins on the 8-pin package I could probe.

In general, my plan is to move all input-output functions (i.e. SCK/MOSI/SCT inputs) to the pins not bonded out on the physical (8-pin) package so that I could add more input/out functionality that actually needs interaction with the real world to the remaining few pins. I hope NXP keeps the existing switch matrix behavior in the future products because I like it a lot:-). One thing I hope also works is to connect multiple input functions to the same physical pin – i.e. I can configure one SCT input to track rising edges, another input to track falling edges and using both of them I can easily get pulse length.

As for how much of other resources (Flash, SRAM) is available on a particular die, my rule of the thumb is to trust the DS/UM. Whenever I would talk to NXP people about if there is more of something on the chip or not, they would underline that even if one gets lucky with a particular revision of the device and gets some bonus feature(s) present, it can easily be revoked/fixed/removed/trimmed in the next design cycle so that it would match the official spec. So far I played it safe and did not get surprised.

cpldcpu
离线
Joined: 2013-06-23
文章: 55

LPChobbyist wrote:

In general, my plan is to move all input-output functions (i.e. SCK/MOSI/SCT inputs) to the pins not bonded out on the physical (8-pin) package so that I could add more input/out functionality that actually needs interaction with the real world to the remaining few pins. I hope NXP keeps the existing switch matrix behavior in the future products because I like it a lot:-). One thing I hope also works is to connect multiple input functions to the same physical pin – i.e. I can configure one SCT input to track rising edges, another input to track falling edges and using both of them I can easily get pulse length.

Yes, that is a very elegant solution. It would helpful if NXP could comment on "feature". Connecting more than one input to a single pin is allowable per the user manual.

LPChobbyist wrote:

As for how much of other resources (Flash, SRAM) is available on a particular die, my rule of the thumb is to trust the DS/UM. Whenever I would talk to NXP people about if there is more of something on the chip or not, they would underline that even if one gets lucky with a particular revision of the device and gets some bonus feature(s) present, it can easily be revoked/fixed/removed/trimmed in the next design cycle so that it would match the official spec. So far I played it safe and did not get surprised.

Well, if you want your application to work, you should stick to the specification, that is obvious. Many MCU vendors use the same die across a range
of products and define the product only at test by fusing or different package options. I strongly suspect that the same is the case for the LPC800 series. However, even if additional memory is present in the LPC810, it may be disabled in a way that makes it impossible to reactivate without physically altering the device.

fjrg76
离线
Joined: 2012-07-23
文章: 207

Where did you buy the LPC800 chips? mouser.com and digi-key.com have no stock, so I cannot start any projects based in such a family, and the LPCXpresso board is not suitable for production purposes.

Any ideas?

rickta59
离线
Joined: 2013-01-11
文章: 24

Adafruit sells the lpc810 chip and a usb dongle as a kit. I really only wanted the chip. Unfortunately, that is the only place I've seen with any stock. Also, the chip they sent me is the revision that has the faulty comparator.

cpldcpu
离线
Joined: 2013-06-23
文章: 55

fjrg76 wrote:
Where did you buy the LPC800 chips? mouser.com and digi-key.com have no stock, so I cannot start any projects based in such a family, and the LPCXpresso board is not suitable for production purposes.

Any ideas?

I got mine as part of the mini-kit in NXPs giveaway. Apparently there are samples available at the official distributors, but they are not selling the device yet. It may be worth calling them...

Ricka: Which one is the version with the broken comparator? The price of Adafruits offering is a bit steep. The parts are hardly worth more than $5...

rickta59
离线
Joined: 2013-01-11
文章: 24

DIP 8 devices with rev. 2A

markr
离线
Joined: 2013-07-19
文章: 14

this posting sort of answers the question:

http://www.lpcware.com/content/forum/lpc810-question-about-connect-acmpo-sct-input#comment-1131496
From NPX_Paul:

Quote:
It is never a good idea to use a pin that does not exist in the device data sheet. Although it may work in some situations, there is no guarantee that it will continue to function correctly in future device revisions.

riscy00
离线
Joined: 2013-01-01
文章: 74

Hi

I pickup your code and make it work under LPCOpen style on actual LPC812 device. Using LPC812-MAX EVAL board. It working very nicely.

The P0.16 and P0.17 connect to LED port which is not optimal. I wish to move it P0.14 and P0.15 but no longer work. I checked datasheet and SCT and could find out why. I'm open for suggestion or reason to explain this. Below is the sample code, the top is for Pin 17/18 (WB2812B_GPIO_Setup) which worked and bottom is Pin 15/16 (WB2812B_GPIO_Setup_1415)

//==================================================================
//================================================================== WB2812B_GPIO_Setup
// Purpose	: Setup GPIO for this project.
// Input	:
// Output	:
// Note 	: Pin 7 shared with heartbeat for activity indicator, but green is too strong to see red.
//			: Pin 4 CTOUT_0 connect to LED string with DIN pin
//			: Pin 16 SCK0 connect to CTIN_0 internally.
//			: Pin 17 MOSI0 connect to CTIN_1 internally.
//==================================================================
void WB2812B_GPIO_Setup(void)
{
	Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SPI0);				//enable SPI0 clock
	Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SCT);					//enable SCT clock
	//--------------------------------------------Activate the SWM
	Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SWM);
	//--------------------------------------------LED Indicator
	Chip_GPIO_SetPinDIROutput(LPC_GPIO_PORT, 0, 7);
	//--------------------------------------------Routing SPI over P0.16/P.17 which are not external pins on LPC810
	Chip_SWM_MovablePinAssign(SWM_SPI0_SCK_IO, 16);	//	P0.16 = SCK0
	Chip_SWM_MovablePinAssign(SWM_SPI0_MOSI_IO,17);	//	P0.17 = MOSI0
	//--------------------------------------------Rounting CTIN0,CTIN1 and CTOUT
	Chip_SWM_MovablePinAssign(SWM_CTIN_0_I,16);		//	P0.16 = CTIN_0 connect to SCK0
	Chip_SWM_MovablePinAssign(SWM_CTIN_1_I,17);		//	P0.17 = CTIN_1 connect to MOSI0
	Chip_SWM_MovablePinAssign(SWM_CTOUT_0_O,4);		//	P0.04 = CTOUT_0  WS2812B data out to LED string.
	//--------------------------------------------Deactivate the SWM to save power.
	Chip_Clock_DisablePeriphClock(SYSCTL_CLOCK_SWM);
}

void WB2812B_GPIO_Setup_1415(void)
{
	Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SPI0);				//enable SPI0 clock
	Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SCT);					//enable SCT clock
	//--------------------------------------------Activate the SWM
	Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SWM);
	//--------------------------------------------LED Indicator
	Chip_GPIO_SetPinDIROutput(LPC_GPIO_PORT, 0, 7);
	//--------------------------------------------Routing SPI over P0.16/P.17 which are not external pins on LPC810
	Chip_SWM_MovablePinAssign(SWM_SPI0_SCK_IO, 14);	//	P0.14 = SCK0
	Chip_SWM_MovablePinAssign(SWM_SPI0_MOSI_IO,15);	//	P0.15 = MOSI0
	//--------------------------------------------Rounting CTIN0,CTIN1 and CTOUT
	Chip_SWM_MovablePinAssign(SWM_CTIN_0_I,14);		//	P0.14 = CTIN_0 connect to SCK0
	Chip_SWM_MovablePinAssign(SWM_CTIN_1_I,15);		//	P0.15 = CTIN_1 connect to MOSI0
	Chip_SWM_MovablePinAssign(SWM_CTOUT_0_O,4);		//	P0.04 = CTOUT_0  WS2812B data out to LED string.
	//--------------------------------------------Deactivate the SWM to save power.
	Chip_Clock_DisablePeriphClock(SYSCTL_CLOCK_SWM);
} 

feedback