License info: * Controls WS2811/WS2812/WS2812B RGB-LEDs * Author: Tim (cpldcpu@gmail.com) * * Jan 18th, 2014 v2.0b Initial Version * March 7th, 2014 v2.1 Added option to retarget the port register during runtime * Removes inlining to allow compiling with c++ * * License: GNU GPL v2 (see License.txt)pull/18/head
parent
6e3c0c960d
commit
02123ff05c
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* light weight WS2812 lib V2.1 - Arduino support
|
||||
*
|
||||
* Controls WS2811/WS2812/WS2812B RGB-LEDs
|
||||
* Author: Matthias Riegler
|
||||
*
|
||||
* Mar 07 2014: Added Arduino and C++ Library
|
||||
*
|
||||
* September 6, 2014: Added option to switch between most popular color orders
|
||||
* (RGB, GRB, and BRG) -- Windell H. Oskay
|
||||
*
|
||||
* License: GNU GPL v2 (see License.txt)
|
||||
*/
|
||||
|
||||
#include "WS2812.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
WS2812::WS2812(uint16_t num_leds) {
|
||||
count_led = num_leds;
|
||||
|
||||
pixels = (uint8_t*)malloc(count_led*3);
|
||||
offsetGreen = 0;
|
||||
offsetRed = 1;
|
||||
offsetBlue = 2;
|
||||
}
|
||||
|
||||
cRGB WS2812::get_crgb_at(uint16_t index) {
|
||||
|
||||
cRGB px_value;
|
||||
|
||||
if(index < count_led) {
|
||||
|
||||
uint16_t tmp;
|
||||
tmp = index * 3;
|
||||
|
||||
px_value.r = pixels[tmp+offsetRed];
|
||||
px_value.g = pixels[tmp+offsetGreen];
|
||||
px_value.b = pixels[tmp+offsetBlue];
|
||||
}
|
||||
|
||||
return px_value;
|
||||
}
|
||||
|
||||
uint8_t WS2812::set_crgb_at(uint16_t index, cRGB px_value) {
|
||||
|
||||
if(index < count_led) {
|
||||
|
||||
uint16_t tmp;
|
||||
tmp = index * 3;
|
||||
|
||||
pixels[tmp+offsetGreen] = px_value.g;
|
||||
pixels[tmp+offsetRed] = px_value.r;
|
||||
pixels[tmp+offsetBlue] = px_value.b;
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void WS2812::sync() {
|
||||
*ws2812_port_reg |= pinMask; // Enable DDR
|
||||
ws2812_sendarray_mask(pixels,3*count_led,pinMask,(uint8_t*) ws2812_port,(uint8_t*) ws2812_port_reg );
|
||||
}
|
||||
|
||||
void WS2812::setColorOrderGRB() { // Default color order
|
||||
offsetGreen = 0;
|
||||
offsetRed = 1;
|
||||
offsetBlue = 2;
|
||||
}
|
||||
|
||||
void WS2812::setColorOrderRGB() {
|
||||
offsetRed = 0;
|
||||
offsetGreen = 1;
|
||||
offsetBlue = 2;
|
||||
}
|
||||
|
||||
void WS2812::setColorOrderBRG() {
|
||||
offsetBlue = 0;
|
||||
offsetRed = 1;
|
||||
offsetGreen = 2;
|
||||
}
|
||||
|
||||
WS2812::~WS2812() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
#ifndef ARDUINO
|
||||
void WS2812::setOutput(const volatile uint8_t* port, volatile uint8_t* reg, uint8_t pin) {
|
||||
pinMask = (1<<pin);
|
||||
ws2812_port = port;
|
||||
ws2812_port_reg = reg;
|
||||
}
|
||||
#else
|
||||
void WS2812::setOutput(uint8_t pin) {
|
||||
pinMask = digitalPinToBitMask(pin);
|
||||
ws2812_port = portOutputRegister(digitalPinToPort(pin));
|
||||
ws2812_port_reg = portModeRegister(digitalPinToPort(pin));
|
||||
}
|
||||
#endif
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* light weight WS2812 lib V2.1 - Arduino support
|
||||
*
|
||||
* Controls WS2811/WS2812/WS2812B RGB-LEDs
|
||||
* Author: Matthias Riegler
|
||||
*
|
||||
* Mar 07 2014: Added Arduino and C++ Library
|
||||
*
|
||||
* September 6, 2014 Added option to switch between most popular color orders
|
||||
* (RGB, GRB, and BRG) -- Windell H. Oskay
|
||||
*
|
||||
* License: GNU GPL v2 (see License.txt)
|
||||
*/
|
||||
|
||||
#ifndef WS2812_H_
|
||||
#define WS2812_H_
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/io.h>
|
||||
#ifndef F_CPU
|
||||
#define F_CPU 16000000UL
|
||||
#endif
|
||||
#include <util/delay.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef ARDUINO
|
||||
#if (ARDUINO >= 100)
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#include <pins_arduino.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct cRGB { uint8_t g; uint8_t r; uint8_t b; };
|
||||
|
||||
class WS2812 {
|
||||
public:
|
||||
WS2812(uint16_t num_led);
|
||||
~WS2812();
|
||||
|
||||
#ifndef ARDUINO
|
||||
void setOutput(const volatile uint8_t* port, volatile uint8_t* reg, uint8_t pin);
|
||||
#else
|
||||
void setOutput(uint8_t pin);
|
||||
#endif
|
||||
|
||||
cRGB get_crgb_at(uint16_t index);
|
||||
uint8_t set_crgb_at(uint16_t index, cRGB px_value);
|
||||
void sync();
|
||||
void setColorOrderRGB();
|
||||
void setColorOrderGRB();
|
||||
void setColorOrderBRG();
|
||||
|
||||
|
||||
private:
|
||||
uint16_t count_led;
|
||||
uint8_t *pixels;
|
||||
uint8_t offsetRed;
|
||||
uint8_t offsetGreen;
|
||||
uint8_t offsetBlue;
|
||||
|
||||
void ws2812_sendarray_mask(uint8_t *array,uint16_t length, uint8_t pinmask,uint8_t *port, uint8_t *portreg);
|
||||
|
||||
const volatile uint8_t *ws2812_port;
|
||||
volatile uint8_t *ws2812_port_reg;
|
||||
uint8_t pinMask;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* WS2812_H_ */
|
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* light weight WS2812 lib V2.1 - Arduino support
|
||||
*
|
||||
* Controls WS2811/WS2812/WS2812B RGB-LEDs
|
||||
* Author: Tim (cpldcpu@gmail.com)
|
||||
*
|
||||
* Jan 18th, 2014 v2.0b Initial Version
|
||||
* March 7th, 2014 v2.1 Added option to retarget the port register during runtime
|
||||
* Removes inlining to allow compiling with c++
|
||||
*
|
||||
* License: GNU GPL v2 (see License.txt)
|
||||
*/
|
||||
|
||||
#include "WS2812.h"
|
||||
|
||||
/*
|
||||
This routine writes an array of bytes with RGB values to the Dataout pin
|
||||
using the fast 800kHz clockless WS2811/2812 protocol.
|
||||
*/
|
||||
|
||||
// Timing in ns
|
||||
#define w_zeropulse 350
|
||||
#define w_onepulse 900
|
||||
#define w_totalperiod 1250
|
||||
|
||||
// Fixed cycles used by the inner loop
|
||||
#define w_fixedlow 3
|
||||
#define w_fixedhigh 6
|
||||
#define w_fixedtotal 10
|
||||
|
||||
// Insert NOPs to match the timing, if possible
|
||||
#define w_zerocycles (((F_CPU/1000)*w_zeropulse )/1000000)
|
||||
#define w_onecycles (((F_CPU/1000)*w_onepulse +500000)/1000000)
|
||||
#define w_totalcycles (((F_CPU/1000)*w_totalperiod +500000)/1000000)
|
||||
|
||||
// w1 - nops between rising edge and falling edge - low
|
||||
#define w1 (w_zerocycles-w_fixedlow)
|
||||
// w2 nops between fe low and fe high
|
||||
#define w2 (w_onecycles-w_fixedhigh-w1)
|
||||
// w3 nops to complete loop
|
||||
#define w3 (w_totalcycles-w_fixedtotal-w1-w2)
|
||||
|
||||
#if w1>0
|
||||
#define w1_nops w1
|
||||
#else
|
||||
#define w1_nops 0
|
||||
#endif
|
||||
|
||||
// The only critical timing parameter is the minimum pulse length of the "0"
|
||||
// Warn or throw error if this timing can not be met with current F_CPU settings.
|
||||
#define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000)
|
||||
#if w_lowtime>550
|
||||
#error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?"
|
||||
#elif w_lowtime>450
|
||||
#warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)."
|
||||
#warning "Please consider a higher clockspeed, if possible"
|
||||
#endif
|
||||
|
||||
#if w2>0
|
||||
#define w2_nops w2
|
||||
#else
|
||||
#define w2_nops 0
|
||||
#endif
|
||||
|
||||
#if w3>0
|
||||
#define w3_nops w3
|
||||
#else
|
||||
#define w3_nops 0
|
||||
#endif
|
||||
|
||||
#define w_nop1 "nop \n\t"
|
||||
#define w_nop2 "rjmp .+0 \n\t"
|
||||
#define w_nop4 w_nop2 w_nop2
|
||||
#define w_nop8 w_nop4 w_nop4
|
||||
#define w_nop16 w_nop8 w_nop8
|
||||
|
||||
void WS2812::ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi,uint8_t *port, uint8_t *portreg)
|
||||
{
|
||||
uint8_t curbyte,ctr,masklo;
|
||||
uint8_t sreg_prev;
|
||||
|
||||
masklo = ~maskhi & *port;
|
||||
maskhi |= *port;
|
||||
sreg_prev=SREG;
|
||||
cli();
|
||||
|
||||
while (datlen--) {
|
||||
curbyte=*data++;
|
||||
|
||||
asm volatile(
|
||||
" ldi %0,8 \n\t"
|
||||
"loop%=: \n\t"
|
||||
" st X,%3 \n\t" // '1' [02] '0' [02] - re
|
||||
#if (w1_nops&1)
|
||||
w_nop1
|
||||
#endif
|
||||
#if (w1_nops&2)
|
||||
w_nop2
|
||||
#endif
|
||||
#if (w1_nops&4)
|
||||
w_nop4
|
||||
#endif
|
||||
#if (w1_nops&8)
|
||||
w_nop8
|
||||
#endif
|
||||
#if (w1_nops&16)
|
||||
w_nop16
|
||||
#endif
|
||||
" sbrs %1,7 \n\t" // '1' [04] '0' [03]
|
||||
" st X,%4 \n\t" // '1' [--] '0' [05] - fe-low
|
||||
" lsl %1 \n\t" // '1' [05] '0' [06]
|
||||
#if (w2_nops&1)
|
||||
w_nop1
|
||||
#endif
|
||||
#if (w2_nops&2)
|
||||
w_nop2
|
||||
#endif
|
||||
#if (w2_nops&4)
|
||||
w_nop4
|
||||
#endif
|
||||
#if (w2_nops&8)
|
||||
w_nop8
|
||||
#endif
|
||||
#if (w2_nops&16)
|
||||
w_nop16
|
||||
#endif
|
||||
" brcc skipone%= \n\t" // '1' [+1] '0' [+2] -
|
||||
" st X,%4 \n\t" // '1' [+3] '0' [--] - fe-high
|
||||
"skipone%=: " // '1' [+3] '0' [+2] -
|
||||
|
||||
#if (w3_nops&1)
|
||||
w_nop1
|
||||
#endif
|
||||
#if (w3_nops&2)
|
||||
w_nop2
|
||||
#endif
|
||||
#if (w3_nops&4)
|
||||
w_nop4
|
||||
#endif
|
||||
#if (w3_nops&8)
|
||||
w_nop8
|
||||
#endif
|
||||
#if (w3_nops&16)
|
||||
w_nop16
|
||||
#endif
|
||||
|
||||
" dec %0 \n\t" // '1' [+4] '0' [+3]
|
||||
" brne loop%=\n\t" // '1' [+5] '0' [+4]
|
||||
: "=&d" (ctr)
|
||||
// : "r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo)
|
||||
: "r" (curbyte), "x" (port), "r" (maskhi), "r" (masklo)
|
||||
);
|
||||
}
|
||||
|
||||
SREG=sreg_prev;
|
||||
}
|
Loading…
Reference in new issue