RmtDriver5.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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 "RmtDriver5.h"
  27. #if SMARTLEDS_NEW_RMT_DRIVER
  28. #include <cstddef>
  29. #include "SmartLeds.h"
  30. namespace detail {
  31. static constexpr const uint32_t RMT_RESOLUTION_HZ = 20 * 1000 * 1000; // 20 MHz
  32. static constexpr const uint32_t RMT_NS_PER_TICK = 1000000000LLU / RMT_RESOLUTION_HZ;
  33. static RmtEncoderWrapper* IRAM_ATTR encSelf(rmt_encoder_t* encoder) {
  34. return (RmtEncoderWrapper*)(((intptr_t)encoder) - offsetof(RmtEncoderWrapper, base));
  35. }
  36. static size_t IRAM_ATTR encEncode(rmt_encoder_t* encoder, rmt_channel_handle_t tx_channel, const void* primary_data,
  37. size_t data_size, rmt_encode_state_t* ret_state) {
  38. auto* self = encSelf(encoder);
  39. // Delay after last pixel
  40. if ((self->last_state & RMT_ENCODING_COMPLETE) && self->frame_idx == data_size) {
  41. *ret_state = (rmt_encode_state_t)0;
  42. return self->copy_encoder->encode(
  43. self->copy_encoder, tx_channel, (const void*)&self->reset_code, sizeof(self->reset_code), ret_state);
  44. }
  45. if (self->last_state & RMT_ENCODING_COMPLETE) {
  46. Rgb* pixel = ((Rgb*)primary_data) + self->frame_idx;
  47. self->buffer_len = sizeof(self->buffer);
  48. for (size_t i = 0; i < sizeof(self->buffer); ++i) {
  49. self->buffer[i] = pixel->getGrb(self->component_idx);
  50. if (++self->component_idx == 3) {
  51. self->component_idx = 0;
  52. if (++self->frame_idx == data_size) {
  53. self->buffer_len = i + 1;
  54. break;
  55. }
  56. ++pixel;
  57. }
  58. }
  59. }
  60. self->last_state = (rmt_encode_state_t)0;
  61. auto encoded_symbols = self->bytes_encoder->encode(
  62. self->bytes_encoder, tx_channel, (const void*)&self->buffer, self->buffer_len, &self->last_state);
  63. if (self->last_state & RMT_ENCODING_MEM_FULL) {
  64. *ret_state = RMT_ENCODING_MEM_FULL;
  65. } else {
  66. *ret_state = (rmt_encode_state_t)0;
  67. }
  68. return encoded_symbols;
  69. }
  70. static esp_err_t encReset(rmt_encoder_t* encoder) {
  71. auto* self = encSelf(encoder);
  72. rmt_encoder_reset(self->bytes_encoder);
  73. rmt_encoder_reset(self->copy_encoder);
  74. self->last_state = RMT_ENCODING_COMPLETE;
  75. self->frame_idx = 0;
  76. self->component_idx = 0;
  77. return ESP_OK;
  78. }
  79. static esp_err_t encDelete(rmt_encoder_t* encoder) {
  80. auto* self = encSelf(encoder);
  81. rmt_del_encoder(self->bytes_encoder);
  82. rmt_del_encoder(self->copy_encoder);
  83. return ESP_OK;
  84. }
  85. RmtDriver::RmtDriver(const LedType& timing, int count, int pin, int channel_num, SemaphoreHandle_t finishedFlag)
  86. : _timing(timing)
  87. , _count(count)
  88. , _pin(pin)
  89. , _finishedFlag(finishedFlag)
  90. , _channel(nullptr)
  91. , _encoder {} {}
  92. esp_err_t RmtDriver::init() {
  93. _encoder.base.encode = encEncode;
  94. _encoder.base.reset = encReset;
  95. _encoder.base.del = encDelete;
  96. _encoder.reset_code.duration0 = _timing.TRS / RMT_NS_PER_TICK;
  97. rmt_bytes_encoder_config_t bytes_cfg = {
  98. .bit0 = {
  99. .duration0 = uint16_t(_timing.T0H / RMT_NS_PER_TICK),
  100. .level0 = 1,
  101. .duration1 = uint16_t(_timing.T0L / RMT_NS_PER_TICK),
  102. .level1 = 0,
  103. },
  104. .bit1 = {
  105. .duration0 = uint16_t(_timing.T1H / RMT_NS_PER_TICK),
  106. .level0 = 1,
  107. .duration1 = uint16_t(_timing.T1L / RMT_NS_PER_TICK),
  108. .level1 = 0,
  109. },
  110. .flags = {
  111. .msb_first = 1,
  112. },
  113. };
  114. auto err = rmt_new_bytes_encoder(&bytes_cfg, &_encoder.bytes_encoder);
  115. if (err != ESP_OK) {
  116. return err;
  117. }
  118. rmt_copy_encoder_config_t copy_cfg = {};
  119. err = rmt_new_copy_encoder(&copy_cfg, &_encoder.copy_encoder);
  120. if (err != ESP_OK) {
  121. return err;
  122. }
  123. // The config must be in registerIsr, because rmt_new_tx_channel
  124. // registers the ISR
  125. return ESP_OK;
  126. }
  127. esp_err_t RmtDriver::registerIsr(bool isFirstRegisteredChannel) {
  128. rmt_tx_channel_config_t conf = {
  129. .gpio_num = (gpio_num_t)_pin,
  130. .clk_src = RMT_CLK_SRC_DEFAULT, //.clk_src = RMT_CLK_SRC_APB,
  131. .resolution_hz = RMT_RESOLUTION_HZ,
  132. .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL,
  133. .trans_queue_depth = 1,
  134. .flags = {},
  135. };
  136. auto err = rmt_new_tx_channel(&conf, &_channel);
  137. if (err != ESP_OK) {
  138. return err;
  139. }
  140. rmt_tx_event_callbacks_t callbacks_cfg = {};
  141. callbacks_cfg.on_trans_done = txDoneCallback;
  142. err = rmt_tx_register_event_callbacks(_channel, &callbacks_cfg, this);
  143. if (err != ESP_OK) {
  144. return err;
  145. }
  146. return rmt_enable(_channel);
  147. }
  148. esp_err_t RmtDriver::unregisterIsr() {
  149. auto err = rmt_del_encoder(&_encoder.base);
  150. if (err != ESP_OK) {
  151. return err;
  152. }
  153. err = rmt_disable(_channel);
  154. if (err != ESP_OK) {
  155. return err;
  156. }
  157. return rmt_del_channel(_channel);
  158. }
  159. bool IRAM_ATTR RmtDriver::txDoneCallback(
  160. rmt_channel_handle_t tx_chan, const rmt_tx_done_event_data_t* edata, void* user_ctx) {
  161. auto* self = (RmtDriver*)user_ctx;
  162. auto taskWoken = pdTRUE;
  163. xSemaphoreGiveFromISR(self->_finishedFlag, &taskWoken);
  164. return taskWoken == pdTRUE;
  165. }
  166. esp_err_t RmtDriver::transmit(const Rgb* buffer) {
  167. rmt_encoder_reset(&_encoder.base);
  168. rmt_transmit_config_t cfg = {};
  169. return rmt_transmit(_channel, &_encoder.base, buffer, _count, &cfg);
  170. }
  171. };
  172. #endif // !SMARTLEDS_NEW_RMT_DRIVER