Merge branch 'master' into patch-1
This commit is contained in:
commit
daf08d45bb
@ -63,10 +63,10 @@ If `pip` is not found try using `python -m pip install` instead.
|
|||||||
## Arduino dependencies
|
## 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.
|
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.
|
<!-- This [ws2812b i2s library](https://github.com/JoDaNl/esp8266_ws2812_i2s) must be downloaded and installed in the Arduino libraries folder.
|
||||||
|
-->
|
||||||
# Hardware Connections
|
# 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 <!-- 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 RX1 pin on the ESP8266 module should be connected to the data input pin of the ws2812b LED strip (often labelled DIN or D0).
|
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.
|
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 256 LEDs. Support for additional LEDs will be added in the near future.
|
||||||
|
|
||||||
# License
|
# License
|
||||||
All code in this project is released under the MIT License.
|
All code in this project is released under the MIT License.
|
26
arduino/ws2812_controller/ws2812.h
Normal file
26
arduino/ws2812_controller/ws2812.h
Normal file
@ -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
|
@ -3,10 +3,12 @@
|
|||||||
#include <WebSocketsServer.h>
|
#include <WebSocketsServer.h>
|
||||||
#include <Hash.h>
|
#include <Hash.h>
|
||||||
#include <WiFiUdp.h>
|
#include <WiFiUdp.h>
|
||||||
#include <ws2812_i2s.h>
|
#include "ws2812_i2s.h"
|
||||||
|
|
||||||
// Set this to the number of LEDs in your LED strip
|
// Set this to the number of LEDs in your LED strip
|
||||||
#define NUM_LEDS 50
|
|
||||||
|
#define NUM_LEDS 60
|
||||||
|
// Maximum number of packets to hold in the buffer. Don't change this.
|
||||||
#define BUFFER_LEN 1024
|
#define BUFFER_LEN 1024
|
||||||
#define PRINT_FPS 1
|
#define PRINT_FPS 1
|
||||||
|
|
||||||
|
172
arduino/ws2812_controller/ws2812_defs.h
Normal file
172
arduino/ws2812_controller/ws2812_defs.h
Normal file
@ -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 <stdint.h>
|
||||||
|
|
||||||
|
// 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
|
102
arduino/ws2812_controller/ws2812_dma.c
Normal file
102
arduino/ws2812_controller/ws2812_dma.c
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// ws2812_init.c
|
||||||
|
|
||||||
|
// C-based helper function for initilalizing
|
||||||
|
// the I2S system
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#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<<SLC_MODE_S));
|
||||||
|
SET_PERI_REG_MASK(SLC_CONF0,(1<<SLC_MODE_S));
|
||||||
|
SET_PERI_REG_MASK(SLC_RX_DSCR_CONF,SLC_INFOR_NO_REPLACE|SLC_TOKEN_NO_REPLACE);
|
||||||
|
CLEAR_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_RX_FILL_EN|SLC_RX_EOF_MODE | SLC_RX_FILL_MODE);
|
||||||
|
|
||||||
|
// configure DMA descriptor
|
||||||
|
CLEAR_PERI_REG_MASK(SLC_RX_LINK,SLC_RXLINK_DESCADDR_MASK);
|
||||||
|
SET_PERI_REG_MASK(SLC_RX_LINK, ((uint32)i2s_pixels_queue) & SLC_RXLINK_DESCADDR_MASK);
|
||||||
|
|
||||||
|
#if WS2812_USE_INTERRUPT == 1
|
||||||
|
// Attach the DMA interrupt
|
||||||
|
ets_isr_attach(ETS_SLC_INUM, (int_handler_t)ws2812_isr , (void *)0);
|
||||||
|
|
||||||
|
//Enable DMA operation intr
|
||||||
|
// WRITE_PERI_REG(SLC_INT_ENA, SLC_RX_EOF_INT_ENA);
|
||||||
|
//clear any interrupt flags that are set
|
||||||
|
WRITE_PERI_REG(SLC_INT_CLR, 0xffffffff);
|
||||||
|
///enable DMA intr in cpu
|
||||||
|
ets_isr_unmask(1<<ETS_SLC_INUM);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Start transmission
|
||||||
|
SET_PERI_REG_MASK(SLC_RX_LINK, SLC_RXLINK_START);
|
||||||
|
|
||||||
|
//Init pins to i2s functions
|
||||||
|
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_I2SO_DATA);
|
||||||
|
|
||||||
|
//Enable clock to i2s subsystem
|
||||||
|
i2c_writeReg_Mask_def(i2c_bbpll, i2c_bbpll_en_audio_clock_out, 1);
|
||||||
|
|
||||||
|
//Reset I2S subsystem
|
||||||
|
CLEAR_PERI_REG_MASK(I2SCONF,I2S_I2S_RESET_MASK);
|
||||||
|
SET_PERI_REG_MASK(I2SCONF,I2S_I2S_RESET_MASK);
|
||||||
|
CLEAR_PERI_REG_MASK(I2SCONF,I2S_I2S_RESET_MASK);
|
||||||
|
|
||||||
|
//Select 16bits per channel (FIFO_MOD=0), no DMA access (FIFO only)
|
||||||
|
CLEAR_PERI_REG_MASK(I2S_FIFO_CONF, I2S_I2S_DSCR_EN|(I2S_I2S_RX_FIFO_MOD<<I2S_I2S_RX_FIFO_MOD_S)|(I2S_I2S_TX_FIFO_MOD<<I2S_I2S_TX_FIFO_MOD_S));
|
||||||
|
//Enable DMA in i2s subsystem
|
||||||
|
SET_PERI_REG_MASK(I2S_FIFO_CONF, I2S_I2S_DSCR_EN);
|
||||||
|
|
||||||
|
//trans master&rece slave,MSB shift,right_first,msb right
|
||||||
|
CLEAR_PERI_REG_MASK(I2SCONF, I2S_TRANS_SLAVE_MOD|
|
||||||
|
(I2S_BITS_MOD<<I2S_BITS_MOD_S)|
|
||||||
|
(I2S_BCK_DIV_NUM <<I2S_BCK_DIV_NUM_S)|
|
||||||
|
(I2S_CLKM_DIV_NUM<<I2S_CLKM_DIV_NUM_S));
|
||||||
|
SET_PERI_REG_MASK(I2SCONF, I2S_RIGHT_FIRST|I2S_MSB_RIGHT|I2S_RECE_SLAVE_MOD|
|
||||||
|
I2S_RECE_MSB_SHIFT|I2S_TRANS_MSB_SHIFT|
|
||||||
|
(((WS_I2S_BCK-1)&I2S_BCK_DIV_NUM )<<I2S_BCK_DIV_NUM_S)|
|
||||||
|
(((WS_I2S_DIV-1)&I2S_CLKM_DIV_NUM)<<I2S_CLKM_DIV_NUM_S));
|
||||||
|
|
||||||
|
#if WS2812_USE_INTERRUPT == 1
|
||||||
|
//clear int
|
||||||
|
SET_PERI_REG_MASK(I2SINT_CLR, I2S_I2S_RX_WFULL_INT_CLR|I2S_I2S_PUT_DATA_INT_CLR|I2S_I2S_TAKE_DATA_INT_CLR);
|
||||||
|
CLEAR_PERI_REG_MASK(I2SINT_CLR, I2S_I2S_RX_WFULL_INT_CLR|I2S_I2S_PUT_DATA_INT_CLR|I2S_I2S_TAKE_DATA_INT_CLR);
|
||||||
|
//enable int
|
||||||
|
SET_PERI_REG_MASK(I2SINT_ENA, I2S_I2S_RX_REMPTY_INT_ENA|I2S_I2S_RX_TAKE_DATA_INT_ENA);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Start transmission
|
||||||
|
SET_PERI_REG_MASK(I2SCONF,I2S_I2S_TX_START);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// end of file
|
||||||
|
|
25
arduino/ws2812_controller/ws2812_dma.h
Normal file
25
arduino/ws2812_controller/ws2812_dma.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// ws2812_dma.h
|
||||||
|
|
||||||
|
#ifndef __WS2812_DMA_H__
|
||||||
|
#define __WS2812_DMA_H__
|
||||||
|
|
||||||
|
// type definition taken from : sdio_slv.h
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t blocksize:12;
|
||||||
|
uint32_t datalen:12;
|
||||||
|
uint32_t unused:5;
|
||||||
|
uint32_t sub_sof:1;
|
||||||
|
uint32_t eof:1;
|
||||||
|
uint32_t owner:1;
|
||||||
|
uint32_t buf_ptr;
|
||||||
|
uint32_t next_link_ptr;
|
||||||
|
} sdio_queue_t;
|
||||||
|
|
||||||
|
// -----------------------------------------------------
|
||||||
|
|
||||||
|
extern void ws2812_dma(sdio_queue_t *);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
165
arduino/ws2812_controller/ws2812_gamma.cpp
Normal file
165
arduino/ws2812_controller/ws2812_gamma.cpp
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
// ws2812_gamma.cpp
|
||||||
|
//
|
||||||
|
// dithering tables with gamma correction
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#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
|
12
arduino/ws2812_controller/ws2812_gamma.h
Normal file
12
arduino/ws2812_controller/ws2812_gamma.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// ws2812_gamma.h
|
||||||
|
|
||||||
|
#ifndef __WS2812_GAMMA_H__
|
||||||
|
#define __WS2812_GAMMA_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "ws2812.h"
|
||||||
|
|
||||||
|
extern const uint8_t *gamma_dither[WS2812_DITHER_NUM];
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
169
arduino/ws2812_controller/ws2812_i2s.cpp
Normal file
169
arduino/ws2812_controller/ws2812_i2s.cpp
Normal file
@ -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 <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
|
41
arduino/ws2812_controller/ws2812_i2s.h
Normal file
41
arduino/ws2812_controller/ws2812_i2s.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// ws2812_lib.h
|
||||||
|
|
||||||
|
#ifndef __WS2812_I2S_H__
|
||||||
|
#define __WS2812_I2S_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#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
|
@ -15,7 +15,7 @@ pixels = np.tile(1, (3, config.N_PIXELS))
|
|||||||
|
|
||||||
def update():
|
def update():
|
||||||
global pixels, _prev_pixels
|
global pixels, _prev_pixels
|
||||||
pixels = np.clip(pixels, 0, 255)
|
pixels = np.clip(pixels, 0, 255).astype(int)
|
||||||
m = ''
|
m = ''
|
||||||
p = _gamma[pixels] if config.GAMMA_CORRECTION else np.copy(pixels)
|
p = _gamma[pixels] if config.GAMMA_CORRECTION else np.copy(pixels)
|
||||||
for i in range(config.N_PIXELS):
|
for i in range(config.N_PIXELS):
|
||||||
@ -27,6 +27,19 @@ def update():
|
|||||||
_sock.sendto(m.encode(), (config.UDP_IP, config.UDP_PORT))
|
_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__':
|
if __name__ == '__main__':
|
||||||
|
import time
|
||||||
|
# Turn all pixels off
|
||||||
pixels *= 0
|
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)
|
||||||
|
|
||||||
|
@ -75,13 +75,13 @@ b_filt = dsp.ExpFilter(np.tile(0.01, config.N_PIXELS // 2),
|
|||||||
alpha_decay=0.25, alpha_rise=0.99)
|
alpha_decay=0.25, alpha_rise=0.99)
|
||||||
p_filt = dsp.ExpFilter(np.tile(1, (3, config.N_PIXELS // 2)),
|
p_filt = dsp.ExpFilter(np.tile(1, (3, config.N_PIXELS // 2)),
|
||||||
alpha_decay=0.05, alpha_rise=0.8)
|
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),
|
gain = dsp.ExpFilter(np.tile(0.01, config.N_FFT_BINS),
|
||||||
alpha_decay=0.001, alpha_rise=0.99)
|
alpha_decay=0.001, alpha_rise=0.99)
|
||||||
|
|
||||||
|
|
||||||
def largest_indices(ary, n):
|
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()
|
flat = ary.flatten()
|
||||||
indices = np.argpartition(flat, -n)[-n:]
|
indices = np.argpartition(flat, -n)[-n:]
|
||||||
indices = indices[np.argsort(-flat[indices])]
|
indices = indices[np.argsort(-flat[indices])]
|
||||||
@ -89,11 +89,12 @@ def largest_indices(ary, n):
|
|||||||
|
|
||||||
|
|
||||||
def visualize_max(y):
|
def visualize_max(y):
|
||||||
|
"""Experimental sandbox effect. Not recommended for use"""
|
||||||
y = np.copy(interpolate(y, config.N_PIXELS // 2)) * 255.0
|
y = np.copy(interpolate(y, config.N_PIXELS // 2)) * 255.0
|
||||||
ind = largest_indices(y, 15)
|
ind = largest_indices(y, 15)
|
||||||
y[ind] *= -1
|
y[ind] *= -1.0
|
||||||
y[y > 0] = 0
|
y[y > 0] = 0.0
|
||||||
y[ind] *= -1
|
y[ind] *= -1.0
|
||||||
# Blur the color channels with different strengths
|
# Blur the color channels with different strengths
|
||||||
r = gaussian_filter1d(y, sigma=0.25)
|
r = gaussian_filter1d(y, sigma=0.25)
|
||||||
g = gaussian_filter1d(y, sigma=0.10)
|
g = gaussian_filter1d(y, sigma=0.10)
|
||||||
@ -111,14 +112,15 @@ def visualize_max(y):
|
|||||||
led.pixels[0, :] = pixel_r
|
led.pixels[0, :] = pixel_r
|
||||||
led.pixels[1, :] = pixel_g
|
led.pixels[1, :] = pixel_g
|
||||||
led.pixels[2, :] = pixel_b
|
led.pixels[2, :] = pixel_b
|
||||||
|
led.update()
|
||||||
# Update the GUI plots
|
# Update the GUI plots
|
||||||
GUI.curve[0][0].setData(y=pixel_r)
|
GUI.curve[0][0].setData(y=pixel_r)
|
||||||
GUI.curve[0][1].setData(y=pixel_g)
|
GUI.curve[0][1].setData(y=pixel_g)
|
||||||
GUI.curve[0][2].setData(y=pixel_b)
|
GUI.curve[0][2].setData(y=pixel_b)
|
||||||
led.update()
|
|
||||||
|
|
||||||
|
|
||||||
def visualize_scroll(y):
|
def visualize_scroll(y):
|
||||||
|
"""Effect that originates in the center and scrolls outwards"""
|
||||||
global p
|
global p
|
||||||
y = gaussian_filter1d(y, sigma=1.0)**3.0
|
y = gaussian_filter1d(y, sigma=1.0)**3.0
|
||||||
y = np.copy(y)
|
y = np.copy(y)
|
||||||
@ -134,11 +136,17 @@ def visualize_scroll(y):
|
|||||||
p[0, 0] = r
|
p[0, 0] = r
|
||||||
p[1, 0] = g
|
p[1, 0] = g
|
||||||
p[2, 0] = b
|
p[2, 0] = b
|
||||||
|
# Update the LED strip
|
||||||
led.pixels = np.concatenate((p[:, ::-1], p), axis=1)
|
led.pixels = np.concatenate((p[:, ::-1], p), axis=1)
|
||||||
led.update()
|
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):
|
def visualize_energy(y):
|
||||||
|
"""Effect that expands from the center with increasing sound energy"""
|
||||||
global p
|
global p
|
||||||
y = gaussian_filter1d(y, sigma=1.0)**3.0
|
y = gaussian_filter1d(y, sigma=1.0)**3.0
|
||||||
gain.update(y)
|
gain.update(y)
|
||||||
@ -147,22 +155,28 @@ def visualize_energy(y):
|
|||||||
r = int(np.mean(y[:len(y) // 3]))
|
r = int(np.mean(y[:len(y) // 3]))
|
||||||
g = int(np.mean(y[len(y) // 3: 2 * len(y) // 3]))
|
g = int(np.mean(y[len(y) // 3: 2 * len(y) // 3]))
|
||||||
b = int(np.mean(y[2 * len(y) // 3:]))
|
b = int(np.mean(y[2 * len(y) // 3:]))
|
||||||
p[0, :r] = 255
|
p[0, :r] = 255.0
|
||||||
p[0, r:] = 0
|
p[0, r:] = 0.0
|
||||||
p[1, :g] = 255
|
p[1, :g] = 255.0
|
||||||
p[1, g:] = 0
|
p[1, g:] = 0.0
|
||||||
p[2, :b] = 255
|
p[2, :b] = 255.0
|
||||||
p[2, b:] = 0
|
p[2, b:] = 0.0
|
||||||
p_filt.update(p)
|
p_filt.update(p)
|
||||||
p = p_filt.value.astype(int)
|
p = p_filt.value.astype(int)
|
||||||
p[0, :] = gaussian_filter1d(p[0, :], sigma=4.0)
|
p[0, :] = gaussian_filter1d(p[0, :], sigma=4.0)
|
||||||
p[1, :] = gaussian_filter1d(p[1, :], sigma=4.0)
|
p[1, :] = gaussian_filter1d(p[1, :], sigma=4.0)
|
||||||
p[2, :] = gaussian_filter1d(p[2, :], 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.pixels = np.concatenate((p[:, ::-1], p), axis=1)
|
||||||
led.update()
|
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):
|
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
|
y = np.copy(interpolate(y, config.N_PIXELS // 2)) * 255.0
|
||||||
# Blur the color channels with different strengths
|
# Blur the color channels with different strengths
|
||||||
r = gaussian_filter1d(y, sigma=0.25)
|
r = gaussian_filter1d(y, sigma=0.25)
|
||||||
@ -179,11 +193,11 @@ def visualize_spectrum(y):
|
|||||||
led.pixels[0, :] = pixel_r
|
led.pixels[0, :] = pixel_r
|
||||||
led.pixels[1, :] = pixel_g
|
led.pixels[1, :] = pixel_g
|
||||||
led.pixels[2, :] = pixel_b
|
led.pixels[2, :] = pixel_b
|
||||||
|
led.update()
|
||||||
# Update the GUI plots
|
# Update the GUI plots
|
||||||
GUI.curve[0][0].setData(y=pixel_r)
|
GUI.curve[0][0].setData(y=pixel_r)
|
||||||
GUI.curve[0][1].setData(y=pixel_g)
|
GUI.curve[0][1].setData(y=pixel_g)
|
||||||
GUI.curve[0][2].setData(y=pixel_b)
|
GUI.curve[0][2].setData(y=pixel_b)
|
||||||
led.update()
|
|
||||||
|
|
||||||
|
|
||||||
mel_gain = dsp.ExpFilter(np.tile(1e-1, config.N_FFT_BINS),
|
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):
|
def microphone_update(stream):
|
||||||
global y_roll, prev_rms, prev_exp
|
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,
|
y = np.fromstring(stream.read(samples_per_frame,
|
||||||
exception_on_overflow=False), dtype=np.int16)
|
exception_on_overflow=False), dtype=np.int16)
|
||||||
y = y / 2.0**15
|
y = y / 2.0**15
|
||||||
@ -209,19 +223,25 @@ def microphone_update(stream):
|
|||||||
led.pixels = np.tile(0, (3, config.N_PIXELS))
|
led.pixels = np.tile(0, (3, config.N_PIXELS))
|
||||||
led.update()
|
led.update()
|
||||||
else:
|
else:
|
||||||
|
# Transform audio input into the frequency domain
|
||||||
XS, YS = dsp.fft(y_data, window=np.hamming)
|
XS, YS = dsp.fft(y_data, window=np.hamming)
|
||||||
|
# Remove half of the FFT data because of symmetry
|
||||||
YS = YS[:len(YS) // 2]
|
YS = YS[:len(YS) // 2]
|
||||||
XS = XS[:len(XS) // 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
|
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
|
YS = np.sum(YS, axis=0)**2.0
|
||||||
mel = YS**0.5
|
mel = YS**0.5
|
||||||
mel = gaussian_filter1d(mel, sigma=1.0)
|
mel = gaussian_filter1d(mel, sigma=1.0)
|
||||||
|
# Normalize the Mel filterbank to make it volume independent
|
||||||
mel_gain.update(np.max(mel))
|
mel_gain.update(np.max(mel))
|
||||||
mel = mel / mel_gain.value
|
mel = mel / mel_gain.value
|
||||||
visualize_spectrum(mel)
|
# Visualize the filterbank output
|
||||||
|
# visualize_spectrum(mel)
|
||||||
# visualize_max(mel)
|
# visualize_max(mel)
|
||||||
# visualize_scroll(mel)
|
# visualize_scroll(mel)
|
||||||
# visualize_energy(mel)
|
visualize_energy(mel)
|
||||||
GUI.app.processEvents()
|
GUI.app.processEvents()
|
||||||
print('FPS {:.0f} / {:.0f}'.format(frames_per_second(), config.FPS))
|
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__':
|
if __name__ == '__main__':
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
|
# Create GUI plot for visualizing LED strip output
|
||||||
GUI = gui.GUI(width=800, height=400, title='Audio Visualization')
|
GUI = gui.GUI(width=800, height=400, title='Audio Visualization')
|
||||||
# Audio plot
|
|
||||||
GUI.add_plot('Color Channels')
|
GUI.add_plot('Color Channels')
|
||||||
r_pen = pg.mkPen((255, 30, 30, 200), width=6)
|
r_pen = pg.mkPen((255, 30, 30, 200), width=6)
|
||||||
g_pen = pg.mkPen((30, 255, 30, 200), width=6)
|
g_pen = pg.mkPen((30, 255, 30, 200), width=6)
|
||||||
|
Loading…
Reference in New Issue
Block a user