From 0950e48925b9d6024ec02e431506e7edd460f937 Mon Sep 17 00:00:00 2001 From: Till Klocke Date: Thu, 5 Feb 2015 18:40:46 +0100 Subject: [PATCH 1/5] Added support for WS2812 LEDs as a new module --- app/include/user_config.h | 1 + app/modules/modules.h | 12 ++++++- app/modules/ws2812.c | 74 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 app/modules/ws2812.c diff --git a/app/include/user_config.h b/app/include/user_config.h index c812f2fa..0c12edcc 100644 --- a/app/include/user_config.h +++ b/app/include/user_config.h @@ -65,6 +65,7 @@ #define LUA_USE_MODULES_OW #define LUA_USE_MODULES_BIT #define LUA_USE_MODULES_MQTT +#define LUA_USE_MODULES_WS2812 #endif /* LUA_USE_MODULES */ // #define LUA_NUMBER_INTEGRAL diff --git a/app/modules/modules.h b/app/modules/modules.h index f28775d5..aaa98053 100644 --- a/app/modules/modules.h +++ b/app/modules/modules.h @@ -117,6 +117,15 @@ #define ROM_MODULES_BIT #endif +#if defined(LUA_USE_MODULES_WS2812) +#define MODULES_WS2812 "ws2812" +#define ROM_MODULES_WS2812 \ + _ROM(MODULES_WS2812, luaopen_ws2812, ws2812_map) +#else +#define ROM_MODULES_WS2812 +#endif + + #define LUA_MODULES_ROM \ ROM_MODULES_GPIO \ ROM_MODULES_PWM \ @@ -131,7 +140,8 @@ ROM_MODULES_ADC \ ROM_MODULES_UART \ ROM_MODULES_OW \ - ROM_MODULES_BIT + ROM_MODULES_BIT \ + ROM_MODULES_WS2812 #endif diff --git a/app/modules/ws2812.c b/app/modules/ws2812.c new file mode 100644 index 00000000..4cc09efc --- /dev/null +++ b/app/modules/ws2812.c @@ -0,0 +1,74 @@ +#include "lualib.h" +#include "lauxlib.h" +#include "platform.h" +#include "auxmods.h" +#include "lrotable.h" + +// ---------------------------------------------------------------------------- +// -- This WS2812 code must be compiled with -O2 to get the timing right. +// -- http://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/ + +// The ICACHE_FLASH_ATTR is there to trick the compiler and get the very first pulse width correct. +static void ICACHE_FLASH_ATTR send_ws_0(uint8_t gpio) +{ + uint8_t i; + i = 4; while (i--) GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << gpio); + i = 9; while (i--) GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << gpio); +} + +static void ICACHE_FLASH_ATTR send_ws_1(uint8_t gpio) +{ + uint8_t i; + i = 8; while (i--) GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << gpio); + i = 6; while (i--) GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << gpio); +} + +// Lua: ws2812(pin, "string") +// Byte triples in the string are interpreted as G R B values. +// gpio.ws2812(4, string.char(0, 255, 0)) uses GPIO2 and sets the first LED red. +// gpio.ws2812(3, string.char(0, 0, 255):rep(10)) uses GPIO0 and sets ten LEDs blue. +// gpio.ws2812(4, string.char(255, 0, 0, 255, 255, 255)) first LED green, second LED white. +static int ICACHE_FLASH_ATTR lgpio_ws2812(lua_State* L) +{ + const uint8_t pin = luaL_checkinteger(L, 1); + size_t length; + const char *buffer = luaL_checklstring(L, 2, &length); + + platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT); + platform_gpio_write(pin, 0); + os_delay_us(10); + + os_intr_lock(); + const char * const end = buffer + length; + while (buffer != end) { + uint8_t mask = 0x80; + while (mask) { + (*buffer & mask) ? send_ws_1(pin_num[pin]) : send_ws_0(pin_num[pin]); + mask >>= 1; + } + ++buffer; + } + os_intr_unlock(); + + return 0; +} + +#define MIN_OPT_LEVEL 2 +#include "lrodefs.h" +const LUA_REG_TYPE ws2812_map[] = +{ + { LSTRKEY( "write" ), LFUNCVAL( lgpio_ws2812 ) }, + { LNILKEY, LNILVAL} +}; + +LUALIB_API int ws2812( lua_State *L ) +{ + // Make sure that the GPIO system is initialized + LREGISTER( L, "ws2812", ws2812_map ); + return 1; +} + +// ---------------------------------------------------------------------------- + + + From c30002b8df4fb04c17bd22eafaeb2b46a144a6d9 Mon Sep 17 00:00:00 2001 From: Till Klocke Date: Thu, 5 Feb 2015 18:43:29 +0100 Subject: [PATCH 2/5] Fixed typo in method name --- app/modules/ws2812.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/modules/ws2812.c b/app/modules/ws2812.c index 4cc09efc..2f0ef3ad 100644 --- a/app/modules/ws2812.c +++ b/app/modules/ws2812.c @@ -61,9 +61,9 @@ const LUA_REG_TYPE ws2812_map[] = { LNILKEY, LNILVAL} }; -LUALIB_API int ws2812( lua_State *L ) +LUALIB_API int luaopen_ws2812( lua_State *L ) { - // Make sure that the GPIO system is initialized + // TODO: Make sure that the GPIO system is initialized LREGISTER( L, "ws2812", ws2812_map ); return 1; } From 284ee8c46ea17238935d000bf6b66db027447378 Mon Sep 17 00:00:00 2001 From: Till Klocke Date: Thu, 5 Feb 2015 18:47:08 +0100 Subject: [PATCH 3/5] Added attribution and fixed documentation in comments --- app/modules/ws2812.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/app/modules/ws2812.c b/app/modules/ws2812.c index 2f0ef3ad..4a91b3f2 100644 --- a/app/modules/ws2812.c +++ b/app/modules/ws2812.c @@ -3,6 +3,13 @@ #include "platform.h" #include "auxmods.h" #include "lrotable.h" +/** + * All this code is mostly from http://www.esp8266.com/viewtopic.php?f=21&t=1143&sid=a620a377672cfe9f666d672398415fcb + * from user Markus Gritsch. + * I just put this code into its own module and pushed into a forked repo, + * to easily create a pull request. Thanks to Markus Gritsch for the code. + * + */ // ---------------------------------------------------------------------------- // -- This WS2812 code must be compiled with -O2 to get the timing right. @@ -23,11 +30,11 @@ static void ICACHE_FLASH_ATTR send_ws_1(uint8_t gpio) i = 6; while (i--) GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << gpio); } -// Lua: ws2812(pin, "string") +// Lua: ws2812.write(pin, "string") // Byte triples in the string are interpreted as G R B values. -// gpio.ws2812(4, string.char(0, 255, 0)) uses GPIO2 and sets the first LED red. -// gpio.ws2812(3, string.char(0, 0, 255):rep(10)) uses GPIO0 and sets ten LEDs blue. -// gpio.ws2812(4, string.char(255, 0, 0, 255, 255, 255)) first LED green, second LED white. +// ws2812.write(4, string.char(0, 255, 0)) uses GPIO2 and sets the first LED red. +// ws2812.write(3, string.char(0, 0, 255):rep(10)) uses GPIO0 and sets ten LEDs blue. +// ws2812.write(4, string.char(255, 0, 0, 255, 255, 255)) first LED green, second LED white. static int ICACHE_FLASH_ATTR lgpio_ws2812(lua_State* L) { const uint8_t pin = luaL_checkinteger(L, 1); From c5d83590bd9ee1667c8139fa50bbc5bf993b0ea7 Mon Sep 17 00:00:00 2001 From: Till Klocke Date: Thu, 5 Feb 2015 19:04:09 +0100 Subject: [PATCH 4/5] Updated README.md with instructions for the ws2812 module --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 674c44e4..653a8e7c 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,7 @@ pre_build/latest/nodemcu_512k_latest.bin is removed. use pre_build/latest/nodemc #define LUA_USE_MODULES_UART #define LUA_USE_MODULES_OW #define LUA_USE_MODULES_BIT +#define LUA_USE_MODULES_WS2812 #endif /* LUA_USE_MODULES */ ... // LUA_NUMBER_INTEGRAL @@ -329,3 +330,13 @@ cu:send("hello") ds18b20 = nil package.loaded["ds18b20"]=nil ``` + +####Control a WS2812 based light strip +```lua + -- set the color of one LED on GPIO 2 to red + ws2812.write(4, string.char(0, 255, 0)) + -- set the color of 10 LEDs on GPIO 0 to blue + ws2812.write(3, string.char(0, 0, 255):rep(10)) + -- first LED green, second LED white + ws2812.write(4, string.char(255, 0, 0, 255, 255, 255)) +``` From 0bbaedac898157df23e5a9d98195fc11aac201de Mon Sep 17 00:00:00 2001 From: Till Klocke Date: Sat, 7 Feb 2015 07:05:41 +0100 Subject: [PATCH 5/5] Renamed lgpio_ws2812 to match lua method name and fixed formatting --- app/modules/ws2812.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/app/modules/ws2812.c b/app/modules/ws2812.c index 4a91b3f2..aab28e92 100644 --- a/app/modules/ws2812.c +++ b/app/modules/ws2812.c @@ -14,20 +14,25 @@ // ---------------------------------------------------------------------------- // -- This WS2812 code must be compiled with -O2 to get the timing right. // -- http://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/ - // The ICACHE_FLASH_ATTR is there to trick the compiler and get the very first pulse width correct. -static void ICACHE_FLASH_ATTR send_ws_0(uint8_t gpio) -{ +static void ICACHE_FLASH_ATTR send_ws_0(uint8_t gpio) { uint8_t i; - i = 4; while (i--) GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << gpio); - i = 9; while (i--) GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << gpio); + i = 4; + while (i--) + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << gpio); + i = 9; + while (i--) + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << gpio); } -static void ICACHE_FLASH_ATTR send_ws_1(uint8_t gpio) -{ +static void ICACHE_FLASH_ATTR send_ws_1(uint8_t gpio) { uint8_t i; - i = 8; while (i--) GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << gpio); - i = 6; while (i--) GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << gpio); + i = 8; + while (i--) + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << gpio); + i = 6; + while (i--) + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << gpio); } // Lua: ws2812.write(pin, "string") @@ -35,8 +40,7 @@ static void ICACHE_FLASH_ATTR send_ws_1(uint8_t gpio) // ws2812.write(4, string.char(0, 255, 0)) uses GPIO2 and sets the first LED red. // ws2812.write(3, string.char(0, 0, 255):rep(10)) uses GPIO0 and sets ten LEDs blue. // ws2812.write(4, string.char(255, 0, 0, 255, 255, 255)) first LED green, second LED white. -static int ICACHE_FLASH_ATTR lgpio_ws2812(lua_State* L) -{ +static int ICACHE_FLASH_ATTR ws2812_write(lua_State* L) { const uint8_t pin = luaL_checkinteger(L, 1); size_t length; const char *buffer = luaL_checklstring(L, 2, &length); @@ -64,18 +68,15 @@ static int ICACHE_FLASH_ATTR lgpio_ws2812(lua_State* L) #include "lrodefs.h" const LUA_REG_TYPE ws2812_map[] = { - { LSTRKEY( "write" ), LFUNCVAL( lgpio_ws2812 ) }, - { LNILKEY, LNILVAL} + { LSTRKEY( "write" ), LFUNCVAL( ws2812_write )}, + { LNILKEY, LNILVAL} }; -LUALIB_API int luaopen_ws2812( lua_State *L ) -{ - // TODO: Make sure that the GPIO system is initialized - LREGISTER( L, "ws2812", ws2812_map ); - return 1; +LUALIB_API int luaopen_ws2812(lua_State *L) { + // TODO: Make sure that the GPIO system is initialized + LREGISTER(L, "ws2812", ws2812_map); + return 1; } // ---------------------------------------------------------------------------- - -