ESP32 Native version of Blinky, featureful controller code for WS2811/WS2812/NeoPixels
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
3.9KB

  1. static const char *TAG = "spi_leds";
  2. #include <esp_log.h>
  3. #include <string.h>
  4. #include <driver/gpio.h>
  5. #include <soc/io_mux_reg.h>
  6. #include "spi_leds.hpp"
  7. #define RET_ON_ERR(func, err) { if (err) { ESP_LOGE(TAG, #func ": %d", err); return; } }
  8. // LCD is using bus 2 in quad SPI mode
  9. SPI_LEDs::SPI_LEDs(int _gpio, int length) :
  10. LEDStrip(length),
  11. host(SPI3_HOST), gpio(_gpio), device(NULL),
  12. out_buf(NULL)
  13. {
  14. int ret;
  15. spi_bus_config_t buscfg = {
  16. .mosi_io_num = gpio,
  17. .miso_io_num = -1,
  18. .sclk_io_num = -1,
  19. .data2_io_num = -1,
  20. .data3_io_num = -1,
  21. .data4_io_num = -1,
  22. .data5_io_num = -1,
  23. .data6_io_num = -1,
  24. .data7_io_num = -1,
  25. .max_transfer_sz = 0, // 4092 (?)
  26. .flags = SPICOMMON_BUSFLAG_MASTER,
  27. .intr_flags = 0,
  28. };
  29. // Initialize the SPI bus
  30. ret = spi_bus_initialize(host, &buscfg, SPI_DMA_CH_AUTO);
  31. RET_ON_ERR(spi_bus_initialize, ret);
  32. // Invert the signal!
  33. // TODO: Clean way thru API?
  34. uint32_t *GPIO39_REG = (uint32_t*)(void*)(0x3f404000 + 0x0554 + (4 * 39));
  35. *GPIO39_REG |= 0x200;
  36. spi_device_interface_config_t devcfg = {
  37. .command_bits = 0,
  38. .address_bits = 0,
  39. .dummy_bits = 0,
  40. .mode = 0, // moot
  41. .duty_cycle_pos = 0, // moot
  42. .cs_ena_pretrans = 0, // moot
  43. .cs_ena_posttrans = 0, // moot
  44. // Datasheet implies 3.2 MHz => 1.25 us / 4
  45. // We can get away with 4.4_ MHz => 900 ns / 4
  46. // HOWEVER, better implementations divide 1.25 us into thirds!
  47. // Thus, 2.4 MHz has the same H times and slightly longer L times.
  48. .clock_speed_hz = 2400000,
  49. .input_delay_ns = 0, // moot
  50. .spics_io_num = -1,
  51. .flags = 0, // Keep it MSB first
  52. .queue_size = 1,
  53. .pre_cb = NULL,
  54. .post_cb = NULL,
  55. };
  56. ret = spi_bus_add_device(host, &devcfg, &device);
  57. RET_ON_ERR(spi_bus_add_device, ret);
  58. configure(length);
  59. }
  60. void SPI_LEDs::configure(int len) {
  61. if (out_buf) {
  62. free(out_buf);
  63. out_buf = NULL;
  64. }
  65. if (len <= 0) return;
  66. out_buf = (uint8_t*)heap_caps_malloc(tx_len(len), MALLOC_CAP_DMA);
  67. memset(out_buf + tx_len(len) - reset_bytes, 0, reset_bytes);
  68. transaction = (spi_transaction_t){
  69. .flags = 0,
  70. .cmd = 0,
  71. .addr = 0,
  72. .length = tx_len(len) * 8,
  73. .rxlength = 0,
  74. .user = NULL,
  75. .tx_buffer = out_buf,
  76. .rx_buffer = NULL,
  77. };
  78. }
  79. // Inverted
  80. constexpr uint8_t nibble_0 = 0b0111;
  81. constexpr uint8_t nibble_1 = 0b0011;
  82. static uint8_t* encode_byte(uint8_t *out, uint8_t in) {
  83. for (int i = 8; i > 0; i -= 2) {
  84. *out++ = (((in & 0x80) ? nibble_1 : nibble_0) << 4) |
  85. (((in & 0x40) ? nibble_1 : nibble_0) << 0);
  86. in <<= 2;
  87. }
  88. return out;
  89. }
  90. void SPI_LEDs::show() {
  91. // We generate a spurious SPI error with a 0-length transaction.
  92. if (length <= 0) return;
  93. static int index = 0;
  94. int ret;
  95. const Color *pixel = pixels;
  96. uint8_t *out = out_buf;
  97. for (int i = length; i > 0; --i) {
  98. out = encode_byte(out, pixel->r);
  99. out = encode_byte(out, pixel->g);
  100. out = encode_byte(out, pixel->b);
  101. ++pixel;
  102. }
  103. ++index;
  104. ret = spi_device_queue_trans(device, &transaction, portMAX_DELAY);
  105. RET_ON_ERR(spi_device_queue_trans, ret);
  106. /*
  107. while ((ret = spi_device_queue_trans(device, &transaction, 0)) != ESP_OK) {
  108. if (ret == ESP_ERR_TIMEOUT) {
  109. // Wait for the previous transaction to finish
  110. ESP_LOGI(TAG, "SPI transaction collision (# %d)", index);
  111. spi_transaction_t *ret_trans;
  112. ret = spi_device_get_trans_result(device, &ret_trans, portMAX_DELAY);
  113. RET_ON_ERR(spi_device_get_trans_result, ret);
  114. ESP_LOGI(TAG, "Transaction complete (# %d)", index);
  115. } else {
  116. RET_ON_ERR(spi_device_queue_trans, ret);
  117. }
  118. }
  119. */
  120. }