Actions

Difference between revisions of "Driving the WS2811 at 800 kHz with an 8 MHz AVR"

From Just in Time

(Attempt to correct syntax highlighting.)
 
(11 intermediate revisions by the same user not shown)
Line 1: Line 1:
This page describes how to drive a WS2811 from an 8Mhz or 9.6Mhz AVR like an Atmel ATmega88, ATtiny2313 or ATtiny13 '''without added components''' such as an external oscillator. With only 32 instructions, the driver code presented here is likely to be the [https://github.com/DannyHavenith/ws2811/blob/master/ws2811/ws2811_8.h#L49 shortest code] that delivers the exact timing (i.e. exactly 10 clock cycles for 1 byte, exactly 60 clock cycles for 6 bytes, etc.) and with even less code a "sparse driver" for 9.6Mhz MCUs can drive long led strings with only a few bytes of buffer in RAM.
+
This page describes how to drive a WS2811 from an 8Mhz or 9.6Mhz AVR like an Atmel ATmega88, ATtiny2313 or ATtiny13 '''without added components''' such as an external oscillator. With only 30 instructions for the driver loop (110 bytes for the complete function), the driver code presented here is likely to be the [https://github.com/DannyHavenith/ws2811/blob/master/ws2811/ws2811_8.h#L49 shortest code] that delivers the exact timing (i.e. exactly 10 clock cycles for 1 byte, exactly 60 clock cycles for 6 bytes, etc.). With even less code a "sparse driver" for 9.6Mhz MCUs can drive long led strings with only a few bytes of buffer in RAM.
  
And of course, if you're creating a hardware project that controls more than 1 LED, you're going to have to demonstrate it with a Knight Rider LED sequence (which, I just learned, is actually called a [https://en.wikipedia.org/wiki/Glen_A._Larson Larson] scanner)... The sources for all the demonstrations in these videos can be found on [https://github.com/DannyHavenith/ws2811 github].
+
Of course, if you're creating a hardware project that controls more than 1 LED, you're going to have to demonstrate it with a Knight Rider LED sequence (which, I just learned, is actually called a [https://en.wikipedia.org/wiki/Glen_A._Larson Larson] scanner)... The sources for all the demonstrations in these videos can be found on [https://github.com/DannyHavenith/ws2811 github].
 
{|
 
{|
 
|- valign="top"
 
|- valign="top"
|{{#ev:youtube|mP7vBw4UeME|300|left|Knight Rider on Steroids ([https://github.com/DannyHavenith/ws2811/blob/master/demo/chasers.hpp source code])}}
+
|colspan="3"|{{#ev:youtube|mP7vBw4UeME|400|left|Knight Rider on Steroids ([https://github.com/DannyHavenith/ws2811/blob/master/effects/chasers.hpp])}}
|{{#ev:youtube|_wkTtAk2V_k|300||"Water Torture" or "Lava Drops" demo ([https://github.com/DannyHavenith/ws2811/blob/master/demo/water_torture.hpp source code], [[WS2811 "Water torture"|details]])}}
+
|- valign="top"
 +
|{{#ev:youtube|MdX45a3OFS0|300||the [https://hackaday.io/project/9393-wheres-my-christmas-light/log/50423-the-most-simplest-is-the-most-easiest where's my christmas light] project}}
 +
|{{#ev:youtube|_wkTtAk2V_k|300||"Water Torture" or "Lava Drops" demo ([https://github.com/DannyHavenith/ws2811/blob/master/effects/water_torture.hpp source code], [[WS2811 "Water torture"|details]])}}
 
|{{#ev:youtube|jAm7nVRvY_I|300||[[Driving a large WS2811 LED string with an ATtiny13 and nothing else|Special sparse driver]] allows an attiny13 to drive arbitrarily large LED strings from 64 bytes of memory}}
 
|{{#ev:youtube|jAm7nVRvY_I|300||[[Driving a large WS2811 LED string with an ATtiny13 and nothing else|Special sparse driver]] allows an attiny13 to drive arbitrarily large LED strings from 64 bytes of memory}}
 
|- valign="top"
 
|- valign="top"
|{{#ev:youtube|mItPxAtkuVI|300||Flares demo on an attiny13 ([https://github.com/DannyHavenith/ws2811/blob/master/demo/flares.hpp source code])}}
+
|{{#ev:youtube|mItPxAtkuVI|300||Flares demo on an attiny13 ([https://github.com/DannyHavenith/ws2811/blob/master/effects/flares.hpp source code])}}
 
|{{#ev:youtube|VM84Q1vWSZE|300||Fireflies!}}
 
|{{#ev:youtube|VM84Q1vWSZE|300||Fireflies!}}
 
|{{#ev:youtube|otCWPGf6O6w|300||Fire without flies}}
 
|{{#ev:youtube|otCWPGf6O6w|300||Fire without flies}}
Line 24: Line 26:
 
You'll need the C++ compiler for this to work (turning ws2811.h into "pure C" is left as an exercise to the reader). I am told that this works just as good for an Arduino, but I haven't tested this myself. Remember that this code was written and optimized for 8Mhz and 9.6Mhz, it would run too fast on an 16Mhz Arduino. From the sources, you'll need files ''ws2811.h'', ''ws2811_8.h'', ''ws2811_96.h'' and ''rgb.h'', though you only include "ws2811.h". A simple example of how to use this code:
 
You'll need the C++ compiler for this to work (turning ws2811.h into "pure C" is left as an exercise to the reader). I am told that this works just as good for an Arduino, but I haven't tested this myself. Remember that this code was written and optimized for 8Mhz and 9.6Mhz, it would run too fast on an 16Mhz Arduino. From the sources, you'll need files ''ws2811.h'', ''ws2811_8.h'', ''ws2811_96.h'' and ''rgb.h'', though you only include "ws2811.h". A simple example of how to use this code:
  
<source lang='cpp'>
+
<syntaxhighlight lang="c++">
 
#include <avr/io.h> // for _BV()
 
#include <avr/io.h> // for _BV()
  
Line 55: Line 57:
 
   for(;;);
 
   for(;;);
 
}
 
}
</source>
+
</syntaxhighlight>
  
 
==History==
 
==History==
Line 119: Line 121:
 
The main point of this text is ''not'' that I can show 4 (four!) Larson scanners in one led strip. Actually there are two different points I ''am'' trying to make:
 
The main point of this text is ''not'' that I can show 4 (four!) Larson scanners in one led strip. Actually there are two different points I ''am'' trying to make:
  
First of all, it is possible to control WS2811 led strips from an AVR without external 16 Mhz oscillator and I want to tell the world.
+
First of all, it is possible to control WS2811 led strips from an AVR without external 16 Mhz oscillator with clock-tick-exact timing and I want to tell the world.
  
 
Secondly, during this exercise I discovered that this kind of extremely time-critical code can be solved with a number or techniques:
 
Secondly, during this exercise I discovered that this kind of extremely time-critical code can be solved with a number or techniques:

Latest revision as of 01:01, 14 November 2020

This page describes how to drive a WS2811 from an 8Mhz or 9.6Mhz AVR like an Atmel ATmega88, ATtiny2313 or ATtiny13 without added components such as an external oscillator. With only 30 instructions for the driver loop (110 bytes for the complete function), the driver code presented here is likely to be the shortest code that delivers the exact timing (i.e. exactly 10 clock cycles for 1 byte, exactly 60 clock cycles for 6 bytes, etc.). With even less code a "sparse driver" for 9.6Mhz MCUs can drive long led strings with only a few bytes of buffer in RAM.

Of course, if you're creating a hardware project that controls more than 1 LED, you're going to have to demonstrate it with a Knight Rider LED sequence (which, I just learned, is actually called a Larson scanner)... The sources for all the demonstrations in these videos can be found on github.

Knight Rider on Steroids ([1])
"Water Torture" or "Lava Drops" demo (source code, details)
Special sparse driver allows an attiny13 to drive arbitrarily large LED strings from 64 bytes of memory
Flares demo on an attiny13 (source code)
Fireflies!
Fire without flies

Download source code

The library is header-only. Using it is a matter of downloading the source code and including it in your AVR code. Example source code can be found here. The code comes as an avr-eclipse project consisting for a large part of C++ demonstration code and the main driver function in assembly, in files ws2811_8.h and ws2811_96.h (for the 9.6Mhz version).

I don't recommend trying to understand the assembly code by reading these sources. How the code functions is described below. Usage information is in the next section. The rest of this page describes the 8Mhz version. The 9.6Mhz code was added later, but is created in the same way.

New: If you'd like to see the assembly code in action, take a look at the