/******************************************************************************* * WS2812 Driver for IdeasX * Author: curiousmuch * Description: LED driver for v0.3.X encoder * Todo: Improve pulse mode to use less CPU cycles and fluidity of cycle. *******************************************************************************/ #include "hal/ws2812.h" static const char* TAG = "ws2812 driver"; // static uint8_t pulseBuffer[100] = { 127, 135, 143, 151, 159, 166, 174, 181, 188, // 195, 202, 208, 214, 220, 225, 230, 235, 239, // 242, 246, 248, 250, 252, 253, 254, 255, 254, // 253, 252, 250, 248, 246, 242, 239, 235, 230, // 225, 220, 214, 208, 202, 195, 188, 181, 174, // 166, 159, 151, 143, 135, 127, 119, 111, 103, // 95, 88, 80, 73, 66, 59, 52, 46, 40, 34, 29, // 24, 19, 15, 12, 8, 6, 4, 2, 1, 0, 0, 0, 1, 2, // 4, 6, 8, 12, 15, 19, 24, 29, 34, 40, 46, 52, // 59, 66, 73, 80, 88, 95, 103, 111, 119}; static os_timer_t ws2812_timer; static WS2812_CONFIG_t ws2812_config; static void ws2812_timer_cb(void); static uint8_t init_buffer[3] = {0x00, 0x00, 0x00}; static void send_ws_0(void) { uint8_t time; #if WS2811_COMPATIBLE time = 6; while(time--) GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, BIT(WSGPIO)); time = 10; while(time--) GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, BIT(WSGPIO)); #else time = 2; while(time--) GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, BIT(WSGPIO)); time = 3; while(time--) GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, BIT(WSGPIO)); #endif } static void send_ws_1(void) { uint8_t time; #if WS2811_COMPATIBLE time = 10; while(time--) GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, BIT(WSGPIO)); time = 6; while(time--) GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, BIT(WSGPIO)); #else time = 5; while(time--) GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, BIT(WSGPIO)); time = 4; while(time--) GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, BIT(WSGPIO)); #endif } void WS2812_OutBuffer(int8_t * buffer, uint16_t length) { ETS_INTR_LOCK(); // why is this different than a normal disable interupts again? uint16_t i; GPIO_OUTPUT_SET(GPIO_ID_PIN(WSGPIO), 0); // set gpio as output (redundent?) for( i = 0; i < length; i++ ) { uint8_t mask = 0x80; uint8_t byte = buffer[i]; while (mask) { if( byte & mask ) send_ws_1(); else send_ws_0(); mask >>= 1; } } ETS_INTR_UNLOCK(); } void ICACHE_FLASH_ATTR WS2812_SetColor(WS2812_COLOR_et color, WS2812_PATTERN_et pattern) { // return if the color is already set if (color == ws2812_config.color && pattern == ws2812_config.pattern) { return; } ws2812_config.color = color; // store color ws2812_config.pattern = pattern; // store pattern ws2812_config.led_state = 1; // reset led update timer state ws2812_config.direction = WS2812_UP; // set direction for pulse os_timer_disarm(&ws2812_timer); // disarm health publish timer switch (ws2812_config.color) { case WS2812_OFF: { ws2812_config.color_mask[WS2812_RED_INDEX] = 0x00; ws2812_config.color_mask[WS2812_GREEN_INDEX] = 0x00; ws2812_config.color_mask[WS2812_BLUE_INDEX] = 0x00; break; } case WS2812_RED: { ws2812_config.color_mask[WS2812_RED_INDEX] = 0xFF; ws2812_config.color_mask[WS2812_GREEN_INDEX] = 0x00; ws2812_config.color_mask[WS2812_BLUE_INDEX] = 0x00; break; } case WS2812_BLUE: { ws2812_config.color_mask[WS2812_RED_INDEX] = 0x00; ws2812_config.color_mask[WS2812_GREEN_INDEX] = 0x00; ws2812_config.color_mask[WS2812_BLUE_INDEX] = 0xFF; break; } case WS2812_GREEN: { ws2812_config.color_mask[WS2812_RED_INDEX] = 0x00; ws2812_config.color_mask[WS2812_GREEN_INDEX] = 0xFF; ws2812_config.color_mask[WS2812_BLUE_INDEX] = 0x00; break; } case WS2812_MAGENTA: { ws2812_config.color_mask[WS2812_RED_INDEX] = 0xFF; ws2812_config.color_mask[WS2812_GREEN_INDEX] = 0x00; ws2812_config.color_mask[WS2812_BLUE_INDEX] = 0xFF; break; } case WS2812_ORANGE: { ws2812_config.color_mask[WS2812_RED_INDEX] = 0xFF; ws2812_config.color_mask[WS2812_GREEN_INDEX] = 0xA5; ws2812_config.color_mask[WS2812_BLUE_INDEX] = 0x00; break; } default: { ws2812_config.color_mask[WS2812_RED_INDEX] = 0x00; ws2812_config.color_mask[WS2812_GREEN_INDEX] = 0x00; ws2812_config.color_mask[WS2812_BLUE_INDEX] = 0x00; break; } } switch (ws2812_config.pattern) { case(WS2812_SOLID): { //WS2812_OutBuffer(init_buffer, 3); //os_delay_us(70); WS2812_OutBuffer(ws2812_config.color_mask, 3); // break; } case(WS2812_PULSE): { os_timer_setfn(&ws2812_timer, (os_timer_func_t *)ws2812_timer_cb, NULL); os_timer_arm(&ws2812_timer, WS2812_REFRESH_INTERVAL, 1); break; } default: { break; } } return; } void ws2812_timer_cb(void) { // calculate color fade uint8_t led_state = ws2812_config.led_state; uint8_t tempBuffer[3] = {ws2812_config.color_mask[WS2812_GREEN_INDEX] / led_state, ws2812_config.color_mask[WS2812_RED_INDEX] / led_state, ws2812_config.color_mask[WS2812_BLUE_INDEX] / led_state}; // Debuging Information //ESP_LOGV(TAG, "WS2812 Timer [led_state]: %d", ws2812_config.led_state); //ESP_LOGV(TAG, "WS2812 Timer [tempBuffer] %d:%d:%d", tempBuffer[0], tempBuffer[1], tempBuffer[2]); WS2812_OutBuffer(tempBuffer, 3); // send color to LED // increase / decrease scaling factor for LED color if (ws2812_config.direction == WS2812_UP) { ws2812_config.led_state++; if (ws2812_config.led_state == 50) ws2812_config.direction = WS2812_DOWN; } else { ws2812_config.led_state--; if (ws2812_config.led_state == 1) ws2812_config.direction = WS2812_UP; } }