RmtDriver4.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /********************************************************************************
  2. * https://github.com/RoboticsBrno/SmartLeds
  3. *
  4. * MIT License
  5. *
  6. * Copyright (c) 2017 RoboticsBrno (RobotikaBrno)
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in all
  16. * copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24. * SOFTWARE.
  25. *******************************************************************************/
  26. #include "RmtDriver4.h"
  27. #if !SMARTLEDS_NEW_RMT_DRIVER
  28. #include "SmartLeds.h"
  29. namespace detail {
  30. // 8 still seems to work, but timings become marginal
  31. static const int DIVIDER = 4;
  32. // minimum time of a single RMT duration based on clock ns
  33. static const double RMT_DURATION_NS = 12.5;
  34. RmtDriver::RmtDriver(const LedType& timing, int count, int pin, int channel_num, SemaphoreHandle_t finishedFlag)
  35. : _timing(timing)
  36. , _count(count)
  37. , _pin((gpio_num_t)pin)
  38. , _finishedFlag(finishedFlag)
  39. , _channel((rmt_channel_t)channel_num) {
  40. _bitToRmt[0].level0 = 1;
  41. _bitToRmt[0].level1 = 0;
  42. _bitToRmt[0].duration0 = _timing.T0H / (RMT_DURATION_NS * DIVIDER);
  43. _bitToRmt[0].duration1 = _timing.T0L / (RMT_DURATION_NS * DIVIDER);
  44. _bitToRmt[1].level0 = 1;
  45. _bitToRmt[1].level1 = 0;
  46. _bitToRmt[1].duration0 = _timing.T1H / (RMT_DURATION_NS * DIVIDER);
  47. _bitToRmt[1].duration1 = _timing.T1L / (RMT_DURATION_NS * DIVIDER);
  48. }
  49. esp_err_t RmtDriver::init() {
  50. rmt_config_t config = RMT_DEFAULT_CONFIG_TX(_pin, _channel);
  51. config.rmt_mode = RMT_MODE_TX;
  52. config.clk_div = DIVIDER;
  53. config.mem_block_num = 1;
  54. return rmt_config(&config);
  55. }
  56. esp_err_t RmtDriver::registerIsr(bool isFirstRegisteredChannel) {
  57. auto err = rmt_driver_install(_channel, 0,
  58. #if defined(CONFIG_RMT_ISR_IRAM_SAFE)
  59. ESP_INTR_FLAG_IRAM
  60. #else
  61. 0
  62. #endif
  63. );
  64. if (err != ESP_OK) {
  65. return err;
  66. }
  67. if (isFirstRegisteredChannel) {
  68. rmt_register_tx_end_callback(txEndCallback, NULL);
  69. }
  70. err = rmt_translator_init(_channel, translateSample);
  71. if (err != ESP_OK) {
  72. return err;
  73. }
  74. return rmt_translator_set_context(_channel, this);
  75. }
  76. esp_err_t RmtDriver::unregisterIsr() { return rmt_driver_uninstall(_channel); }
  77. void IRAM_ATTR RmtDriver::txEndCallback(rmt_channel_t channel, void* arg) {
  78. xSemaphoreGiveFromISR(SmartLed::ledForChannel(channel)->_finishedFlag, nullptr);
  79. }
  80. void IRAM_ATTR RmtDriver::translateSample(const void* src, rmt_item32_t* dest, size_t src_size,
  81. size_t wanted_rmt_items_num, size_t* out_consumed_src_bytes, size_t* out_used_rmt_items) {
  82. RmtDriver* self;
  83. ESP_ERROR_CHECK(rmt_translator_get_context(out_used_rmt_items, (void**)&self));
  84. const auto& _bitToRmt = self->_bitToRmt;
  85. const auto src_offset = self->_translatorSourceOffset;
  86. auto* src_components = (const uint8_t*)src;
  87. size_t consumed_src_bytes = 0;
  88. size_t used_rmt_items = 0;
  89. while (consumed_src_bytes < src_size && used_rmt_items + 7 < wanted_rmt_items_num) {
  90. uint8_t val = *src_components;
  91. // each bit, from highest to lowest
  92. for (uint8_t j = 0; j != 8; j++, val <<= 1) {
  93. dest->val = _bitToRmt[val >> 7].val;
  94. ++dest;
  95. }
  96. used_rmt_items += 8;
  97. ++src_components;
  98. ++consumed_src_bytes;
  99. // skip alpha byte
  100. if (((src_offset + consumed_src_bytes) % 4) == 3) {
  101. ++src_components;
  102. ++consumed_src_bytes;
  103. // TRST delay after last pixel in strip
  104. if (consumed_src_bytes == src_size) {
  105. (dest - 1)->duration1 = self->_timing.TRS / (detail::RMT_DURATION_NS * detail::DIVIDER);
  106. }
  107. }
  108. }
  109. self->_translatorSourceOffset = src_offset + consumed_src_bytes;
  110. *out_consumed_src_bytes = consumed_src_bytes;
  111. *out_used_rmt_items = used_rmt_items;
  112. }
  113. esp_err_t RmtDriver::transmit(const Rgb* buffer) {
  114. static_assert(sizeof(Rgb) == 4); // The translator code above assumes RGB is 4 bytes
  115. _translatorSourceOffset = 0;
  116. return rmt_write_sample(_channel, (const uint8_t*)buffer, _count * 4, false);
  117. }
  118. };
  119. #endif // !SMARTLEDS_NEW_RMT_DRIVER