ESP32 Native version of Blinky, featureful controller code for WS2811/WS2812/NeoPixels
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

143 řádky
3.7KB

  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. .clock_speed_hz = 3200000,
  47. .input_delay_ns = 0, // moot
  48. .spics_io_num = -1,
  49. .flags = 0, // Keep it MSB first
  50. .queue_size = 1,
  51. .pre_cb = NULL,
  52. .post_cb = NULL,
  53. };
  54. ret = spi_bus_add_device(host, &devcfg, &device);
  55. RET_ON_ERR(spi_bus_add_device, ret);
  56. configure(length);
  57. }
  58. void SPI_LEDs::configure(int len) {
  59. if (out_buf) {
  60. free(out_buf);
  61. out_buf = NULL;
  62. }
  63. if (len <= 0) return;
  64. out_buf = (uint8_t*)heap_caps_malloc(tx_len(len), MALLOC_CAP_DMA);
  65. memset(out_buf + tx_len(len) - reset_bytes, 0, reset_bytes);
  66. transaction = {
  67. .flags = 0,
  68. .cmd = 0,
  69. .addr = 0,
  70. .length = tx_len(len) * 8,
  71. .rxlength = 0,
  72. .user = NULL,
  73. .tx_buffer = out_buf,
  74. .rx_buffer = NULL,
  75. };
  76. }
  77. // Inverted
  78. constexpr uint8_t nibble_0 = 0b0111;
  79. constexpr uint8_t nibble_1 = 0b0011;
  80. static uint8_t* encode_byte(uint8_t *out, uint8_t in) {
  81. for (int i = 8; i > 0; i -= 2) {
  82. *out++ = (((in & 0x80) ? nibble_1 : nibble_0) << 4) |
  83. (((in & 0x40) ? nibble_1 : nibble_0) << 0);
  84. in <<= 2;
  85. }
  86. return out;
  87. }
  88. void SPI_LEDs::show() {
  89. static int index = 0;
  90. int ret;
  91. const Color *pixel = pixels;
  92. uint8_t *out = out_buf;
  93. for (int i = length; i > 0; --i) {
  94. out = encode_byte(out, pixel->r);
  95. out = encode_byte(out, pixel->g);
  96. out = encode_byte(out, pixel->b);
  97. ++pixel;
  98. }
  99. ++index;
  100. ret = spi_device_queue_trans(device, &transaction, portMAX_DELAY);
  101. RET_ON_ERR(spi_device_queue_trans, ret);
  102. /*
  103. while ((ret = spi_device_queue_trans(device, &transaction, 0)) != ESP_OK) {
  104. if (ret == ESP_ERR_TIMEOUT) {
  105. // Wait for the previous transaction to finish
  106. ESP_LOGI(TAG, "SPI transaction collision (# %d)", index);
  107. spi_transaction_t *ret_trans;
  108. ret = spi_device_get_trans_result(device, &ret_trans, portMAX_DELAY);
  109. RET_ON_ERR(spi_device_get_trans_result, ret);
  110. ESP_LOGI(TAG, "Transaction complete (# %d)", index);
  111. } else {
  112. RET_ON_ERR(spi_device_queue_trans, ret);
  113. }
  114. }
  115. */
  116. }