tm1829.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. #include "module.h"
  2. #include "lauxlib.h"
  3. #include "platform.h"
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include "user_interface.h"
  7. #include "pixbuf.h"
  8. static inline uint32_t _getCycleCount(void) {
  9. uint32_t cycles;
  10. __asm__ __volatile__("rsr %0,ccount":"=a" (cycles));
  11. return cycles;
  12. }
  13. // This algorithm reads the cpu clock cycles to calculate the correct
  14. // pulse widths. It works in both 80 and 160 MHz mode.
  15. static void ICACHE_RAM_ATTR tm1829_write_to_pin(uint8_t pin, const uint8_t *pixels, size_t length) {
  16. const uint8_t *p, *end;
  17. uint8_t phasergb = 0;
  18. p = pixels;
  19. end = p + length;
  20. const uint32_t t0l = (1000 * system_get_cpu_freq()) / 3333; // 0.390us (spec=0.35 +- 0.15)
  21. const uint32_t t1l = (1000 * system_get_cpu_freq()) / 1250; // 0.800us (spec=0.70 +- 0.15)
  22. const uint32_t ttot = (1000 * system_get_cpu_freq()) / 800; // 1.25us
  23. while (p != end) {
  24. register int i;
  25. register uint8_t pixel = *p++;
  26. if ((phasergb == 0) && (pixel == 0xFF)) {
  27. // clamp initial byte value to avoid constant-current shenanigans. Yuck!
  28. pixel = 0xFE;
  29. }
  30. if (++phasergb == 3) {
  31. phasergb = 0;
  32. }
  33. ets_intr_lock();
  34. for (i = 7; i >= 0; i--) {
  35. register uint32_t pin_mask = 1 << pin;
  36. // Select low time
  37. register uint32_t tl = ((pixel >> i) & 1) ? t1l : t0l;
  38. register uint32_t t1, t2;
  39. register uint32_t t = _getCycleCount();
  40. t1 = t + tl;
  41. t2 = t + ttot;
  42. GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pin_mask); // Set pin low
  43. while (_getCycleCount() < t1);
  44. GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pin_mask); // Set pin high
  45. while (_getCycleCount() < t2);
  46. }
  47. ets_intr_unlock();
  48. }
  49. }
  50. // Lua: tm1829.write(pin, "string")
  51. // Byte triples in the string are interpreted as GRB values.
  52. static int ICACHE_FLASH_ATTR tm1829_write(lua_State* L)
  53. {
  54. const uint8_t pin = luaL_checkinteger(L, 1);
  55. const uint8_t *pixels;
  56. size_t length;
  57. switch(lua_type(L, 3)) {
  58. case LUA_TSTRING: {
  59. pixels = luaL_checklstring(L, 2, &length);
  60. break;
  61. }
  62. case LUA_TUSERDATA: {
  63. pixbuf *buffer = pixbuf_from_lua_arg(L, 2);
  64. luaL_argcheck(L, pixbuf_channels(buffer) == 3, 2, "Bad pixbuf format");
  65. pixels = buffer->values;
  66. length = 3 * buffer->npix;
  67. break;
  68. }
  69. default:
  70. return luaL_argerror(L, 2, "String or pixbuf expected");
  71. }
  72. // Initialize the output pin and wait a bit
  73. platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT);
  74. platform_gpio_write(pin, 1);
  75. // Send the buffer
  76. tm1829_write_to_pin(pin_num[pin], pixels, length);
  77. os_delay_us(500); // reset time
  78. return 0;
  79. }
  80. LROT_BEGIN(tm1829, NULL, 0)
  81. LROT_FUNCENTRY( write, tm1829_write )
  82. LROT_END(tm1829, NULL, 0)
  83. int luaopen_tm1829(lua_State *L) {
  84. // TODO: Make sure that the GPIO system is initialized
  85. return 0;
  86. }
  87. NODEMCU_MODULE(TM1829, "tm1829", tm1829, luaopen_tm1829);