diff --git a/examples/sandbox/sandbox.c b/examples/sandbox/sandbox.c
index 4aefb859c55d3d7a9825c2af16016ff3c9f412a0..338cb9f9368ad602d91dec69d3c20f82dabc72ad 100644
--- a/examples/sandbox/sandbox.c
+++ b/examples/sandbox/sandbox.c
@@ -5,6 +5,10 @@
 #include <stdio.h>
 #include <string.h>
 
+#define WS2812DMA_IMPLEMENTATION
+
+#include "ws2812b_dma_spi_led_driver.h"
+
 #define APB_CLOCK SYSTEM_CORE_CLOCK
 
 // Working on WS2812 driving.
@@ -61,9 +65,6 @@ void SystemInit(void)
 	USART1->CTLR1 |= CTLR1_UE_Set;
 }
 
-
-
-
 uint32_t EHSVtoHEX( uint8_t hue, uint8_t sat, uint8_t val )
 {
 	#define SIXTH1 43
@@ -135,6 +136,25 @@ uint32_t EHSVtoHEX( uint8_t hue, uint8_t sat, uint8_t val )
 	return or | (og<<8) | ((uint32_t)ob<<16);
 }
 
+
+const unsigned char huetable[] = {
+	0x00, 0x06, 0x0c, 0x12, 0x18, 0x1e, 0x24, 0x2a, 0x30, 0x36, 0x3c, 0x42, 0x48, 0x4e, 0x54, 0x5a, 
+	0x60, 0x66, 0x6c, 0x72, 0x78, 0x7e, 0x84, 0x8a, 0x90, 0x96, 0x9c, 0xa2, 0xa8, 0xae, 0xb4, 0xba, 
+	0xc0, 0xc6, 0xcc, 0xd2, 0xd8, 0xde, 0xe4, 0xea, 0xf0, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xf9, 0xf3, 0xed, 0xe7, 0xe1, 0xdb, 0xd5, 0xcf, 0xc9, 0xc3, 0xbd, 0xb7, 0xb1, 0xab, 0xa5, 
+	0x9f, 0x99, 0x93, 0x8d, 0x87, 0x81, 0x7b, 0x75, 0x6f, 0x69, 0x63, 0x5d, 0x57, 0x51, 0x4b, 0x45, 
+	0x3f, 0x39, 0x33, 0x2d, 0x27, 0x21, 0x1b, 0x15, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
+
 const unsigned char rands[] = {
 	0x67, 0xc6, 0x69, 0x73, 0x51, 0xff, 0x4a, 0xec, 0x29, 0xcd, 0xba, 0xab, 0xf2, 0xfb, 0xe3, 0x46, 
 	0x7c, 0xc2, 0x54, 0xf8, 0x1b, 0xe8, 0xe7, 0x8d, 0x76, 0x5a, 0x2e, 0x63, 0x33, 0x9f, 0xc9, 0x9a, 
@@ -153,146 +173,91 @@ const unsigned char rands[] = {
 	0xac, 0x86, 0x21, 0x2b, 0xaa, 0x1a, 0x55, 0xa2, 0xbe, 0x70, 0xb5, 0x73, 0x3b, 0x04, 0x5c, 0xd3, 
 	0x36, 0x94, 0xb3, 0xaf, 0xe2, 0xf0, 0xe4, 0x9e, 0x4f, 0x32, 0x15, 0x49, 0xfd, 0x82, 0x4e, 0xa9, };
 
-
-#define NR_LEDS 90
-uint16_t bufferset[12+NR_LEDS*6+1];
-
-// Note first 2 LEDs of DMA Buffer are 0's as a "break"
-// Need one extra LED at end to leave line high. 
-#define DMALEDS 16
-#define DMA_BUFFER_LEN (16*6)
-
-void EncodeLED( uint16_t * ptr, uint32_t ledval24bit )
-{
-	// This encodes 4 bits of incoming signal into one uint16_t
-	const static uint16_t bitquartets[16] = {
-		0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110,
-		0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110,
-		0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110,
-		0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110, };
-	ptr[0] = bitquartets[(ledval24bit>>20)&0xf];
-	ptr[1] = bitquartets[(ledval24bit>>16)&0xf];
-	ptr[2] = bitquartets[(ledval24bit>>12)&0xf];
-	ptr[3] = bitquartets[(ledval24bit>>8)&0xf];
-	ptr[4] = bitquartets[(ledval24bit>>4)&0xf];
-	ptr[5] = bitquartets[(ledval24bit>>0)&0xf];
-} 
-
-void DMA1_Channel3_IRQHandler( void ) __attribute__((interrupt));
-void DMA1_Channel3_IRQHandler( void ) 
+const unsigned char sintable[] = {
+	0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x95, 0x99, 0x9c, 0x9f, 0xa2, 0xa5, 0xa8, 0xab, 0xad, 
+	0xb0, 0xb3, 0xb6, 0xb9, 0xbc, 0xbe, 0xc1, 0xc4, 0xc6, 0xc9, 0xcb, 0xce, 0xd0, 0xd3, 0xd5, 0xd7, 
+	0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xe9, 0xeb, 0xed, 0xee, 0xf0, 0xf1, 0xf3, 0xf4, 
+	0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfd, 0xfc, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 
+	0xf5, 0xf4, 0xf3, 0xf1, 0xf0, 0xee, 0xed, 0xeb, 0xe9, 0xe8, 0xe6, 0xe4, 0xe2, 0xe0, 0xde, 0xdc, 
+	0xda, 0xd7, 0xd5, 0xd3, 0xd0, 0xce, 0xcb, 0xc9, 0xc6, 0xc4, 0xc1, 0xbe, 0xbc, 0xb9, 0xb6, 0xb3, 
+	0xb0, 0xad, 0xab, 0xa8, 0xa5, 0xa2, 0x9f, 0x9c, 0x99, 0x95, 0x92, 0x8f, 0x8c, 0x89, 0x86, 0x83, 
+	0x80, 0x7d, 0x79, 0x76, 0x73, 0x70, 0x6d, 0x6a, 0x67, 0x64, 0x61, 0x5e, 0x5b, 0x58, 0x55, 0x52, 
+	0x4f, 0x4c, 0x49, 0x47, 0x44, 0x41, 0x3e, 0x3c, 0x39, 0x36, 0x34, 0x31, 0x2f, 0x2d, 0x2a, 0x28, 
+	0x26, 0x24, 0x21, 0x1f, 0x1d, 0x1b, 0x1a, 0x18, 0x16, 0x14, 0x13, 0x11, 0x10, 0x0e, 0x0d, 0x0b, 
+	0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x04, 0x03, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 
+	0x0a, 0x0b, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, 0x16, 0x18, 0x1a, 0x1b, 0x1d, 0x1f, 0x21, 0x24, 
+	0x26, 0x28, 0x2a, 0x2d, 0x2f, 0x31, 0x34, 0x36, 0x39, 0x3c, 0x3e, 0x41, 0x44, 0x47, 0x49, 0x4c, 
+	0x4f, 0x52, 0x55, 0x58, 0x5b, 0x5e, 0x61, 0x64, 0x67, 0x6a, 0x6d, 0x70, 0x73, 0x76, 0x79, 0x7d, };
+
+#define NR_LEDS 197
+
+uint16_t phases[NR_LEDS];
+int frameno;
+int tween = 0;
+
+uint32_t TweenHexColors( uint32_t hexa, uint32_t hexb, int tween )
 {
-	// Check DMA1->INTFR 
-	// Clear all possible flags.
-	GPIOD->BSHR = 1;	 // Turn on GPIOD0
-	DMA1->INTFCR = DMA1_IT_GL3;
-	GPIOD->BSHR = 1<<16; // Turn off GPIOD0
+	int32_t aamt = 255-tween;
+	int32_t bamt = tween;
+	int32_t hab = hexa & 0xff;
+	int32_t har = (hexa>>8) & 0xff;
+	int32_t hag = (hexa>>16) & 0xff;
+	int32_t hbb = hexb & 0xff;
+	int32_t hbr = (hexb>>8) & 0xff;
+	int32_t hbg = (hexb>>16) & 0xff;
+	int32_t b = (hab * aamt + hbb * bamt + 128) >> 8;
+	int32_t r = (har * aamt + hbr * bamt + 128) >> 8;
+	int32_t g = (hag * aamt + hbg * bamt + 128) >> 8;
+	return b | (r<<8) | (g<<16);
 }
 
-void ConfigSpeedyLED()
+
+// Callbacks that you must implement.
+uint32_t WS2812BLEDCallback( int ledno )
 {
-	// Enable DMA + Peripherals
-	RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
-	RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
-
-	// MOSI, Configure GPIO Pin
-	GPIOC->CFGLR &= ~(0xf<<(4*6));
-	GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
-
-	// Configure SPI 
-	SPI1->CTLR1 = 
-		SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b |
-		SPI_Mode_Master | SPI_Direction_1Line_Tx |
-		3<<3; // Dvisior
-
-	SPI1->CTLR2 = SPI_CTLR2_TXDMAEN;
-	SPI1->HSCR = 1;
-
-	SPI1->CTLR1 |= CTLR1_SPE_Set;
-
-	memset( bufferset, 0xaa, sizeof( bufferset ) );
-
-	//DMA1_Channel3 is for SPI1TX
-	DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR;
-	DMA1_Channel3->MADDR = (uint32_t)bufferset;
-	DMA1_Channel3->CNTR  = sizeof( bufferset )/2; // Number of unique copies.
-	DMA1_Channel3->CFGR  =
-		DMA_M2M_Disable |		 
-		DMA_Priority_VeryHigh |
-		DMA_MemoryDataSize_HalfWord |
-		DMA_PeripheralDataSize_HalfWord |
-		DMA_MemoryInc_Enable |
-		DMA_Mode_Normal | // OR DMA_Mode_Circular or DMA_Mode_Normal
-		DMA_DIR_PeripheralDST |
-		DMA_IT_TC | DMA_IT_HT; // Transmission Complete + Half Empty Interrupts. 
-
-//	NVIC_SetPriority( DMA1_Channel3_IRQn, 0<<4 ); // Regular priority.
-	NVIC_EnableIRQ( DMA1_Channel3_IRQn );
-	DMA1_Channel3->CFGR |= DMA_CFGR1_EN;
+	uint8_t index = (phases[ledno])>>8;
+	uint8_t rs = sintable[index]>>3;
+	uint32_t fire = huetable[(rs+190&0xff)] | (huetable[(rs+30&0xff)]<<8) | (huetable[(rs+0)]<<16);
+	uint32_t ice  = 0xff | ((rs)<<8) | (rs<<16);
+	return TweenHexColors( fire, ice, tween ); // Where "tween" is a value from 0 ... 255
 }
 
 int main()
 {
+	int k;
 
-	// Enable GPIOD.
+	// Enable GPIOD (for debugging)
 	RCC->APB2PCENR |= RCC_APB2Periph_GPIOD;
 	GPIOD->CFGLR &= ~(0xf<<(4*0));
 	GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*0);
 
-	ConfigSpeedyLED();
+	WS2812BDMAInit( );
 
 	printf( "CFG: %08x\n", SPI1->CTLR1 );
 
-	uint16_t phases[NR_LEDS];
+	frameno = 0;
+
+	for( k = 0; k < NR_LEDS; k++ ) phases[k] = k<<8;
 
-/*
-#define NR_LEDS 30
-uint16_t bufferset[4+30*6+1];
-*/
-	int frame = 0;
 
 	while(1)
 	{
-		int k;
-		Delay_Ms( 10 );
-		frame++;
-
-		// 50 us low pulse.
-		bufferset[0] = 0x00;
-		bufferset[1] = 0x00;
-		bufferset[2] = 0x00;
-		bufferset[3] = 0x00;
-		bufferset[4] = 0x00;
-		bufferset[5] = 0x00;
-		bufferset[6] = 0x00;
-		bufferset[7] = 0x00;
-		bufferset[8] = 0x00;
-		bufferset[9] = 0x00;
-		bufferset[10] = 0x00;
-		bufferset[11] = 0x00;
-
-		uint16_t * ept = bufferset + 12;
-
-		//Pre-compute 'whiteness'
+		while( !WS2812BLEDDone );
+		frameno++;
+		if( frameno < 1024 ) tween = 0;
+		else if( frameno < (1024+256) ) tween = frameno - 1024;
+		else if( frameno < 2048 ) tween = 255;
+		else if( frameno < 2048+256 ) tween = 255-(frameno - 2048);
+		else frameno = 0;
+
 		for( k = 0; k < NR_LEDS; k++ )
 		{
-			int phase = phases[k] += (((rands[k&0xff])+0xf)<<2) + (((rands[k&0xff])+0xf)<<1);
-
-			EncodeLED( ept, k );
-			ept += 6;
-/*			uint8_t rs = ST(index)>>3;
-			SEND_WS( HUE(rs ) );
-			index = (buffer1[l])>>8;
-			SEND_WS( HUE(rs + 30) );
-			SEND_WS( HUE(rs + 190) );
-
-			SEND_WS( HUE(rs ) );
-			SEND_WS( HUE(rs + 30) );
-			l++;
-			SEND_WS( HUE(rs + 190) );*/
+			phases[k] += ((((rands[k&0xff])+0xf)<<2) + (((rands[k&0xff])+0xf)<<1))>>1;
 		}
-		ept[0] = 0;//0xffff;
 
-		DMA1_Channel3->CNTR  = sizeof( bufferset )/2; // Number of unique copies.
+		WS2812BDMAStart( NR_LEDS );
 	}
 }
 
diff --git a/examples/ws2812demo/Makefile b/examples/ws2812demo/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..816641bef4916ed5ac99f0b17a7a0f60e57bc614
--- /dev/null
+++ b/examples/ws2812demo/Makefile
@@ -0,0 +1,42 @@
+TARGET:=ws2812bdemo
+
+all : flash
+
+PREFIX:=riscv64-unknown-elf
+
+GPIO_Toggle:=EXAM/GPIO/GPIO_Toggle/User
+
+EVT:=../../ch32v003evt
+MINICHLINK:=../../minichlink
+
+CFLAGS:= \
+	-g -Os -flto -ffunction-sections \
+	-static-libgcc -lgcc \
+	-march=rv32ec \
+	-mabi=ilp32e \
+	-I/usr/include/newlib \
+	-I$(EVT) \
+	-nostdlib \
+	-I.
+
+LDFLAGS:=-T $(EVT)/ch32v003.ld -Wl,--gc-sections
+
+SYSTEM_C:=$(EVT)/startup_ch32v003.c $(EVT)/embedlibc.c
+
+$(TARGET).elf : $(SYSTEM_C) $(TARGET).c
+	$(PREFIX)-gcc -o $@ $^ $(CFLAGS) $(LDFLAGS)
+
+$(TARGET).bin : $(TARGET).elf
+	$(PREFIX)-size $^
+	$(PREFIX)-objdump -S $^ > $(TARGET).lst
+	$(PREFIX)-objdump -t $^ > $(TARGET).map
+	$(PREFIX)-objcopy -O binary $< $(TARGET).bin
+	$(PREFIX)-objcopy -O ihex $< $(TARGET).hex
+
+flash : $(TARGET).bin
+	make -C $(MINICHLINK) all
+	$(MINICHLINK)/minichlink -w $< -r
+
+clean :
+	rm -rf $(TARGET).elf $(TARGET).bin $(TARGET).hex $(TARGET).lst $(TARGET).map $(TARGET).hex
+
diff --git a/examples/ws2812demo/README.md b/examples/ws2812demo/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6894ecdaee82b73a9f3f52c57079f2d32f43e530
--- /dev/null
+++ b/examples/ws2812demo/README.md
@@ -0,0 +1,17 @@
+# WS2812B SPI DMA example
+
+This example uses SPI-DMA to output WS2812B LEDs.  By chunking the outputs using the center-interrupt, it is possible to double-buffer the WS2812B output data while only storing a few LEDs worth of data in memory at once.
+
+This outputs the LED data on the MOSI (PC6) pin of the CH32V003.
+
+Additionally, this demo only uses 6% CPU while it's outputting LEDs and free while not and it doesn't require precise interrupt timing, increasing or decreasing `DMALEDS` will adjust how lineant the timing is on LED catpures.
+
+The timing on the SPI bus is not terribly variable, the best I was able to find was:
+
+Ton0 = 324ns
+Ton1 = 990ns
+Toff0 = 990ns
+Toff1 = 324ns
+Treset = 68us
+
+
diff --git a/examples/ws2812demo/color_utilities.h b/examples/ws2812demo/color_utilities.h
new file mode 100644
index 0000000000000000000000000000000000000000..3a9d20095c1a2ea8435b5cd19a95c8e949d1f569
--- /dev/null
+++ b/examples/ws2812demo/color_utilities.h
@@ -0,0 +1,154 @@
+/*
+	Color utility functions for embedded systems
+
+	Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
+*/
+
+#ifndef _COLOR_UTILITIES_H
+#define _COLOR_UTILITIES_H
+
+
+
+static uint32_t EHSVtoHEX( uint8_t hue, uint8_t sat, uint8_t val )
+{
+	#define SIXTH1 43
+	#define SIXTH2 85
+	#define SIXTH3 128
+	#define SIXTH4 171
+	#define SIXTH5 213
+
+	uint16_t or = 0, og = 0, ob = 0;
+
+	hue -= SIXTH1; //Off by 60 degrees.
+
+	//TODO: There are colors that overlap here, consider 
+	//tweaking this to make the best use of the colorspace.
+
+	if( hue < SIXTH1 ) //Ok: Yellow->Red.
+	{
+		or = 255;
+		og = 255 - ((uint16_t)hue * 255) / (SIXTH1);
+	}
+	else if( hue < SIXTH2 ) //Ok: Red->Purple
+	{
+		or = 255;
+		ob = (uint16_t)hue*255 / SIXTH1 - 255;
+	}
+	else if( hue < SIXTH3 )  //Ok: Purple->Blue
+	{
+		ob = 255;
+		or = ((SIXTH3-hue) * 255) / (SIXTH1);
+	}
+	else if( hue < SIXTH4 ) //Ok: Blue->Cyan
+	{
+		ob = 255;
+		og = (hue - SIXTH3)*255 / SIXTH1;
+	}
+	else if( hue < SIXTH5 ) //Ok: Cyan->Green.
+	{
+		og = 255;
+		ob = ((SIXTH5-hue)*255) / SIXTH1;
+	}
+	else //Green->Yellow
+	{
+		og = 255;
+		or = (hue - SIXTH5) * 255 / SIXTH1;
+	}
+
+	uint16_t rv = val;
+	if( rv > 128 ) rv++;
+	uint16_t rs = sat;
+	if( rs > 128 ) rs++;
+
+	//or, og, ob range from 0...255 now.
+	//Need to apply saturation and value.
+
+	or = (or * val)>>8;
+	og = (og * val)>>8;
+	ob = (ob * val)>>8;
+
+	//OR..OB == 0..65025
+	or = or * rs + 255 * (256-rs);
+	og = og * rs + 255 * (256-rs);
+	ob = ob * rs + 255 * (256-rs);
+//printf( "__%d %d %d =-> %d\n", or, og, ob, rs );
+
+	or >>= 8;
+	og >>= 8;
+	ob >>= 8;
+
+	return or | (og<<8) | ((uint32_t)ob<<16);
+}
+
+static const unsigned char huetable[] = {
+	0x00, 0x06, 0x0c, 0x12, 0x18, 0x1e, 0x24, 0x2a, 0x30, 0x36, 0x3c, 0x42, 0x48, 0x4e, 0x54, 0x5a, 
+	0x60, 0x66, 0x6c, 0x72, 0x78, 0x7e, 0x84, 0x8a, 0x90, 0x96, 0x9c, 0xa2, 0xa8, 0xae, 0xb4, 0xba, 
+	0xc0, 0xc6, 0xcc, 0xd2, 0xd8, 0xde, 0xe4, 0xea, 0xf0, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xff, 0xf9, 0xf3, 0xed, 0xe7, 0xe1, 0xdb, 0xd5, 0xcf, 0xc9, 0xc3, 0xbd, 0xb7, 0xb1, 0xab, 0xa5, 
+	0x9f, 0x99, 0x93, 0x8d, 0x87, 0x81, 0x7b, 0x75, 0x6f, 0x69, 0x63, 0x5d, 0x57, 0x51, 0x4b, 0x45, 
+	0x3f, 0x39, 0x33, 0x2d, 0x27, 0x21, 0x1b, 0x15, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
+
+static const unsigned char rands[] = {
+	0x67, 0xc6, 0x69, 0x73, 0x51, 0xff, 0x4a, 0xec, 0x29, 0xcd, 0xba, 0xab, 0xf2, 0xfb, 0xe3, 0x46, 
+	0x7c, 0xc2, 0x54, 0xf8, 0x1b, 0xe8, 0xe7, 0x8d, 0x76, 0x5a, 0x2e, 0x63, 0x33, 0x9f, 0xc9, 0x9a, 
+	0x66, 0x32, 0x0d, 0xb7, 0x31, 0x58, 0xa3, 0x5a, 0x25, 0x5d, 0x05, 0x17, 0x58, 0xe9, 0x5e, 0xd4, 
+	0xab, 0xb2, 0xcd, 0xc6, 0x9b, 0xb4, 0x54, 0x11, 0x0e, 0x82, 0x74, 0x41, 0x21, 0x3d, 0xdc, 0x87, 
+	0x70, 0xe9, 0x3e, 0xa1, 0x41, 0xe1, 0xfc, 0x67, 0x3e, 0x01, 0x7e, 0x97, 0xea, 0xdc, 0x6b, 0x96, 
+	0x8f, 0x38, 0x5c, 0x2a, 0xec, 0xb0, 0x3b, 0xfb, 0x32, 0xaf, 0x3c, 0x54, 0xec, 0x18, 0xdb, 0x5c, 
+	0x02, 0x1a, 0xfe, 0x43, 0xfb, 0xfa, 0xaa, 0x3a, 0xfb, 0x29, 0xd1, 0xe6, 0x05, 0x3c, 0x7c, 0x94, 
+	0x75, 0xd8, 0xbe, 0x61, 0x89, 0xf9, 0x5c, 0xbb, 0xa8, 0x99, 0x0f, 0x95, 0xb1, 0xeb, 0xf1, 0xb3, 
+	0x05, 0xef, 0xf7, 0x00, 0xe9, 0xa1, 0x3a, 0xe5, 0xca, 0x0b, 0xcb, 0xd0, 0x48, 0x47, 0x64, 0xbd, 
+	0x1f, 0x23, 0x1e, 0xa8, 0x1c, 0x7b, 0x64, 0xc5, 0x14, 0x73, 0x5a, 0xc5, 0x5e, 0x4b, 0x79, 0x63, 
+	0x3b, 0x70, 0x64, 0x24, 0x11, 0x9e, 0x09, 0xdc, 0xaa, 0xd4, 0xac, 0xf2, 0x1b, 0x10, 0xaf, 0x3b, 
+	0x33, 0xcd, 0xe3, 0x50, 0x48, 0x47, 0x15, 0x5c, 0xbb, 0x6f, 0x22, 0x19, 0xba, 0x9b, 0x7d, 0xf5, 
+	0x0b, 0xe1, 0x1a, 0x1c, 0x7f, 0x23, 0xf8, 0x29, 0xf8, 0xa4, 0x1b, 0x13, 0xb5, 0xca, 0x4e, 0xe8, 
+	0x98, 0x32, 0x38, 0xe0, 0x79, 0x4d, 0x3d, 0x34, 0xbc, 0x5f, 0x4e, 0x77, 0xfa, 0xcb, 0x6c, 0x05, 
+	0xac, 0x86, 0x21, 0x2b, 0xaa, 0x1a, 0x55, 0xa2, 0xbe, 0x70, 0xb5, 0x73, 0x3b, 0x04, 0x5c, 0xd3, 
+	0x36, 0x94, 0xb3, 0xaf, 0xe2, 0xf0, 0xe4, 0x9e, 0x4f, 0x32, 0x15, 0x49, 0xfd, 0x82, 0x4e, 0xa9, };
+
+static const unsigned char sintable[] = {
+	0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x95, 0x99, 0x9c, 0x9f, 0xa2, 0xa5, 0xa8, 0xab, 0xad, 
+	0xb0, 0xb3, 0xb6, 0xb9, 0xbc, 0xbe, 0xc1, 0xc4, 0xc6, 0xc9, 0xcb, 0xce, 0xd0, 0xd3, 0xd5, 0xd7, 
+	0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xe9, 0xeb, 0xed, 0xee, 0xf0, 0xf1, 0xf3, 0xf4, 
+	0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 
+	0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfd, 0xfc, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 
+	0xf5, 0xf4, 0xf3, 0xf1, 0xf0, 0xee, 0xed, 0xeb, 0xe9, 0xe8, 0xe6, 0xe4, 0xe2, 0xe0, 0xde, 0xdc, 
+	0xda, 0xd7, 0xd5, 0xd3, 0xd0, 0xce, 0xcb, 0xc9, 0xc6, 0xc4, 0xc1, 0xbe, 0xbc, 0xb9, 0xb6, 0xb3, 
+	0xb0, 0xad, 0xab, 0xa8, 0xa5, 0xa2, 0x9f, 0x9c, 0x99, 0x95, 0x92, 0x8f, 0x8c, 0x89, 0x86, 0x83, 
+	0x80, 0x7d, 0x79, 0x76, 0x73, 0x70, 0x6d, 0x6a, 0x67, 0x64, 0x61, 0x5e, 0x5b, 0x58, 0x55, 0x52, 
+	0x4f, 0x4c, 0x49, 0x47, 0x44, 0x41, 0x3e, 0x3c, 0x39, 0x36, 0x34, 0x31, 0x2f, 0x2d, 0x2a, 0x28, 
+	0x26, 0x24, 0x21, 0x1f, 0x1d, 0x1b, 0x1a, 0x18, 0x16, 0x14, 0x13, 0x11, 0x10, 0x0e, 0x0d, 0x0b, 
+	0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x04, 0x03, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 
+	0x0a, 0x0b, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, 0x16, 0x18, 0x1a, 0x1b, 0x1d, 0x1f, 0x21, 0x24, 
+	0x26, 0x28, 0x2a, 0x2d, 0x2f, 0x31, 0x34, 0x36, 0x39, 0x3c, 0x3e, 0x41, 0x44, 0x47, 0x49, 0x4c, 
+	0x4f, 0x52, 0x55, 0x58, 0x5b, 0x5e, 0x61, 0x64, 0x67, 0x6a, 0x6d, 0x70, 0x73, 0x76, 0x79, 0x7d, };
+
+static uint32_t TweenHexColors( uint32_t hexa, uint32_t hexb, int tween )
+{
+	int32_t aamt = 255-tween;
+	int32_t bamt = tween;
+	int32_t hab = hexa & 0xff;
+	int32_t har = (hexa>>8) & 0xff;
+	int32_t hag = (hexa>>16) & 0xff;
+	int32_t hbb = hexb & 0xff;
+	int32_t hbr = (hexb>>8) & 0xff;
+	int32_t hbg = (hexb>>16) & 0xff;
+	int32_t b = (hab * aamt + hbb * bamt + 128) >> 8;
+	int32_t r = (har * aamt + hbr * bamt + 128) >> 8;
+	int32_t g = (hag * aamt + hbg * bamt + 128) >> 8;
+	return b | (r<<8) | (g<<16);
+}
+
+#endif
+
diff --git a/examples/ws2812demo/ws2812b_dma_spi_led_driver.h b/examples/ws2812demo/ws2812b_dma_spi_led_driver.h
new file mode 100644
index 0000000000000000000000000000000000000000..9972fee9a0e93fe8d0850d0219a8759a690a1322
--- /dev/null
+++ b/examples/ws2812demo/ws2812b_dma_spi_led_driver.h
@@ -0,0 +1,197 @@
+/* Single-File-Header for using asynchronous LEDs with the CH32V003 using DMA to the SPI port.
+   I may write another version of this to use DMA to timer ports, but, the SPI port can be used
+   to generate outputs very efficiently. So, for now, SPI Port.
+
+   Copyright 2023 <>< Charles Lohr, under the MIT-x11 or NewBSD License, you choose!
+
+   If you are including this in main, simply 
+	#define WS2812DMA_IMPLEMENTATION
+
+   You will need to implement the following two functions, as callbacks from the ISR.
+	uint32_t CallbackWS2812BLED( int ledno );
+
+   You willalso need to call
+	InitWS2812DMA();
+
+   Then, whenyou want to update the LEDs, call:
+	WS2812BStart( int num_leds );
+*/
+
+#ifndef _WS2812_LED_DRIVER_H
+#define _WS2812_LED_DRIVER_H
+
+#include <stdint.h>
+
+// Use DMA and SPI to stream out WS2812B LED Data via the MOSI pin.
+void WS2812BDMAInit( );
+void WS2812BDMAStart( int leds );
+
+// Callbacks that you must implement.
+uint32_t WS2812BLEDCallback( int ledno );
+
+extern volatile int WS2812BLEDDone;
+
+
+#ifdef WS2812DMA_IMPLEMENTATION
+
+// Note first 2 LEDs of DMA Buffer are 0's as a "break"
+// Need one extra LED at end to leave line high. 
+// This must be greater than WS2812B_RESET_PERIOD.
+//  1: Divisble by 2.
+//  2: 
+#define DMALEDS 16
+#define WS2812B_RESET_PERIOD 6
+#define DMA_BUFFER_LEN (((DMALEDS+1)/2)*6)
+
+static uint16_t WS2812dmabuff[DMA_BUFFER_LEN];
+static int WS2812LEDs;
+static int WS2812LEDPlace;
+volatile int WS2812BLEDDone;
+
+// This is the code that updates a portion of the WS2812dmabuff with new data.
+// This effectively creates the bitstream that outputs to the LEDs.
+static void WS2812FillBuffSec( uint16_t * ptr, int numhalfwords, int ending )
+{
+	const static uint16_t bitquartets[16] = {
+		0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110,
+		0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110,
+		0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110,
+		0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110, };
+
+	int i;
+	uint16_t * end = ptr + numhalfwords;
+	int ledcount = WS2812LEDs;
+	int place = WS2812LEDPlace;
+
+	while( place < 0 && ptr != end )
+	{
+		(*ptr++) = 0;
+		(*ptr++) = 0;
+		place++;
+	}
+
+	while( ptr != end )
+	{
+		if( place >= ledcount )
+		{
+			// Optionally, leave line high.
+			while( ptr != end )
+				(*ptr++) = 0;//0xffff;
+
+			// If we're "totally finished" we can set the flag.
+			if( place == ledcount+1 ) 
+				WS2812BLEDDone = 1;
+
+			// Only safe to do this when we're on the second leg.
+			if( ending )
+			{
+				if( place == ledcount )
+				{
+					// Take the DMA out of circular mode and let it expire.
+					DMA1_Channel3->CFGR &= ~DMA_Mode_Circular;
+				}
+				place++;
+			}
+
+
+			break;
+		}
+
+		uint32_t ledval24bit = WS2812BLEDCallback( place++ );
+		ptr[0] = bitquartets[(ledval24bit>>20)&0xf];
+		ptr[1] = bitquartets[(ledval24bit>>16)&0xf];
+		ptr[2] = bitquartets[(ledval24bit>>12)&0xf];
+		ptr[3] = bitquartets[(ledval24bit>>8)&0xf];
+		ptr[4] = bitquartets[(ledval24bit>>4)&0xf];
+		ptr[5] = bitquartets[(ledval24bit>>0)&0xf];
+		ptr += 6;
+		i += 6;
+	}
+	WS2812LEDPlace = place;
+}
+
+void DMA1_Channel3_IRQHandler( void ) __attribute__((interrupt));
+void DMA1_Channel3_IRQHandler( void ) 
+{
+	GPIOD->BSHR = 1;	 // Turn on GPIOD0
+
+	// Backup flags.
+	int intfr = DMA1->INTFR;
+
+	// Clear all possible flags.
+	DMA1->INTFCR = DMA1_IT_GL3;
+
+	if( intfr & DMA1_IT_HT3 )
+	{
+		// Complete (Fill in second part)
+		WS2812FillBuffSec( WS2812dmabuff + DMA_BUFFER_LEN / 2, DMA_BUFFER_LEN / 2, 1 );
+	}
+	if( intfr & DMA1_IT_TC3 )
+	{
+		// Halfwaay (Fill in first part)
+		WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN / 2, 0 );
+	}
+
+	GPIOD->BSHR = 1<<16; // Turn off GPIOD0
+}
+
+void WS2812BDMAStart( int leds )
+{
+	WS2812BLEDDone = 0;
+	WS2812LEDs = leds;
+	WS2812LEDPlace = -WS2812B_RESET_PERIOD;
+	WS2812FillBuffSec( WS2812dmabuff, DMA_BUFFER_LEN, 0 );
+	DMA1_Channel3->CFGR |= DMA_Mode_Circular;
+	DMA1_Channel3->CNTR = DMA_BUFFER_LEN; // Number of unique uint16_t entries.
+}
+
+void WS2812BDMAInit( )
+{
+	WS2812BLEDDone = 1;
+
+	// Enable DMA + Peripherals
+	RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
+	RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
+
+	// MOSI, Configure GPIO Pin
+	GPIOC->CFGLR &= ~(0xf<<(4*6));
+	GPIOC->CFGLR |= (GPIO_Speed_50MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
+
+	// Configure SPI 
+	SPI1->CTLR1 = 
+		SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b |
+		SPI_Mode_Master | SPI_Direction_1Line_Tx |
+		3<<3; // Dvisior
+
+	SPI1->CTLR2 = SPI_CTLR2_TXDMAEN;
+	SPI1->HSCR = 1;
+
+	SPI1->CTLR1 |= CTLR1_SPE_Set;
+
+	SPI1->DATAR = 0; // Set LEDs Low.
+
+	//memset( bufferset, 0xaa, sizeof( bufferset ) );
+
+	//DMA1_Channel3 is for SPI1TX
+	DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR;
+	DMA1_Channel3->MADDR = (uint32_t)WS2812dmabuff;
+	DMA1_Channel3->CNTR  = 0;// sizeof( bufferset )/2; // Number of unique copies.  (Don't start, yet!)
+	DMA1_Channel3->CFGR  =
+		DMA_M2M_Disable |		 
+		DMA_Priority_VeryHigh |
+		DMA_MemoryDataSize_HalfWord |
+		DMA_PeripheralDataSize_HalfWord |
+		DMA_MemoryInc_Enable |
+		DMA_Mode_Normal | // OR DMA_Mode_Circular or DMA_Mode_Normal
+		DMA_DIR_PeripheralDST |
+		DMA_IT_TC | DMA_IT_HT; // Transmission Complete + Half Empty Interrupts. 
+
+//	NVIC_SetPriority( DMA1_Channel3_IRQn, 0<<4 ); // Regular priority.
+	NVIC_EnableIRQ( DMA1_Channel3_IRQn );
+	DMA1_Channel3->CFGR |= DMA_CFGR1_EN;
+}
+
+#endif
+
+#endif
+
diff --git a/examples/ws2812demo/ws2812bdemo.c b/examples/ws2812demo/ws2812bdemo.c
new file mode 100644
index 0000000000000000000000000000000000000000..a74a420bde1a6aa5cab16e54e90c8869d96aff7b
--- /dev/null
+++ b/examples/ws2812demo/ws2812bdemo.c
@@ -0,0 +1,137 @@
+// Could be defined here, or in the processor defines.
+#define SYSTEM_CORE_CLOCK 48000000
+
+#include "ch32v00x.h"
+#include <stdio.h>
+#include <string.h>
+
+#define WS2812DMA_IMPLEMENTATION
+
+#include "ws2812b_dma_spi_led_driver.h"
+
+#define APB_CLOCK SYSTEM_CORE_CLOCK
+
+#include "color_utilities.h"
+
+// For debug writing to the UART.
+int _write(int fd, char *buf, int size)
+{
+    for(int i = 0; i < size; i++){
+        while( !(USART1->STATR & USART_FLAG_TC));
+        USART1->DATAR = *buf++;
+    }
+    return size;
+}
+
+
+void SystemInit(void)
+{
+	// Values lifted from the EVT.  There is little to no documentation on what this does.
+	RCC->CTLR |= (uint32_t)0x00000001;
+	RCC->CFGR0 &= (uint32_t)0xFCFF0000;
+	RCC->CTLR &= (uint32_t)0xFEF6FFFF;
+	RCC->CTLR &= (uint32_t)0xFFFBFFFF;
+	RCC->CFGR0 &= (uint32_t)0xFFFEFFFF;
+	RCC->INTR = 0x009F0000;
+
+	// From SetSysClockTo_48MHZ_HSI
+	// This is some dark stuff.  But, I copy-pasted it and it seems towork.
+	FLASH->ACTLR = (FLASH->ACTLR & ((uint32_t)~FLASH_ACTLR_LATENCY)) | FLASH_ACTLR_LATENCY_1; 	// Flash 0 wait state
+	RCC->CFGR0 = ( RCC->CFGR0 & ((uint32_t)~(RCC_PLLSRC)) ) | (uint32_t)(RCC_PLLSRC_HSI_Mul2); 	// PLL configuration: PLLCLK = HSI * 2 = 48 MHz
+	RCC->CTLR |= RCC_PLLON; 																	// Enable PLL
+	while((RCC->CTLR & RCC_PLLRDY) == 0);														// Wait till PLL is ready
+	RCC->CFGR0 = ( RCC->CFGR0 & ((uint32_t)~(RCC_SW))) | (uint32_t)RCC_SW_PLL;					// Select PLL as system clock source
+	while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08);									// Wait till PLL is used as system clock source
+
+	// Once clock is up and running, we can enable the UART for other debugging.
+
+	// Enable GPIOD and UART.
+	RCC->APB2PCENR |= RCC_APB2Periph_GPIOD | RCC_APB2Periph_USART1;
+
+	// Push-Pull, 10MHz Output, GPIO D5, with AutoFunction
+	GPIOD->CFGLR &= ~(0xf<<(4*5));
+	GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*5);
+	
+	// 115200, 8n1.  Note if you don't specify a mode, UART remains off even when UE_Set.
+	USART1->CTLR1 = USART_WordLength_8b | USART_Parity_No | USART_Mode_Tx;
+	USART1->CTLR2 = USART_StopBits_1;
+	USART1->CTLR3 = USART_HardwareFlowControl_None;
+
+	#define UART_BAUD_RATE 115200
+	#define OVER8DIV 4
+	#define INTEGER_DIVIDER (((25 * (APB_CLOCK)) / (OVER8DIV * (UART_BAUD_RATE))))
+	#define FRACTIONAL_DIVIDER ((INTEGER_DIVIDER)%100)
+	USART1->BRR = ((INTEGER_DIVIDER / 100) << 4) | ((((FRACTIONAL_DIVIDER * (OVER8DIV*2)) + 50)/100)&7);
+	USART1->CTLR1 |= CTLR1_UE_Set;
+}
+
+#define NR_LEDS 197
+
+uint16_t phases[NR_LEDS];
+int frameno;
+int tween = 0;
+int tweendir = 0;
+
+// Callbacks that you must implement.
+uint32_t WS2812BLEDCallback( int ledno )
+{
+	uint8_t index = (phases[ledno])>>8;
+	uint8_t rs = sintable[index]>>3;
+//	uint32_t fire = huetable[(rs+190&0xff)] | (huetable[(rs+30&0xff)]<<8) | (huetable[(rs+0)]<<16);
+	uint32_t ice  = 0xff | ((rs)<<8) | (rs<<16);
+	return ice;
+	//return TweenHexColors( fire, ice, tween ); // Where "tween" is a value from 0 ... 255
+}
+
+int main()
+{
+	int k;
+
+	// Enable GPIOD (for debugging)
+	RCC->APB2PCENR |= RCC_APB2Periph_GPIOD;
+	GPIOD->CFGLR &= ~(0xf<<(4*0));
+	GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*0);
+
+	WS2812BDMAInit( );
+
+	printf( "CFG: %08x\n", SPI1->CTLR1 );
+
+	frameno = 0;
+
+	for( k = 0; k < NR_LEDS; k++ ) phases[k] = k<<8;
+
+
+	while(1)
+	{
+		// Wait for LEDs to totally finish.
+		if( WS2812BLEDDone )
+		{
+			frameno++;
+
+			if( frameno == 1024 )
+			{
+				tweendir = 4;
+			}
+			if( frameno == 2048 )
+			{
+				tweendir = -4;
+				frameno = 0;
+			}
+
+			if( tweendir )
+			{
+				tween += tweendir;
+				if( tween > 255 ) tween = 255;
+				if( tween < 0 ) tween = 0;
+			}
+
+			for( k = 0; k < NR_LEDS; k++ )
+			{
+				phases[k] += ((((rands[k&0xff])+0xf)<<2) + (((rands[k&0xff])+0xf)<<1))>>1;
+			}
+
+			WS2812BDMAStart( NR_LEDS );
+		}
+	}
+}
+