============================================================================== WS2812 driver for ATtiny, ATmega and ATxmega 2013 by M. Marquardt (adrock0905@alice.de) ============================================================================== ============================================================================== ----- OVERVIEW ============================================================================== This code provides some subroutines to drive one or more WS2812 LEDs (RGB LEDs with built-in WS2811 controller). Because the timing of the output signal is different from the standard serial protocls (RS232, SPI) supported natively by the µC, it has to be generated through another technique. There are several ways to do so, with their advantages and disadvantages: 1. "bit banging": Toggle the port output with simple I/O instructions + No hardware resources needed beside an I/O pin - Because the timing of the output signal is done by carefully order the CPU instructions, it depends directly on the CPU frequency, therefore the code will only work for one specific frequency, if another frequence is used, the code needs to be changed - The CPU is 100% busy during output 2. FastPWM "manual": A timer and an output compare pin in FastPWM are used to generate the output signal + Even with different CPU frequence, the PWM timing can easily be changed to meet the requirements - A free timer with PWM must be available - During output also the CPU is 100% busy, because for each output bit the output compare register must be reloaded manually 3. FastPWM using DMA: A time and output compare pin in FastPWM are used to generate the output signal, values to output compare register are feeded by DMA + Independent of CPU frequency like (2) + During output the CPU is only used by about 30%, everything else is done by the DMA controller - Resources needed: 2 DMA channels (double buffering mode), 1 timer, 1 event channel 4. SPI using DMA: The output signal is generated by constucting bit patterns and put them out using the SPI + Independent of CPU frequency like (2) + During output the CPU is not 100% busy (depends on implementation) - Resources needed: 1-2 DMA channels (depends ond implementation) and USART This code implements some of these, depending of the type of controller used: ATtiny + ATmega: Method (2) is used ATxmega: Method (3) is used The implementation is done in AVR assembler, the code meets the standards for parameter handling with AVR GCC. But as it not relies on the C environment (ie. the heap), it can also be used from your assembler program, when you pay attention to the register usage (see the include file). ============================================================================== ----- SUPPORTED DEVICES ============================================================================== Tested on this AVRs: - ATtiny 45 / 16 MHz - ATmega 168 / 20 MHz - ATxmega 192A3 / 32 MHz0 Should work on: - ATtiny 45/85 - ATmega 48/88/168/328 - ATxmega xA3(U) The operation frequency needs to be at least 16 MHz. ============================================================================== ----- FILES ============================================================================== ws2812.h Public definitions for using the driver, here you can do some customization if required (ie. change the timing etc.). ws2812test.c Quick'n'dirty test program, doing some chasing light if you have some LEDs as strip ws2812_tinymega.s Implementation for ATtiny and ATmega ws2812_xmega.s Implementation for ATxmega asmdefs.h Used in the ASM source, implements some handy macros gammacorrection.h Some definitions for gamma correction lookup-table, used in the test program. ============================================================================== ----- HOW TO BUILD ============================================================================== If you use Atmel Studio 6, you simply can open the ws2812.atsln file with Atmel Studio 6 and build the project by the following steps: ============================================================================== IMPORTANT! DEFINE F_CPU in the project, NOT in your main program code! ============================================================================== To build the project with the small test program: 1. Open the project properties 2. Select tab "Toolchain" 3. Expand "AVR/GNU C Compiler" and click "Symbols" 4. Create a new symbol "F_CPU=UL", ie. "F_CPU=16000000UL" 5. Expand "AVR/GNU Assembler" and select "General" 6. On the "Assembler Flags" field add "-DF_CPU=