From e874ed3b2c3f9599b746371f4d3df61e4e806101 Mon Sep 17 00:00:00 2001 From: Scott Lawson Date: Thu, 29 Dec 2016 15:51:38 -0700 Subject: [PATCH 1/5] Resolved issues with Python 3.5 compatibility Fixed some bugs that occurred in Python 3.5 but were not present in Python 2.7. Most compatiblity issues were caused by incompatible type casting of numpy arrays. --- python/led.py | 2 +- python/visualization.py | 52 ++++++++++++++++++++++++++++------------- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/python/led.py b/python/led.py index e3e4971..b2b3458 100644 --- a/python/led.py +++ b/python/led.py @@ -15,7 +15,7 @@ pixels = np.tile(1, (3, config.N_PIXELS)) def update(): global pixels, _prev_pixels - pixels = np.clip(pixels, 0, 255) + pixels = np.clip(pixels, 0, 255).astype(int) m = '' p = _gamma[pixels] if config.GAMMA_CORRECTION else np.copy(pixels) for i in range(config.N_PIXELS): diff --git a/python/visualization.py b/python/visualization.py index 0baf103..3cc353c 100644 --- a/python/visualization.py +++ b/python/visualization.py @@ -75,13 +75,13 @@ b_filt = dsp.ExpFilter(np.tile(0.01, config.N_PIXELS // 2), alpha_decay=0.25, alpha_rise=0.99) p_filt = dsp.ExpFilter(np.tile(1, (3, config.N_PIXELS // 2)), alpha_decay=0.05, alpha_rise=0.8) -p = np.tile(1, (3, config.N_PIXELS // 2)) +p = np.tile(1.0, (3, config.N_PIXELS // 2)) gain = dsp.ExpFilter(np.tile(0.01, config.N_FFT_BINS), alpha_decay=0.001, alpha_rise=0.99) def largest_indices(ary, n): - """Returns the n largest indices from a numpy array.""" + """Returns indices of the n largest values in the given a numpy array""" flat = ary.flatten() indices = np.argpartition(flat, -n)[-n:] indices = indices[np.argsort(-flat[indices])] @@ -89,11 +89,12 @@ def largest_indices(ary, n): def visualize_max(y): + """Experimental sandbox effect. Not recommended for use""" y = np.copy(interpolate(y, config.N_PIXELS // 2)) * 255.0 ind = largest_indices(y, 15) - y[ind] *= -1 - y[y > 0] = 0 - y[ind] *= -1 + y[ind] *= -1.0 + y[y > 0] = 0.0 + y[ind] *= -1.0 # Blur the color channels with different strengths r = gaussian_filter1d(y, sigma=0.25) g = gaussian_filter1d(y, sigma=0.10) @@ -111,14 +112,15 @@ def visualize_max(y): led.pixels[0, :] = pixel_r led.pixels[1, :] = pixel_g led.pixels[2, :] = pixel_b + led.update() # Update the GUI plots GUI.curve[0][0].setData(y=pixel_r) GUI.curve[0][1].setData(y=pixel_g) GUI.curve[0][2].setData(y=pixel_b) - led.update() def visualize_scroll(y): + """Effect that originates in the center and scrolls outwards""" global p y = gaussian_filter1d(y, sigma=1.0)**3.0 y = np.copy(y) @@ -134,11 +136,17 @@ def visualize_scroll(y): p[0, 0] = r p[1, 0] = g p[2, 0] = b + # Update the LED strip led.pixels = np.concatenate((p[:, ::-1], p), axis=1) led.update() + # Update the GUI plots + GUI.curve[0][0].setData(y=np.concatenate((p[0, :][::-1], p[0, :]))) + GUI.curve[0][1].setData(y=np.concatenate((p[1, :][::-1], p[1, :]))) + GUI.curve[0][2].setData(y=np.concatenate((p[2, :][::-1], p[2, :]))) def visualize_energy(y): + """Effect that expands from the center with increasing sound energy""" global p y = gaussian_filter1d(y, sigma=1.0)**3.0 gain.update(y) @@ -147,22 +155,28 @@ def visualize_energy(y): r = int(np.mean(y[:len(y) // 3])) g = int(np.mean(y[len(y) // 3: 2 * len(y) // 3])) b = int(np.mean(y[2 * len(y) // 3:])) - p[0, :r] = 255 - p[0, r:] = 0 - p[1, :g] = 255 - p[1, g:] = 0 - p[2, :b] = 255 - p[2, b:] = 0 + p[0, :r] = 255.0 + p[0, r:] = 0.0 + p[1, :g] = 255.0 + p[1, g:] = 0.0 + p[2, :b] = 255.0 + p[2, b:] = 0.0 p_filt.update(p) p = p_filt.value.astype(int) p[0, :] = gaussian_filter1d(p[0, :], sigma=4.0) p[1, :] = gaussian_filter1d(p[1, :], sigma=4.0) p[2, :] = gaussian_filter1d(p[2, :], sigma=4.0) + # Update LED pixel arrays led.pixels = np.concatenate((p[:, ::-1], p), axis=1) led.update() + # Update the GUI plots + GUI.curve[0][0].setData(y=np.concatenate((p[0, :][::-1], p[0, :]))) + GUI.curve[0][1].setData(y=np.concatenate((p[1, :][::-1], p[1, :]))) + GUI.curve[0][2].setData(y=np.concatenate((p[2, :][::-1], p[2, :]))) def visualize_spectrum(y): + """Effect that maps the Mel filterbank frequencies onto the LED strip""" y = np.copy(interpolate(y, config.N_PIXELS // 2)) * 255.0 # Blur the color channels with different strengths r = gaussian_filter1d(y, sigma=0.25) @@ -179,11 +193,11 @@ def visualize_spectrum(y): led.pixels[0, :] = pixel_r led.pixels[1, :] = pixel_g led.pixels[2, :] = pixel_b + led.update() # Update the GUI plots GUI.curve[0][0].setData(y=pixel_r) GUI.curve[0][1].setData(y=pixel_g) GUI.curve[0][2].setData(y=pixel_b) - led.update() mel_gain = dsp.ExpFilter(np.tile(1e-1, config.N_FFT_BINS), @@ -194,7 +208,7 @@ volume = dsp.ExpFilter(config.MIN_VOLUME_THRESHOLD, def microphone_update(stream): global y_roll, prev_rms, prev_exp - # Normalize new audio samples + # Retrieve and normalize the new audio samples y = np.fromstring(stream.read(samples_per_frame, exception_on_overflow=False), dtype=np.int16) y = y / 2.0**15 @@ -209,19 +223,25 @@ def microphone_update(stream): led.pixels = np.tile(0, (3, config.N_PIXELS)) led.update() else: + # Transform audio input into the frequency domain XS, YS = dsp.fft(y_data, window=np.hamming) + # Remove half of the FFT data because of symmetry YS = YS[:len(YS) // 2] XS = XS[:len(XS) // 2] + # Construct a Mel filterbank from the FFT data YS = np.atleast_2d(np.abs(YS)).T * dsp.mel_y.T + # Scale data to values more suitable for visualization YS = np.sum(YS, axis=0)**2.0 mel = YS**0.5 mel = gaussian_filter1d(mel, sigma=1.0) + # Normalize the Mel filterbank to make it volume independent mel_gain.update(np.max(mel)) mel = mel / mel_gain.value + # Visualize the filterbank output visualize_spectrum(mel) # visualize_max(mel) # visualize_scroll(mel) - # visualize_energy(mel) + visualize_energy(mel) GUI.app.processEvents() print('FPS {:.0f} / {:.0f}'.format(frames_per_second(), config.FPS)) @@ -235,8 +255,8 @@ y_roll = np.random.rand(config.N_ROLLING_HISTORY, samples_per_frame) / 1e16 if __name__ == '__main__': import pyqtgraph as pg + # Create GUI plot for visualizing LED strip output GUI = gui.GUI(width=800, height=400, title='Audio Visualization') - # Audio plot GUI.add_plot('Color Channels') r_pen = pg.mkPen((255, 30, 30, 200), width=6) g_pen = pg.mkPen((30, 255, 30, 200), width=6) From 27a04482031725ead8d85eadd9492c76ddea7d64 Mon Sep 17 00:00:00 2001 From: Scott Lawson Date: Fri, 30 Dec 2016 22:18:56 -0700 Subject: [PATCH 2/5] Added LED strand test to LED.py Added a test routine to led.py to do a simple LED strand test. The strand test scrolls a red, green, and blue pixel across the LED strip forever. --- python/led.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/python/led.py b/python/led.py index b2b3458..1122e1d 100644 --- a/python/led.py +++ b/python/led.py @@ -27,6 +27,19 @@ def update(): _sock.sendto(m.encode(), (config.UDP_IP, config.UDP_PORT)) +# Execute this file to run a LED strand test +# If everything is working, you should see a red, green, and blue pixel scroll +# across the LED strip continously if __name__ == '__main__': + import time + # Turn all pixels off pixels *= 0 - update() + pixels[0, 0] = 255 # Set 1st pixel red + pixels[1, 1] = 255 # Set 2nd pixel green + pixels[2, 2] = 255 # Set 3rd pixel blue + print('Starting LED strand test') + while True: + pixels = np.roll(pixels, 1, axis=1) + update() + time.sleep(0.2) + From 3241e434357f0821cabc1fdbdbd3c08340260dce Mon Sep 17 00:00:00 2001 From: Scott Lawson Date: Fri, 30 Dec 2016 22:19:46 -0700 Subject: [PATCH 3/5] Fixed a typo where multiple effects were uncommented --- python/visualization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/visualization.py b/python/visualization.py index 3cc353c..dd789b9 100644 --- a/python/visualization.py +++ b/python/visualization.py @@ -238,7 +238,7 @@ def microphone_update(stream): mel_gain.update(np.max(mel)) mel = mel / mel_gain.value # Visualize the filterbank output - visualize_spectrum(mel) + # visualize_spectrum(mel) # visualize_max(mel) # visualize_scroll(mel) visualize_energy(mel) From f860922d67efaa614ffa5ba0ac904984098a467d Mon Sep 17 00:00:00 2001 From: Scott Lawson Date: Fri, 30 Dec 2016 22:31:27 -0700 Subject: [PATCH 4/5] 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) --- README.md | 9 +- arduino/ws2812_controller/ws2812.h | 26 +++ .../ws2812_controller/ws2812_controller.ino | 5 +- arduino/ws2812_controller/ws2812_defs.h | 172 ++++++++++++++++++ arduino/ws2812_controller/ws2812_dma.c | 102 +++++++++++ arduino/ws2812_controller/ws2812_dma.h | 25 +++ arduino/ws2812_controller/ws2812_gamma.cpp | 165 +++++++++++++++++ arduino/ws2812_controller/ws2812_gamma.h | 12 ++ arduino/ws2812_controller/ws2812_i2s.cpp | 169 +++++++++++++++++ arduino/ws2812_controller/ws2812_i2s.h | 41 +++++ 10 files changed, 721 insertions(+), 5 deletions(-) create mode 100644 arduino/ws2812_controller/ws2812.h create mode 100644 arduino/ws2812_controller/ws2812_defs.h create mode 100644 arduino/ws2812_controller/ws2812_dma.c create mode 100644 arduino/ws2812_controller/ws2812_dma.h create mode 100644 arduino/ws2812_controller/ws2812_gamma.cpp create mode 100644 arduino/ws2812_controller/ws2812_gamma.h create mode 100644 arduino/ws2812_controller/ws2812_i2s.cpp create mode 100644 arduino/ws2812_controller/ws2812_i2s.h diff --git a/README.md b/README.md index 76bd1c9..0aa7e94 100644 --- a/README.md +++ b/README.md @@ -63,10 +63,10 @@ If `pip` is not found try using `python -m pip install` instead. ## Arduino dependencies ESP8266 firmare is uploaded using the Arduino IDE. See [this tutorial](https://learn.sparkfun.com/tutorials/esp8266-thing-hookup-guide/installing-the-esp8266-arduino-addon) to setup the Arduino IDE for ESP8266. -This [ws2812b i2s library](https://github.com/JoDaNl/esp8266_ws2812_i2s) must be downloaded and installed in the Arduino libraries folder. - + # Hardware Connections -The ESP8266 has hardware support for [I²S](https://en.wikipedia.org/wiki/I%C2%B2S) and this peripheral is used by the [ws2812b i2s library](https://github.com/JoDaNl/esp8266_ws2812_i2s) to control the ws2812b LED strip. This signficantly improves performance compared to bit-banging the IO pin. Unfortunately, this means that the LED strip **must** be connected to the RX1 pin, which is not accessible in some ESP8266 modules (such as the ESP-01). +The ESP8266 has hardware support for [I²S](https://en.wikipedia.org/wiki/I%C2%B2S) and this peripheral is used to control the ws2812b LED strip. This signficantly improves performance compared to bit-banging the IO pin. Unfortunately, this means that the LED strip **must** be connected to the RX1 pin, which is not accessible in some ESP8266 modules (such as the ESP-01). The RX1 pin on the ESP8266 module should be connected to the data input pin of the ws2812b LED strip (often labelled DIN or D0). @@ -99,5 +99,8 @@ A PyQtGraph GUI will open to display the output of the visualization on the comp If you encounter any issues or have questions about this project, feel free to open a new issue. +# Limitations +The visualization code currently supports up to 255 LEDs. Support for additional LEDs will be added in the near future. + # License All code in this project is released under the MIT License. \ No newline at end of file diff --git a/arduino/ws2812_controller/ws2812.h b/arduino/ws2812_controller/ws2812.h new file mode 100644 index 0000000..5085988 --- /dev/null +++ b/arduino/ws2812_controller/ws2812.h @@ -0,0 +1,26 @@ +// ws2812.h + +#ifndef __WS2812_H__ +#define __WS2812_H__ + +// Gamma Correction +// Uses a nonlinear lookup table to correct for human perception of light. +// When gamma correction is used, a brightness value of 2X should appear twice +// as bright as a value of X. +// 1 = Enable gamma correction +// 0 = Disable gamma correction +// Note: There seems to be a bug and you can't actually disable this +#define WS2812_GAMMA_CORRECTION (0) + +// Temporal Dithering +// Dithering preserves color and light when brightness is low. +// Sometimes this can cause undesirable flickering. +// 1 = Disable temporal dithering +// 2, 6, 8 = Enable temporal dithering (larger values = more dithering) +#define WS2812_DITHER_NUM (4) + +#define WS2812_USE_INTERRUPT (0) // not supported yet + +#endif + +// end of file diff --git a/arduino/ws2812_controller/ws2812_controller.ino b/arduino/ws2812_controller/ws2812_controller.ino index 1632d1b..fa79bd7 100644 --- a/arduino/ws2812_controller/ws2812_controller.ino +++ b/arduino/ws2812_controller/ws2812_controller.ino @@ -3,10 +3,11 @@ #include #include #include -#include +#include "ws2812_i2s.h" // Set this to the number of LEDs in your LED strip -#define NUM_LEDS 260 +#define NUM_LEDS 60 +// Maximum number of packets to hold in the buffer. Don't change this. #define BUFFER_LEN 1024 // Wifi and socket settings diff --git a/arduino/ws2812_controller/ws2812_defs.h b/arduino/ws2812_controller/ws2812_defs.h new file mode 100644 index 0000000..6a4a08d --- /dev/null +++ b/arduino/ws2812_controller/ws2812_defs.h @@ -0,0 +1,172 @@ +// w2812_defs.h +// +// contains material from Charles Lohr, but changed by me. + +#ifndef __WS2812_I2S_DEFS_H__ +#define __WS2812_I2S_DEFS_H__ + +#include + +// include file from project folder +#include "ws2812.h" + +// ----------------------------------------------------- + +// Helper macro's + +#define NUM_RGB_BYTES (num_leds * 3) +#define NUM_I2S_PIXEL_BYTES (num_leds * 3 * 4) // (#leds) * (RGB) * (4 i2s bits) +#define NUM_I2S_PIXEL_WORDS (num_leds * 3) + +// ----------------------------------------------------- + +// I2S timing parameters + +// Creates an I2S SR of 93,750 Hz, or 3 MHz Bitclock (.333us/sample) +// Measured on scope : 4 bitclock-ticks every 1200ns --> 300ns bitclock ??? +// 12000000L/(div*bestbck*2) + +#define WS_I2S_BCK (17) +#define WS_I2S_DIV (4) +#define NUM_I2S_ZERO_BYTES (28) // WS2812 LED Treset = 67us (must be >50us) +#define NUM_I2S_ZERO_WORDS (NUM_I2S_ZERO_BYTES / 4) + +// ----------------------------------------------------- + +#ifndef i2c_bbpll +#define i2c_bbpll 0x67 +#define i2c_bbpll_en_audio_clock_out 4 +#define i2c_bbpll_en_audio_clock_out_msb 7 +#define i2c_bbpll_en_audio_clock_out_lsb 7 +#define i2c_bbpll_hostid 4 +#endif + +// ----------------------------------------------------- + +#define i2c_writeReg_Mask(block, host_id, reg_add, Msb, Lsb, indata) rom_i2c_writeReg_Mask(block, host_id, reg_add, Msb, Lsb, indata) +#define i2c_readReg_Mask(block, host_id, reg_add, Msb, Lsb) rom_i2c_readReg_Mask(block, host_id, reg_add, Msb, Lsb) +#define i2c_writeReg_Mask_def(block, reg_add, indata) i2c_writeReg_Mask(block, block##_hostid, reg_add, reg_add##_msb, reg_add##_lsb, indata) +#define i2c_readReg_Mask_def(block, reg_add) i2c_readReg_Mask(block, block##_hostid, reg_add, reg_add##_msb, reg_add##_lsb) + +// ----------------------------------------------------- + +#ifndef ETS_SLC_INUM +#define ETS_SLC_INUM 1 +#endif + +// ----------------------------------------------------- + +// from i2s_reg.h + +#define DR_REG_I2S_BASE (0x60000e00) + +#define I2STXFIFO (DR_REG_I2S_BASE + 0x0000) +#define I2SRXFIFO (DR_REG_I2S_BASE + 0x0004) +#define I2SCONF (DR_REG_I2S_BASE + 0x0008) +#define I2S_BCK_DIV_NUM 0x0000003F +#define I2S_BCK_DIV_NUM_S 22 +#define I2S_CLKM_DIV_NUM 0x0000003F +#define I2S_CLKM_DIV_NUM_S 16 +#define I2S_BITS_MOD 0x0000000F +#define I2S_BITS_MOD_S 12 +#define I2S_RECE_MSB_SHIFT (BIT(11)) +#define I2S_TRANS_MSB_SHIFT (BIT(10)) +#define I2S_I2S_RX_START (BIT(9)) +#define I2S_I2S_TX_START (BIT(8)) +#define I2S_MSB_RIGHT (BIT(7)) +#define I2S_RIGHT_FIRST (BIT(6)) +#define I2S_RECE_SLAVE_MOD (BIT(5)) +#define I2S_TRANS_SLAVE_MOD (BIT(4)) +#define I2S_I2S_RX_FIFO_RESET (BIT(3)) +#define I2S_I2S_TX_FIFO_RESET (BIT(2)) +#define I2S_I2S_RX_RESET (BIT(1)) +#define I2S_I2S_TX_RESET (BIT(0)) +#define I2S_I2S_RESET_MASK 0xf + +#define I2SINT_RAW (DR_REG_I2S_BASE + 0x000c) +#define I2S_I2S_TX_REMPTY_INT_RAW (BIT(5)) +#define I2S_I2S_TX_WFULL_INT_RAW (BIT(4)) +#define I2S_I2S_RX_REMPTY_INT_RAW (BIT(3)) +#define I2S_I2S_RX_WFULL_INT_RAW (BIT(2)) +#define I2S_I2S_TX_PUT_DATA_INT_RAW (BIT(1)) +#define I2S_I2S_RX_TAKE_DATA_INT_RAW (BIT(0)) + +#define I2SINT_ST (DR_REG_I2S_BASE + 0x0010) +#define I2S_I2S_TX_REMPTY_INT_ST (BIT(5)) +#define I2S_I2S_TX_WFULL_INT_ST (BIT(4)) +#define I2S_I2S_RX_REMPTY_INT_ST (BIT(3)) +#define I2S_I2S_RX_WFULL_INT_ST (BIT(2)) +#define I2S_I2S_TX_PUT_DATA_INT_ST (BIT(1)) +#define I2S_I2S_RX_TAKE_DATA_INT_ST (BIT(0)) + +#define I2SINT_ENA (DR_REG_I2S_BASE + 0x0014) +#define I2S_I2S_TX_REMPTY_INT_ENA (BIT(5)) +#define I2S_I2S_TX_WFULL_INT_ENA (BIT(4)) +#define I2S_I2S_RX_REMPTY_INT_ENA (BIT(3)) +#define I2S_I2S_RX_WFULL_INT_ENA (BIT(2)) +#define I2S_I2S_TX_PUT_DATA_INT_ENA (BIT(1)) +#define I2S_I2S_RX_TAKE_DATA_INT_ENA (BIT(0)) + +#define I2SINT_CLR (DR_REG_I2S_BASE + 0x0018) +#define I2S_I2S_TX_REMPTY_INT_CLR (BIT(5)) +#define I2S_I2S_TX_WFULL_INT_CLR (BIT(4)) +#define I2S_I2S_RX_REMPTY_INT_CLR (BIT(3)) +#define I2S_I2S_RX_WFULL_INT_CLR (BIT(2)) +#define I2S_I2S_PUT_DATA_INT_CLR (BIT(1)) +#define I2S_I2S_TAKE_DATA_INT_CLR (BIT(0)) + +#define I2STIMING (DR_REG_I2S_BASE + 0x001c) +#define I2S_TRANS_BCK_IN_INV (BIT(22)) +#define I2S_RECE_DSYNC_SW (BIT(21)) +#define I2S_TRANS_DSYNC_SW (BIT(20)) +#define I2S_RECE_BCK_OUT_DELAY 0x00000003 +#define I2S_RECE_BCK_OUT_DELAY_S 18 +#define I2S_RECE_WS_OUT_DELAY 0x00000003 +#define I2S_RECE_WS_OUT_DELAY_S 16 +#define I2S_TRANS_SD_OUT_DELAY 0x00000003 +#define I2S_TRANS_SD_OUT_DELAY_S 14 +#define I2S_TRANS_WS_OUT_DELAY 0x00000003 +#define I2S_TRANS_WS_OUT_DELAY_S 12 +#define I2S_TRANS_BCK_OUT_DELAY 0x00000003 +#define I2S_TRANS_BCK_OUT_DELAY_S 10 +#define I2S_RECE_SD_IN_DELAY 0x00000003 +#define I2S_RECE_SD_IN_DELAY_S 8 +#define I2S_RECE_WS_IN_DELAY 0x00000003 +#define I2S_RECE_WS_IN_DELAY_S 6 +#define I2S_RECE_BCK_IN_DELAY 0x00000003 +#define I2S_RECE_BCK_IN_DELAY_S 4 +#define I2S_TRANS_WS_IN_DELAY 0x00000003 +#define I2S_TRANS_WS_IN_DELAY_S 2 +#define I2S_TRANS_BCK_IN_DELAY 0x00000003 +#define I2S_TRANS_BCK_IN_DELAY_S 0 + +#define I2S_FIFO_CONF (DR_REG_I2S_BASE + 0x0020) +#define I2S_I2S_RX_FIFO_MOD 0x00000007 +#define I2S_I2S_RX_FIFO_MOD_S 16 +#define I2S_I2S_TX_FIFO_MOD 0x00000007 +#define I2S_I2S_TX_FIFO_MOD_S 13 +#define I2S_I2S_DSCR_EN (BIT(12)) +#define I2S_I2S_TX_DATA_NUM 0x0000003F +#define I2S_I2S_TX_DATA_NUM_S 6 +#define I2S_I2S_RX_DATA_NUM 0x0000003F +#define I2S_I2S_RX_DATA_NUM_S 0 + +#define I2SRXEOF_NUM (DR_REG_I2S_BASE + 0x0024) +#define I2S_I2S_RX_EOF_NUM 0xFFFFFFFF +#define I2S_I2S_RX_EOF_NUM_S 0 + +#define I2SCONF_SIGLE_DATA (DR_REG_I2S_BASE + 0x0028) +#define I2S_I2S_SIGLE_DATA 0xFFFFFFFF +#define I2S_I2S_SIGLE_DATA_S 0 + +#define I2SCONF_CHAN (DR_REG_I2S_BASE + 0x002c) +#define I2S_RX_CHAN_MOD 0x00000003 +#define I2S_RX_CHAN_MOD_S 3 +#define I2S_TX_CHAN_MOD 0x00000007 +#define I2S_TX_CHAN_MOD_S 0 + +// ----------------------------------------------------- + +#endif + +// end of file diff --git a/arduino/ws2812_controller/ws2812_dma.c b/arduino/ws2812_controller/ws2812_dma.c new file mode 100644 index 0000000..d2aa497 --- /dev/null +++ b/arduino/ws2812_controller/ws2812_dma.c @@ -0,0 +1,102 @@ +// ws2812_init.c + +// C-based helper function for initilalizing +// the I2S system + +#include +#include "slc_register.h" +#include "user_interface.h" +#include "ws2812_defs.h" +#include "ws2812_dma.h" + + +#if WS2812_USE_INTERRUPT == 1 +// for debugging purposes +static volatile uint32_t interrupt_count = 0; + +static void ws2812_isr(void) +{ + //clear all intr flags + WRITE_PERI_REG(SLC_INT_CLR, 0xffffffff);//slc_intr_status); + + interrupt_count++; +} +#endif + + +void ws2812_dma(sdio_queue_t *i2s_pixels_queue) +{ + // Reset DMA + SET_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST); //|SLC_TXLINK_RST); + CLEAR_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST); //|SLC_TXLINK_RST); + + // Clear DMA int flags + SET_PERI_REG_MASK(SLC_INT_CLR, 0xffffffff); + CLEAR_PERI_REG_MASK(SLC_INT_CLR, 0xffffffff); + + // Enable and configure DMA + CLEAR_PERI_REG_MASK(SLC_CONF0,(SLC_MODE< +#include "ws2812_gamma.h" + +static const uint8_t gamma0[] = { + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, + 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, + 10, 10, 10, 11, 11, 12, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, + 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, + 26, 26, 27, 28, 28, 29, 30, 30, 31, 32, 32, 33, 34, 34, 35, 36, + 37, 37, 38, 39, 40, 41, 41, 42, 43, 44, 45, 45, 46, 47, 48, 49, + 50, 51, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 80, 81, + 82, 83, 84, 85, 86, 88, 89, 90, 91, 92, 94, 95, 96, 97, 98, 100, + 101, 102, 103, 105, 106, 107, 109, 110, 111, 113, 114, 115, 117, 118, 119, 121, + 122, 123, 125, 126, 128, 129, 130, 132, 133, 135, 136, 138, 139, 141, 142, 144, + 145, 147, 148, 150, 151, 153, 154, 156, 157, 159, 161, 162, 164, 165, 167, 169, + 170, 172, 173, 175, 177, 178, 180, 182, 183, 185, 187, 189, 190, 192, 194, 196, + 197, 199, 201, 203, 204, 206, 208, 210, 212, 213, 215, 217, 219, 221, 223, 225, + 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 254, 255 }; + +static const uint8_t gamma1[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, + 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, + 9, 9, 10, 10, 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, + 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, + 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32, 32, 33, 34, 35, 35, + 36, 37, 38, 38, 39, 40, 41, 42, 42, 43, 44, 45, 46, 47, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 84, 85, 86, 87, 88, 89, 91, 92, 93, 94, 95, 97, 98, 99, + 100, 102, 103, 104, 105, 107, 108, 109, 111, 112, 113, 115, 116, 117, 119, 120, + 121, 123, 124, 126, 127, 128, 130, 131, 133, 134, 136, 137, 139, 140, 142, 143, + 145, 146, 148, 149, 151, 152, 154, 155, 157, 158, 160, 162, 163, 165, 166, 168, + 170, 171, 173, 175, 176, 178, 180, 181, 183, 185, 186, 188, 190, 192, 193, 195, + 197, 199, 200, 202, 204, 206, 207, 209, 211, 213, 215, 217, 218, 220, 222, 224, + 226, 228, 230, 232, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255 }; + +static const uint8_t gamma2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, + 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, + 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, + 16, 17, 17, 18, 18, 19, 19, 20, 21, 21, 22, 22, 23, 24, 24, 25, + 25, 26, 27, 27, 28, 29, 29, 30, 31, 31, 32, 33, 33, 34, 35, 36, + 36, 37, 38, 39, 39, 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, 49, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 82, 83, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 96, 97, 98, 99, + 101, 102, 103, 104, 106, 107, 108, 110, 111, 112, 114, 115, 116, 118, 119, 120, + 122, 123, 125, 126, 127, 129, 130, 132, 133, 134, 136, 137, 139, 140, 142, 143, + 145, 146, 148, 149, 151, 152, 154, 156, 157, 159, 160, 162, 163, 165, 167, 168, + 170, 172, 173, 175, 177, 178, 180, 182, 183, 185, 187, 188, 190, 192, 194, 195, + 197, 199, 201, 202, 204, 206, 208, 210, 211, 213, 215, 217, 219, 221, 222, 224, + 226, 228, 230, 232, 234, 236, 238, 240, 241, 243, 245, 247, 249, 251, 253, 255 }; + +static const uint8_t gamma3[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, + 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, + 9, 9, 10, 10, 10, 11, 11, 12, 12, 12, 13, 13, 14, 14, 15, 15, + 16, 16, 17, 17, 18, 18, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, + 25, 25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 34, 35, + 36, 37, 37, 38, 39, 40, 41, 41, 42, 43, 44, 45, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 98, 99, + 100, 101, 103, 104, 105, 107, 108, 109, 110, 112, 113, 114, 116, 117, 118, 120, + 121, 123, 124, 125, 127, 128, 130, 131, 133, 134, 135, 137, 138, 140, 141, 143, + 144, 146, 147, 149, 150, 152, 153, 155, 157, 158, 160, 161, 163, 165, 166, 168, + 169, 171, 173, 174, 176, 178, 179, 181, 183, 184, 186, 188, 190, 191, 193, 195, + 197, 198, 200, 202, 204, 205, 207, 209, 211, 213, 214, 216, 218, 220, 222, 224, + 226, 228, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255 }; + +static const uint8_t gamma4[] = { + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, + 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, + 9, 10, 10, 11, 11, 11, 12, 12, 13, 13, 14, 14, 14, 15, 15, 16, + 16, 17, 17, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25, + 25, 26, 27, 27, 28, 29, 29, 30, 31, 31, 32, 33, 34, 34, 35, 36, + 37, 37, 38, 39, 40, 40, 41, 42, 43, 44, 44, 45, 46, 47, 48, 49, + 50, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 81, + 82, 83, 84, 85, 86, 87, 89, 90, 91, 92, 93, 95, 96, 97, 98, 100, + 101, 102, 103, 105, 106, 107, 108, 110, 111, 112, 114, 115, 116, 118, 119, 120, + 122, 123, 125, 126, 127, 129, 130, 132, 133, 135, 136, 138, 139, 140, 142, 143, + 145, 146, 148, 149, 151, 153, 154, 156, 157, 159, 160, 162, 164, 165, 167, 168, + 170, 172, 173, 175, 177, 178, 180, 182, 183, 185, 187, 188, 190, 192, 194, 195, + 197, 199, 201, 202, 204, 206, 208, 210, 211, 213, 215, 217, 219, 221, 223, 224, + 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 245, 247, 249, 251, 253, 255 }; + +static const uint8_t gamma5[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, + 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9, + 9, 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 14, 15, 15, + 16, 16, 17, 17, 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, + 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32, 32, 33, 34, 35, 35, + 36, 37, 38, 38, 39, 40, 41, 41, 42, 43, 44, 45, 46, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 93, 94, 95, 97, 98, 99, + 100, 102, 103, 104, 105, 107, 108, 109, 111, 112, 113, 115, 116, 117, 119, 120, + 121, 123, 124, 126, 127, 128, 130, 131, 133, 134, 136, 137, 138, 140, 141, 143, + 144, 146, 147, 149, 151, 152, 154, 155, 157, 158, 160, 161, 163, 165, 166, 168, + 170, 171, 173, 174, 176, 178, 179, 181, 183, 185, 186, 188, 190, 191, 193, 195, + 197, 198, 200, 202, 204, 206, 207, 209, 211, 213, 215, 216, 218, 220, 222, 224, + 226, 228, 230, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255 }; + +static const uint8_t gamma6[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, + 9, 10, 10, 10, 11, 11, 12, 12, 12, 13, 13, 14, 14, 15, 15, 16, + 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 22, 22, 23, 23, 24, 25, + 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32, 33, 33, 34, 35, 36, + 36, 37, 38, 39, 39, 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 83, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 96, 97, 98, 99, + 101, 102, 103, 104, 106, 107, 108, 109, 111, 112, 113, 115, 116, 117, 119, 120, + 122, 123, 124, 126, 127, 129, 130, 131, 133, 134, 136, 137, 139, 140, 142, 143, + 145, 146, 148, 149, 151, 152, 154, 155, 157, 159, 160, 162, 163, 165, 167, 168, + 170, 171, 173, 175, 176, 178, 180, 181, 183, 185, 186, 188, 190, 192, 193, 195, + 197, 199, 200, 202, 204, 206, 208, 209, 211, 213, 215, 217, 219, 220, 222, 224, + 226, 228, 230, 232, 234, 236, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255 }; + +static const uint8_t gamma7[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, + 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, + 16, 16, 17, 17, 18, 18, 19, 19, 20, 21, 21, 22, 22, 23, 23, 24, + 25, 25, 26, 27, 27, 28, 29, 29, 30, 31, 31, 32, 33, 34, 34, 35, + 36, 37, 37, 38, 39, 40, 40, 41, 42, 43, 44, 45, 45, 46, 47, 48, + 49, 50, 51, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 78, 79, 80, + 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 93, 94, 95, 96, 98, 99, + 100, 101, 103, 104, 105, 106, 108, 109, 110, 112, 113, 114, 116, 117, 118, 120, + 121, 122, 124, 125, 127, 128, 130, 131, 132, 134, 135, 137, 138, 140, 141, 143, + 144, 146, 147, 149, 150, 152, 153, 155, 156, 158, 160, 161, 163, 164, 166, 168, + 169, 171, 173, 174, 176, 178, 179, 181, 183, 184, 186, 188, 189, 191, 193, 195, + 196, 198, 200, 202, 203, 205, 207, 209, 211, 213, 214, 216, 218, 220, 222, 224, + 226, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255 }; + + +#if WS2812_DITHER_NUM == 1 + const uint8_t *gamma_dither[WS2812_DITHER_NUM] = {gamma0}; +#elif WS2812_DITHER_NUM == 2 + const uint8_t *gamma_dither[WS2812_DITHER_NUM] = {gamma0,gamma1}; +#elif WS2812_DITHER_NUM == 4 + const uint8_t *gamma_dither[WS2812_DITHER_NUM] = {gamma0,gamma1,gamma2,gamma3}; +#elif WS2812_DITHER_NUM == 8 + const uint8_t *gamma_dither[WS2812_DITHER_NUM] = {gamma0,gamma1,gamma2,gamma3,gamma4,gamma5,gamma6,gamma7}; +#else + #error Invalid WS2812_DITHER_NUM value. Allowed values are 1, 2, 4, 8 +#endif + +// end of file diff --git a/arduino/ws2812_controller/ws2812_gamma.h b/arduino/ws2812_controller/ws2812_gamma.h new file mode 100644 index 0000000..84353a2 --- /dev/null +++ b/arduino/ws2812_controller/ws2812_gamma.h @@ -0,0 +1,12 @@ +// ws2812_gamma.h + +#ifndef __WS2812_GAMMA_H__ +#define __WS2812_GAMMA_H__ + +#include +#include "ws2812.h" + +extern const uint8_t *gamma_dither[WS2812_DITHER_NUM]; + +#endif + diff --git a/arduino/ws2812_controller/ws2812_i2s.cpp b/arduino/ws2812_controller/ws2812_i2s.cpp new file mode 100644 index 0000000..c0658e7 --- /dev/null +++ b/arduino/ws2812_controller/ws2812_i2s.cpp @@ -0,0 +1,169 @@ +// 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 +#include +#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>4) & 0x0f ]; + } + } + +} + +// end of file diff --git a/arduino/ws2812_controller/ws2812_i2s.h b/arduino/ws2812_controller/ws2812_i2s.h new file mode 100644 index 0000000..e40c8ba --- /dev/null +++ b/arduino/ws2812_controller/ws2812_i2s.h @@ -0,0 +1,41 @@ +// ws2812_lib.h + +#ifndef __WS2812_I2S_H__ +#define __WS2812_I2S_H__ + +#include +#include "ws2812_defs.h" + +// include C-style header +extern "C" +{ +#include "ws2812_dma.h" +}; + +typedef struct +{ + uint8_t G; // G,R,B order is determined by WS2812B + uint8_t R; + uint8_t B; +} Pixel_t; + + +class WS2812 +{ + public: + WS2812(void); + ~WS2812(void); + void init(uint16_t num_leds); + void show(Pixel_t *); + + private: + uint16_t num_leds; + uint32_t *i2s_pixels_buffer[WS2812_DITHER_NUM]; + uint32_t i2s_zeros_buffer[NUM_I2S_ZERO_WORDS]; + sdio_queue_t i2s_zeros_queue[WS2812_DITHER_NUM]; + sdio_queue_t i2s_pixels_queue[WS2812_DITHER_NUM]; +}; + +#endif + +// end of file From 3504d0b9c07f1b8c5ab45d435b76502d48229d9a Mon Sep 17 00:00:00 2001 From: Scott Lawson Date: Fri, 30 Dec 2016 22:47:06 -0700 Subject: [PATCH 5/5] Fixed typo from 255 to 256 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0aa7e94..651fce8 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ A PyQtGraph GUI will open to display the output of the visualization on the comp If you encounter any issues or have questions about this project, feel free to open a new issue. # Limitations -The visualization code currently supports up to 255 LEDs. Support for additional LEDs will be added in the near future. +The visualization code currently supports up to 256 LEDs. Support for additional LEDs will be added in the near future. # License All code in this project is released under the MIT License. \ No newline at end of file