Skip to content

Commit ca484b4

Browse files
Add WS2812B library again, but this time without the .git folder in it
1 parent 40dd7c6 commit ca484b4

6 files changed

Lines changed: 737 additions & 0 deletions

File tree

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# WS2812B_STM32_Libmaple
2+
WS2812B (Neopixel) library for Arduino STM32 (Libmaple core)
3+
4+
Written by Roger Clark www.rogerclark.net, from first principals
5+
6+
This library uses SPI DMA to control a strip of WS2812B (NeoPixel) LEDS
7+
8+
It should be generally compatible with the Adafruit NeoPixel library,
9+
except I have not had chance to implement one or two of the lesser used functions
10+
11+
Connect Data In of the strip to SPI1 MOSI
12+
13+
This library has only been tested on the WS2812B LED. It may not work with the older WS2812 or
14+
other types of addressable RGB LED, becuase it relies on a division multiple of the 72Mhz clock
15+
frequence on the STM32 SPI to generate the correct width T0H pulse, of 400ns +/- 150nS
16+
SPI DIV32 gives a pulse width of 444nS which is well within spec for the WS2812B but
17+
is probably too long for the WS2812 which needs a 350ns pulse for T0H
18+
19+
##Technical details
20+
21+
The library uses SPI to send the mark/space encoded data to the LED's
22+
23+
Each mark/space squarewave is generated by 3 bits of data
24+
A pixel 0 value is achieved by sending the bit pattern 100
25+
A pixel 1 value is achieved by sending the bit pattern 110
26+
27+
Where the duration of each bit is 444nS
28+
Hence 100 generates a mark space value of 444/888nS
29+
and 110 generates a mark space value of 888/444nS
30+
31+
This method results in the smallest storage requirement and the fastest send times,
32+
however because the 8 bit pixel channel data is encoded in 24 bits, (3 bytes) the values required in each of the 3 bytes to represent
33+
a specific value is not easy to generate.
34+
35+
The bit pattern in the 3 bytes is
36+
88877766 65554443 33222111
37+
38+
For speed of operation the values reqired for each byte for each of the 256 possible values is held in 3 separate 256 byte LUTS
39+
which were pre-computed by this function (which generates the full 24 bit pattern for a given input value (0-255)
40+
41+
```
42+
uint32_t convert(uint8_t data)
43+
{
44+
uint32_t out=0;
45+
for(uint8_t mask = 0x80; mask; mask >>= 1)
46+
{
47+
out=out<<3;
48+
if (data & mask)
49+
{
50+
out = out | 0B110;//Bit high
51+
}
52+
else
53+
{
54+
out = out | 0B100;// bit low
55+
}
56+
}
57+
return out;
58+
}
59+
```
60+
61+
The STM32F103 has plenty of flash space (either 64 or 128k), so I used 256 byte LUTs even though the number of unique values in each LUT is
62+
only 8,4 and 8 bytes respectively.
63+
However to use small LUTS requires shifting and masking of the input data, and the code was written with a preference for speed over binary size
64+
65+
The encoded pixel buffer is 2 bytes longer than the actual encoded data.
66+
The first and last encoded bytes are all zeros. This is because the SPI hardware seems to preload MOSI with its output value before the start
67+
of the DMA transfer, which causes the first encoded pulse to be around 50ns longer than the subsequent bits, (around 490 or 500ns)
68+
This had the effect of causing the first LED to always think the MS bit of the green channel was set to High.
69+
70+
So having the first encoded byte of zeros, is a work-around , as although the first encoded bit is still 490nS wide its a logic zero and is therefore
71+
not visible, becuase the default state is of the SPI when not transmitting data is logic zero
72+
The last byte was also set to all zeros, as occasionally MOSI seemed to be left set to logic high on completion of the SPI DMA send
73+
74+
Adding these 2 bytes does slightly slow down the transfer, as it add 444ns * 8 = just over 3.5uS to both end.
75+
But the WS2812B theoretically requires a reset time of more than 50uS between transmissions, so 3.5uS can be part of that time.
76+
In reality the WS2812B seems to only need around 6uS of reset time, so for all practical purposes, there no delays are needed at all in the
77+
library to enforce the reset time, as the overead of the function call and the SPI DMA setup plus the 3.5uS gives the enough reset time.
78+
Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
#include <WS2812B.h>
2+
3+
#define NUM_LEDS 30
4+
/*
5+
* Note. Library uses SPI1
6+
* Connect the WS2812B data input to MOSI on your board.
7+
*
8+
*/
9+
WS2812B strip = WS2812B(NUM_LEDS);
10+
// Note. Gamma is not really supported in the library, its only included as some functions used in this example require Gamma
11+
uint8_t LEDGamma[] = {
12+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
13+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
14+
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
15+
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
16+
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
17+
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
18+
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
19+
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
20+
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
21+
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
22+
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
23+
90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
24+
115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
25+
144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
26+
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
27+
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
28+
29+
void setup()
30+
{
31+
strip.begin();// Sets up the SPI
32+
strip.show();// Clears the strip, as by default the strip data is set to all LED's off.
33+
// strip.setBrightness(8);
34+
}
35+
36+
void loop()
37+
{
38+
colorWipe(strip.Color(0, 255, 0), 20); // Green
39+
colorWipe(strip.Color(255, 0, 0), 20); // Red
40+
colorWipe(strip.Color(0, 0, 255), 20); // Blue
41+
rainbow(10);
42+
rainbowCycle(10);
43+
theaterChase(strip.Color(255, 0, 0), 20); // Red
44+
theaterChase(strip.Color(0, 255, 0), 20); // Green
45+
theaterChase(strip.Color(0, 0, 255), 20); // Blue
46+
theaterChaseRainbow(10);
47+
whiteOverRainbow(20,75,5);
48+
pulseWhite(5);
49+
delay(250);
50+
fullWhite();
51+
delay(250);
52+
rainbowFade2White(3,3,1);
53+
}
54+
55+
// Fill the dots one after the other with a color
56+
void colorWipe(uint32_t c, uint8_t wait)
57+
{
58+
for(uint16_t i=0; i<strip.numPixels(); i++)
59+
{
60+
strip.setPixelColor(i, c);
61+
strip.show();
62+
delay(wait);
63+
}
64+
}
65+
66+
void rainbow(uint8_t wait) {
67+
uint16_t i, j;
68+
69+
for(j=0; j<256; j++) {
70+
for(i=0; i<strip.numPixels(); i++)
71+
{
72+
strip.setPixelColor(i, Wheel((i+j) & 255));
73+
}
74+
strip.show();
75+
delay(wait);
76+
}
77+
}
78+
79+
80+
81+
// Slightly different, this makes the rainbow equally distributed throughout
82+
void rainbowCycle(uint8_t wait)
83+
{
84+
uint16_t i, j;
85+
86+
for(j=0; j<256*5; j++)
87+
{ // 5 cycles of all colors on wheel
88+
for(i=0; i< strip.numPixels(); i++)
89+
{
90+
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
91+
}
92+
strip.show();
93+
delay(wait);
94+
}
95+
}
96+
97+
// Input a value 0 to 255 to get a color value.
98+
// The colours are a transition r - g - b - back to r.
99+
uint32_t Wheel(byte WheelPos)
100+
{
101+
if(WheelPos < 85)
102+
{
103+
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
104+
}
105+
else
106+
{
107+
if(WheelPos < 170)
108+
{
109+
WheelPos -= 85;
110+
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
111+
}
112+
else
113+
{
114+
WheelPos -= 170;
115+
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
116+
}
117+
}
118+
}
119+
120+
//Theatre-style crawling lights.
121+
void theaterChase(uint32_t c, uint8_t wait) {
122+
for (int j=0; j<10; j++) { //do 10 cycles of chasing
123+
for (int q=0; q < 3; q++) {
124+
for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
125+
strip.setPixelColor(i+q, c); //turn every third pixel on
126+
}
127+
strip.show();
128+
129+
delay(wait);
130+
131+
for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
132+
strip.setPixelColor(i+q, 0); //turn every third pixel off
133+
}
134+
}
135+
}
136+
}
137+
138+
//Theatre-style crawling lights with rainbow effect
139+
void theaterChaseRainbow(uint8_t wait) {
140+
for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheel
141+
for (int q=0; q < 3; q++) {
142+
for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
143+
strip.setPixelColor(i+q, Wheel( (i+j) % 255)); //turn every third pixel on
144+
}
145+
strip.show();
146+
147+
delay(wait);
148+
149+
for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
150+
strip.setPixelColor(i+q, 0); //turn every third pixel off
151+
}
152+
}
153+
}
154+
}
155+
156+
void pulseWhite(uint8_t wait) {
157+
for(int j = 0; j < 256 ; j++){
158+
for(uint16_t i=0; i<strip.numPixels(); i++) {
159+
strip.setPixelColor(i, strip.Color(0,0,0, LEDGamma[j] ) );
160+
}
161+
delay(wait);
162+
strip.show();
163+
}
164+
165+
for(int j = 255; j >= 0 ; j--){
166+
for(uint16_t i=0; i<strip.numPixels(); i++) {
167+
strip.setPixelColor(i, strip.Color(0,0,0, LEDGamma[j] ) );
168+
}
169+
delay(wait);
170+
strip.show();
171+
}
172+
}
173+
174+
175+
void rainbowFade2White(uint8_t wait, int rainbowLoops, int whiteLoops) {
176+
float fadeMax = 100.0;
177+
int fadeVal = 0;
178+
uint32_t wheelVal;
179+
int redVal, greenVal, blueVal;
180+
181+
for(int k = 0 ; k < rainbowLoops ; k ++){
182+
183+
for(int j=0; j<256; j++) { // 5 cycles of all colors on wheel
184+
185+
for(int i=0; i< strip.numPixels(); i++) {
186+
187+
wheelVal = Wheel(((i * 256 / strip.numPixels()) + j) & 255);
188+
189+
redVal = red(wheelVal) * float(fadeVal/fadeMax);
190+
greenVal = green(wheelVal) * float(fadeVal/fadeMax);
191+
blueVal = blue(wheelVal) * float(fadeVal/fadeMax);
192+
193+
strip.setPixelColor( i, strip.Color( redVal, greenVal, blueVal ) );
194+
195+
}
196+
197+
//First loop, fade in!
198+
if(k == 0 && fadeVal < fadeMax-1) {
199+
fadeVal++;
200+
}
201+
202+
//Last loop, fade out!
203+
else if(k == rainbowLoops - 1 && j > 255 - fadeMax ){
204+
fadeVal--;
205+
}
206+
207+
strip.show();
208+
delay(wait);
209+
}
210+
211+
}
212+
213+
214+
215+
delay(500);
216+
217+
218+
for(int k = 0 ; k < whiteLoops ; k ++){
219+
220+
for(int j = 0; j < 256 ; j++){
221+
222+
for(uint16_t i=0; i < strip.numPixels(); i++) {
223+
strip.setPixelColor(i, strip.Color(0,0,0, LEDGamma[j] ) );
224+
}
225+
strip.show();
226+
}
227+
228+
delay(2000);
229+
for(int j = 255; j >= 0 ; j--){
230+
231+
for(uint16_t i=0; i < strip.numPixels(); i++) {
232+
strip.setPixelColor(i, strip.Color(0,0,0, LEDGamma[j] ) );
233+
}
234+
strip.show();
235+
}
236+
}
237+
238+
delay(500);
239+
240+
241+
}
242+
243+
void whiteOverRainbow(uint8_t wait, uint8_t whiteSpeed, uint8_t whiteLength ) {
244+
245+
if(whiteLength >= strip.numPixels()) whiteLength = strip.numPixels() - 1;
246+
247+
int head = whiteLength - 1;
248+
int tail = 0;
249+
250+
int loops = 3;
251+
int loopNum = 0;
252+
253+
static unsigned long lastTime = 0;
254+
255+
256+
while(true){
257+
for(int j=0; j<256; j++) {
258+
for(uint16_t i=0; i<strip.numPixels(); i++) {
259+
if((i >= tail && i <= head) || (tail > head && i >= tail) || (tail > head && i <= head) ){
260+
strip.setPixelColor(i, strip.Color(0,0,0, 255 ) );
261+
}
262+
else{
263+
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
264+
}
265+
266+
}
267+
268+
if(millis() - lastTime > whiteSpeed) {
269+
head++;
270+
tail++;
271+
if(head == strip.numPixels()){
272+
loopNum++;
273+
}
274+
lastTime = millis();
275+
}
276+
277+
if(loopNum == loops) return;
278+
279+
head%=strip.numPixels();
280+
tail%=strip.numPixels();
281+
strip.show();
282+
delay(wait);
283+
}
284+
}
285+
286+
}
287+
void fullWhite() {
288+
289+
for(uint16_t i=0; i<strip.numPixels(); i++) {
290+
strip.setPixelColor(i, strip.Color(0,0,0, 255 ) );
291+
}
292+
strip.show();
293+
}
294+
295+
uint8_t red(uint32_t c) {
296+
return (c >> 16);
297+
}
298+
uint8_t green(uint32_t c) {
299+
return (c >> 8);
300+
}
301+
uint8_t blue(uint32_t c) {
302+
return (c);
303+
}

0 commit comments

Comments
 (0)