Library for controlling a strip of Adafruit NeoPixels with WS2812 drivers. Because of the strict timing requirements of the self-clocking data signal, the critical parts of code are written in ARM assembly. Currently, only the NXP LPC1768 platform is supported. More information about NeoPixels can be found at http://learn.adafruit.com/adafruit-neopixel-uberguide/overview

Dependents:   NeoPixels ECE4180_Werable_LCD_DEMO neopixel_spi NeoPixels ... more

Files at this revision

API Documentation at this revision

Comitter:
aswild
Date:
Wed Mar 12 18:36:58 2014 +0000
Child:
1:f531a2be180d
Commit message:
Initial version

Changed in this revision

NeoCore.s Show annotated file Show diff for this revision Revisions of this file
NeoStrip.cpp Show annotated file Show diff for this revision Revisions of this file
NeoStrip.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NeoCore.s	Wed Mar 12 18:36:58 2014 +0000
@@ -0,0 +1,218 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; NeoCore.s
+; 
+; Allen Wild
+; March 2014
+;
+; ARM assembly functions for writing to Adafruit NeoPixels
+; with the mbed NXP LPC1768
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+	AREA neo_core, CODE, READONLY
+	
+	IMPORT neo_fio_reg
+	IMPORT neo_bitmask
+	
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+neo_write_pin
+; Set the GPIO pin to the value passed in R0
+; Registers and bitmasks are stored in variables set by the C++ library
+	LDR		R1, =neo_fio_reg	; load pointers to register values
+	LDR		R2, =neo_bitmask
+	LDR		R1, [R1]			; load actual values from memory
+	LDR		R2, [R2]
+
+	CMP		R0, #0			; VALUE == 0 ?
+	ITE EQ					; (IF-THEN-ELSE) ON NEXT TWO INSTRUCTIONS USING "EQ" FLAG
+	STREQ	R2, [R1,#0x1C]	; if==0, CLEAR BIT
+	STRNE	R2, [R1,#0x18]	; if==1, SET BIT
+	BX		LR
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+neo_zero
+; Output a NeoPixel zero, composed of a short
+; HIGH pulse and a long LOW pulse
+	PUSH	{LR}
+	MOV		R0, #1
+	BL		neo_write_pin	; set pin high
+	
+	MOV		R0, #10			; delay for long enough
+	BL		neo_delay
+	
+	MOV		R0, #0			; set pin low
+	BL		neo_write_pin
+	
+	MOV		R0, #20			; delay
+	BL		neo_delay
+	
+	POP		{LR}
+	BX		LR
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+neo_one
+; Output a NeoPixel one, composed of a long
+; HIGH pulse and a short LOW pulse
+	PUSH	{LR}
+	MOV		R0, #1
+	BL		neo_write_pin
+	
+	MOV		R0, #86
+	BL		neo_delay
+	
+	MOV		R0, #0
+	BL		neo_write_pin
+	
+	NOP		; really short delay
+	NOP
+	NOP
+	
+	POP		{LR}
+	BX		LR
+	
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+	EXPORT neo_out ; void neo_out(int *data, int n);
+; Main function called from the C++ library
+; R0 contains a pointer to the array of color data to send
+; R1 contains the number of bytes of data to send
+neo_out
+	PUSH	{LR, R4, R5, R6, R7, R8}
+	MOV		R7, R1		; move length to R7
+	MOV		R6, R0		; move address to R6
+	
+neo_byteloop
+	LDRB	R5, [R6]	; load byte to send
+	MOV		R4, #0x80	; load initial bitmask
+	
+neo_bitloop
+	AND		R3, R5, R4	; mask current byte
+	CMP		R3, #0
+	BLEQ	neo_zero	; send current bit
+	BLNE	neo_one
+	
+	LSR		R4, R4, #1	; shift bitmask right one
+	CMP		R4, #0		; if still more bits, loop back
+	BNE		neo_bitloop
+	
+	ADD		R6, R6, #1	; increment address
+	SUB		R7, R7, #1	; decrement count
+	CMP		R7, #0
+	BNE		neo_byteloop	; continue if not done
+
+	MOV		R0, #0
+	BL		neo_write_pin
+	POP		{R8, R7, R6, R5, R4, LR}
+	BX		LR
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ 
+neo_delay
+; delay the specified number of cycles in R0 with a bunch of nops
+	LDR		R2, =neo_delay_end
+	SUB		R2, R2, R0
+	BX		R2
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+	NOP
+neo_delay_end
+	BX	 LR
+
+	END ; end code region
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NeoStrip.cpp	Wed Mar 12 18:36:58 2014 +0000
@@ -0,0 +1,93 @@
+/**********************************************
+ * NeoStrip.cpp
+ *
+ * Allen Wild
+ * March 2014
+ *
+ * Controls a strip of Adafruit NeoPixels, addressable RGB LEDs
+ * Currently, because of the global nature of the IO register and bitmask variables,
+ * it is only possible to use one NeoStrip instance at a time.
+ *
+ * This library supports only the NXP LPC1768!
+ */
+
+#include "mbed.h"
+#include "NeoStrip.h"
+
+// function to write to the strip, implemented in ARM assembly
+extern "C" void neo_out(NeoColor*, int);
+
+// FastIO register address and bitmask for the GPIO pin
+// because these are imported in the assembly
+uint32_t neo_fio_reg;
+uint32_t neo_bitmask;
+
+NeoStrip::NeoStrip(PinName pin, int N) : N(N)
+{
+	bright = 0.5;
+	Nbytes = N * 3;
+	strip = (NeoColor*)malloc(N * sizeof(NeoColor));
+	if (strip == NULL)
+	{
+		printf("NeoStrip: ERROR unable to malloc strip data");
+		N = 0;
+	}
+	
+	gpio_init(&gpio, pin, PIN_OUTPUT);		// initialize GPIO registers
+	neo_fio_reg = (uint32_t)gpio.reg_dir;	// set registers and bitmask for
+	neo_bitmask = 1 << ((int)pin & 0x1F);	// the assembly to use
+}
+
+void NeoStrip::setBrightness(float bright)
+{
+	this->bright = bright;
+}
+
+void NeoStrip::setPixel(int p, int color)
+{
+	int red = (color & 0xFF0000) >> 16;
+	int green = (color & 0x00FF00) >> 8;
+	int blue = (color & 0x0000FF);
+	setPixel(p, red, green, blue);
+}
+
+void NeoStrip::setPixel(int p, uint8_t red, uint8_t green, uint8_t blue)
+{
+	// set the given pixel's RGB values
+	// the array is indexed modulo N to avoid overflow
+	strip[p % N].red = (uint8_t)(red * bright);
+	strip[p % N].green = (uint8_t)(green * bright);
+	strip[p % N].blue = (uint8_t)(blue * bright);
+}
+
+void NeoStrip::setPixels(int p, int n, const int *colors)
+{
+	int r, g, b;
+	for (int i = 0; i < n; i++)
+	{
+		r = (colors[i] & 0xFF0000) >> 16;
+		g = (colors[i] & 0x00FF00) >>8;
+		b = colors[i] & 0x0000FF;
+		setPixel(p+i, r, g, b);
+	}
+}
+
+void NeoStrip::clear()
+{
+	for (int i = 0; i < N; i++)
+	{
+		strip[i].red = 0;
+		strip[i].green = 0;
+		strip[i].blue = 0;
+	}
+}
+
+void NeoStrip::write()
+{
+	__disable_irq();		// disable interrupts
+	neo_out(strip, Nbytes);	// output to the strip
+	__enable_irq();			// enable interrupts
+	wait_us(50);			// wait 50us for the reset pulse
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NeoStrip.h	Wed Mar 12 18:36:58 2014 +0000
@@ -0,0 +1,107 @@
+/**
+ * NeoStrip.h
+ *
+ * Allen Wild
+ * March 2014
+ *
+ * Library for the control of Adafruit NeoPixel addressable RGB LEDs.
+ */
+
+
+#ifndef NEOSTRIP_H
+#define NEOSTRIP_H
+
+#ifndef TARGET_LPC1768
+#error NeoStrip only supports the NXP LPC1768!
+#endif
+
+// NeoColor struct definition to hold 24 bit
+// color data for each pixel, in GRB order
+typedef struct _NeoColor
+{
+	uint8_t green;
+	uint8_t red;
+	uint8_t blue;
+} NeoColor;
+
+/**
+ * NeoStrip objects manage the buffering and assigning of
+ * addressable NeoPixels
+ */
+class NeoStrip
+{
+	public:
+
+		/**
+		 * Create a NeoStrip object
+		 *
+		 * @param pin The mbed data pin name
+		 * @param N The number of pixels in the strip
+		 */
+		NeoStrip(PinName pin, int N);
+
+		/**
+		 * Set an overall brightness scale for the entire strip.
+		 * When colors are set using setPixel(), they are scaled
+		 * according to this brightness.
+		 *
+		 * Because NeoPixels are very bright and draw a lot of current,
+		 * the brightness is set to 0.5 by default.
+		 *
+		 * @param bright The brightness scale between 0 and 1.0
+		 */
+		void setBrightness(float bright);
+
+		/**
+		 * Set a single pixel to the specified color.
+		 *
+		 * This method (and all other setPixel methods) uses modulo-N arithmetic
+		 * when addressing pixels. If p >= N, the pixel address will wrap around.
+		 *
+		 * @param p The pixel number (starting at 0) to set
+		 * @param color A 24-bit color packed into a single int,
+		 * using standard hex color codes (e.g. 0xFF0000 is red)
+		 */
+		void setPixel(int p, int color);
+
+		/**
+		 * Set a single pixel to the specified color, with red, green, and blue
+		 * values in separate arguments.
+		 */
+		void setPixel(int p, uint8_t red, uint8_t green, uint8_t blue);
+
+		/**
+		 * Set n pixels starting at pixel p.
+		 *
+		 * @param p The first pixel in the strip to set.
+		 * @param n The number of pixels to set.
+		 * @param colors An array of length n containing the 24-bit colors for each pixel
+		 */
+		void setPixels(int p, int n, const int *colors);
+
+		/**
+		 * Reset all pixels in the strip to be of (0x000000)
+		 */
+		void clear();
+
+		/**
+		 * Write the colors out to the strip; this method must be called
+		 * to see any hardware effect.
+		 *
+		 * This function disables interrupts while the strip data is being sent,
+		 * each pixel takes approximately 30us to send, plus a 50us reset pulse
+		 * at the end.
+		 */
+		void write();
+
+	protected:
+		NeoColor *strip;	// pixel data buffer modified by setPixel() and used by neo_out()
+		int N;				// the number of pixels in the strip
+		int Nbytes;			// the number of bytes of pixel data (always N*3)
+		float bright;		// the master strip brightness
+		gpio_t gpio;		// gpio struct for initialization and getting register addresses
+};
+
+#endif
+
+