audio-reactive-led-strip/arduino/ws2812_controller/ws2812_i2s.cpp
Scott Lawson f860922d67 Removed ws2812b i2s library dependency, updated README
I have added a pre-configured version of the ws2812b i2s library to the
Arduino code. This removes the need to download and install the ws2812b
i2s library manually. The ws2812b code has been preconfigured to reduce
the temporal compared to the default value. The default value was found
to cause excessive flickering. The readme has been updated to reflect
this change. Also added a note about the maximum number of LEDs (255)
2016-12-30 22:31:27 -07:00

170 lines
4.7 KiB
C++

// ws2812_lib.cpp
//
// main library file / contains class implementation
//
// Need to give credits to Charles Lohr (https://github.com/cnlohr due
// to his work on his software for driving ws2812 led-strips using
// the i2s interface of the ESP8266.
//
// This inspired me to create an ESP8266 library for the Arduino IDE
// I've added temporal dithering & gamma-correction
// for a 'more natural' light intensity profile.
//
// No pin-definitions/mapings are required/possible as the library used the I2S
// output-pin. This pin in it's turn is shared with GPIO3 & RXD0
//
#include <Arduino.h>
#include <stdint.h>
#include "ws2812_i2s.h"
#include "ws2812_defs.h"
#include "ws2812_gamma.h"
// include C-style header
extern "C"
{
#include "ws2812_dma.h"
};
// class constructor
WS2812::WS2812(void)
{
// empty for now
}
// class de-constructor
WS2812::~WS2812(void)
{
// empty for now
// TODO : should implement switching of DMA
}
// Init led-string / memory buffers etc.
void WS2812::init(uint16_t _num_leds)
{
uint8_t i;
uint16_t j;
num_leds = _num_leds;
// clear zero buffer
for(j=0; j<NUM_I2S_ZERO_WORDS; j++)
{
i2s_zeros_buffer[j] = 0;
}
// do memory allocation for i2s buffer(s)
for(i=0; i<WS2812_DITHER_NUM; i++)
{
i2s_pixels_buffer[i] = new uint32_t[NUM_I2S_PIXEL_WORDS];
// TODO : handle memory allocation error better
if (i2s_pixels_buffer[i] == 0)
{
Serial.println("WS2812_I2S : ERROR ALLOCATING MEMORY");
return;
}
for(j=0; j<NUM_I2S_PIXEL_WORDS; j++)
{
i2s_pixels_buffer[i][j] = 0;
}
}
// set-up DMA descriptors / 1 pair per dither-factor
for(i=0; i<WS2812_DITHER_NUM; i++)
{
i2s_pixels_queue[i].owner = 1;
i2s_pixels_queue[i].eof = 1;
i2s_pixels_queue[i].sub_sof = 0;
i2s_pixels_queue[i].datalen = NUM_I2S_PIXEL_BYTES; // Size in bytes
i2s_pixels_queue[i].blocksize = NUM_I2S_PIXEL_BYTES; // Size in bytes
i2s_pixels_queue[i].buf_ptr = (uint32_t)i2s_pixels_buffer[i];
i2s_pixels_queue[i].unused = 0;
i2s_pixels_queue[i].next_link_ptr = (uint32_t)&i2s_zeros_queue[i]; // always link to zeros-buffer
i2s_zeros_queue[i].owner = 1;
i2s_zeros_queue[i].eof = 1;
i2s_zeros_queue[i].sub_sof = 0;
i2s_zeros_queue[i].datalen = NUM_I2S_ZERO_BYTES; // Size in bytes)
i2s_zeros_queue[i].blocksize = NUM_I2S_ZERO_BYTES; // Size in bytes
i2s_zeros_queue[i].buf_ptr = (uint32_t)i2s_zeros_buffer;
i2s_zeros_queue[i].unused = 0;
if (i == (WS2812_DITHER_NUM-1)) // last DMA descriptor in linked list ?
{
// yes : link to first DMA descriptor
i2s_zeros_queue[i].next_link_ptr = (uint32_t)&i2s_pixels_queue[0];
}
else
{
// no : link to next DMA descriptor
i2s_zeros_queue[i].next_link_ptr = (uint32_t)&i2s_pixels_queue[i+1];
}
}
// call C based helper function
// I did not really succeed in putting the code from the helper
// funtion directly into this constructor...has something to do
// with C vs. C++
// the i2c_writeReg_Mask macro (+ others) failed.. see ws2812_defs.h
// may be I solve this later
// parameter = first entry in DMA descriptor list, i.e the descriptor list
ws2812_dma(i2s_pixels_queue);
}
// left this comment in tact....credit to Charles
// All functions below this line are Public Domain 2015 Charles Lohr.
// this code may be used by anyone in any way without restriction or limitation.
// Send out WS2812 bits with coded pulses, one nibble, then the other.
static const uint16_t bitpatterns[16] =
{
0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110,
0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110,
0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110,
0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110,
};
// display the pixels
void WS2812::show(Pixel_t *pixels)
{
uint8_t *buffer;
uint8_t pixelbyte;
uint8_t gammabyte;
uint16_t i,b;
uint16_t *i2s_ptr[WS2812_DITHER_NUM];
buffer = (uint8_t *)pixels;
// set-up pointers into the i2s-pixel-buffers
for(i=0; i<WS2812_DITHER_NUM; i++)
{
i2s_ptr[i] = (uint16_t *)i2s_pixels_buffer[i];
}
// for every pixel in the input-array
// - get the pixel value (either R,G, or B)
// - for every dithered buffer
// get the gamma-corrected output value
// - and transform into i2s nibble
for(b=0; b<NUM_RGB_BYTES; b++)
{
pixelbyte = *buffer++;
for(i=0; i<WS2812_DITHER_NUM; i++)
{
gammabyte = gamma_dither[i][pixelbyte];
*(i2s_ptr[i]++) = bitpatterns[ (gammabyte & 0x0f) ];
*(i2s_ptr[i]++) = bitpatterns[ (gammabyte>>4) & 0x0f ];
}
}
}
// end of file