ws2801.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #include "module.h"
  2. #include "lauxlib.h"
  3. #include "platform.h"
  4. #include "c_stdlib.h"
  5. #include "c_string.h"
  6. /**
  7. * Code is based on https://github.com/CHERTS/esp8266-devkit/blob/master/Espressif/examples/EspLightNode/user/ws2801.c
  8. * and provides a similar api as the ws2812 module.
  9. * The current implementation allows the caller to use
  10. * any combination of GPIO0, GPIO2, GPIO4, GPIO5 as clock and data.
  11. */
  12. #define PIN_CLK_DEFAULT 0
  13. #define PIN_DATA_DEFAULT 2
  14. static uint32_t ws2801_bit_clk;
  15. static uint32_t ws2801_bit_data;
  16. static void ws2801_byte(uint8_t n) {
  17. uint8_t bitmask;
  18. for (bitmask = 0x80; bitmask !=0 ; bitmask >>= 1) {
  19. if (n & bitmask) {
  20. GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, ws2801_bit_data);
  21. } else {
  22. GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, ws2801_bit_data);
  23. }
  24. GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, ws2801_bit_clk);
  25. GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, ws2801_bit_clk);
  26. }
  27. }
  28. static void ws2801_color(uint8_t r, uint8_t g, uint8_t b) {
  29. ws2801_byte(r);
  30. ws2801_byte(g);
  31. ws2801_byte(b);
  32. }
  33. static void ws2801_strip(uint8_t const * data, uint16_t len) {
  34. while (len--) {
  35. ws2801_byte(*(data++));
  36. }
  37. GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, ws2801_bit_data);
  38. }
  39. static void enable_pin_mux(int pin) {
  40. // The API only supports setting PERIPHS_IO_MUX on GPIO 0, 2, 4, 5
  41. switch (pin) {
  42. case 0:
  43. PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);
  44. break;
  45. case 2:
  46. PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
  47. break;
  48. case 4:
  49. PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4);
  50. break;
  51. case 5:
  52. PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5);
  53. break;
  54. default:
  55. break;
  56. }
  57. }
  58. /* Lua: ws2801.init(pin_clk, pin_data)
  59. * Sets up the GPIO pins
  60. *
  61. * ws2801.init(0, 2) uses GPIO0 as clock and GPIO2 as data.
  62. * This is the default behavior.
  63. */
  64. static int ICACHE_FLASH_ATTR ws2801_init_lua(lua_State* L) {
  65. uint32_t pin_clk;
  66. uint32_t pin_data;
  67. uint32_t func_gpio_clk;
  68. uint32_t func_gpio_data;
  69. if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) {
  70. // Use default pins if the input is omitted
  71. pin_clk = PIN_CLK_DEFAULT;
  72. pin_data = PIN_DATA_DEFAULT;
  73. } else {
  74. pin_clk = luaL_checkinteger(L, 1);
  75. pin_data = luaL_checkinteger(L, 2);
  76. }
  77. ws2801_bit_clk = 1 << pin_clk;
  78. ws2801_bit_data = 1 << pin_data;
  79. os_delay_us(10);
  80. //Set GPIO pins to output mode
  81. enable_pin_mux(pin_clk);
  82. enable_pin_mux(pin_data);
  83. //Set both GPIOs low low
  84. gpio_output_set(0, ws2801_bit_clk | ws2801_bit_data, ws2801_bit_clk | ws2801_bit_data, 0);
  85. os_delay_us(10);
  86. }
  87. /* Lua: ws2801.write(pin, "string")
  88. * Byte triples in the string are interpreted as R G B values.
  89. * This function does not corrupt your buffer.
  90. *
  91. * ws2801.write(string.char(255, 0, 0)) sets the first LED red.
  92. * ws2801.write(string.char(0, 0, 255):rep(10)) sets ten LEDs blue.
  93. * ws2801.write(string.char(0, 255, 0, 255, 255, 255)) first LED green, second LED white.
  94. */
  95. static int ICACHE_FLASH_ATTR ws2801_writergb(lua_State* L) {
  96. size_t length;
  97. const char *buffer = luaL_checklstring(L, 1, &length);
  98. os_delay_us(10);
  99. ets_intr_lock();
  100. ws2801_strip(buffer, length);
  101. ets_intr_unlock();
  102. return 0;
  103. }
  104. static const LUA_REG_TYPE ws2801_map[] =
  105. {
  106. { LSTRKEY( "write" ), LFUNCVAL( ws2801_writergb )},
  107. { LSTRKEY( "init" ), LFUNCVAL( ws2801_init_lua )},
  108. { LNILKEY, LNILVAL}
  109. };
  110. NODEMCU_MODULE(WS2801, "ws2801", ws2801_map, NULL);