| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- /********************************************************************************
- * https://github.com/RoboticsBrno/SmartLeds
- *
- * MIT License
- *
- * Copyright (c) 2017 RoboticsBrno (RobotikaBrno)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *******************************************************************************/
- #include "RmtDriver5.h"
- #if SMARTLEDS_NEW_RMT_DRIVER
- #include <cstddef>
- #include "SmartLeds.h"
- namespace detail {
- static constexpr const uint32_t RMT_RESOLUTION_HZ = 20 * 1000 * 1000; // 20 MHz
- static constexpr const uint32_t RMT_NS_PER_TICK = 1000000000LLU / RMT_RESOLUTION_HZ;
- static RmtEncoderWrapper* IRAM_ATTR encSelf(rmt_encoder_t* encoder) {
- return (RmtEncoderWrapper*)(((intptr_t)encoder) - offsetof(RmtEncoderWrapper, base));
- }
- static size_t IRAM_ATTR encEncode(rmt_encoder_t* encoder, rmt_channel_handle_t tx_channel, const void* primary_data,
- size_t data_size, rmt_encode_state_t* ret_state) {
- auto* self = encSelf(encoder);
- // Delay after last pixel
- if ((self->last_state & RMT_ENCODING_COMPLETE) && self->frame_idx == data_size) {
- *ret_state = (rmt_encode_state_t)0;
- return self->copy_encoder->encode(
- self->copy_encoder, tx_channel, (const void*)&self->reset_code, sizeof(self->reset_code), ret_state);
- }
- if (self->last_state & RMT_ENCODING_COMPLETE) {
- Rgb* pixel = ((Rgb*)primary_data) + self->frame_idx;
- self->buffer_len = sizeof(self->buffer);
- for (size_t i = 0; i < sizeof(self->buffer); ++i) {
- self->buffer[i] = pixel->getGrb(self->component_idx);
- if (++self->component_idx == 3) {
- self->component_idx = 0;
- if (++self->frame_idx == data_size) {
- self->buffer_len = i + 1;
- break;
- }
- ++pixel;
- }
- }
- }
- self->last_state = (rmt_encode_state_t)0;
- auto encoded_symbols = self->bytes_encoder->encode(
- self->bytes_encoder, tx_channel, (const void*)&self->buffer, self->buffer_len, &self->last_state);
- if (self->last_state & RMT_ENCODING_MEM_FULL) {
- *ret_state = RMT_ENCODING_MEM_FULL;
- } else {
- *ret_state = (rmt_encode_state_t)0;
- }
- return encoded_symbols;
- }
- static esp_err_t encReset(rmt_encoder_t* encoder) {
- auto* self = encSelf(encoder);
- rmt_encoder_reset(self->bytes_encoder);
- rmt_encoder_reset(self->copy_encoder);
- self->last_state = RMT_ENCODING_COMPLETE;
- self->frame_idx = 0;
- self->component_idx = 0;
- return ESP_OK;
- }
- static esp_err_t encDelete(rmt_encoder_t* encoder) {
- auto* self = encSelf(encoder);
- rmt_del_encoder(self->bytes_encoder);
- rmt_del_encoder(self->copy_encoder);
- return ESP_OK;
- }
- RmtDriver::RmtDriver(const LedType& timing, int count, int pin, int channel_num, SemaphoreHandle_t finishedFlag)
- : _timing(timing)
- , _count(count)
- , _pin(pin)
- , _finishedFlag(finishedFlag)
- , _channel(nullptr)
- , _encoder {} {}
- esp_err_t RmtDriver::init() {
- _encoder.base.encode = encEncode;
- _encoder.base.reset = encReset;
- _encoder.base.del = encDelete;
- _encoder.reset_code.duration0 = _timing.TRS / RMT_NS_PER_TICK;
- rmt_bytes_encoder_config_t bytes_cfg = {
- .bit0 = {
- .duration0 = uint16_t(_timing.T0H / RMT_NS_PER_TICK),
- .level0 = 1,
- .duration1 = uint16_t(_timing.T0L / RMT_NS_PER_TICK),
- .level1 = 0,
- },
- .bit1 = {
- .duration0 = uint16_t(_timing.T1H / RMT_NS_PER_TICK),
- .level0 = 1,
- .duration1 = uint16_t(_timing.T1L / RMT_NS_PER_TICK),
- .level1 = 0,
- },
- .flags = {
- .msb_first = 1,
- },
- };
- auto err = rmt_new_bytes_encoder(&bytes_cfg, &_encoder.bytes_encoder);
- if (err != ESP_OK) {
- return err;
- }
- rmt_copy_encoder_config_t copy_cfg = {};
- err = rmt_new_copy_encoder(©_cfg, &_encoder.copy_encoder);
- if (err != ESP_OK) {
- return err;
- }
- // The config must be in registerIsr, because rmt_new_tx_channel
- // registers the ISR
- return ESP_OK;
- }
- esp_err_t RmtDriver::registerIsr(bool isFirstRegisteredChannel) {
- rmt_tx_channel_config_t conf = {
- .gpio_num = (gpio_num_t)_pin,
- .clk_src = RMT_CLK_SRC_DEFAULT, //.clk_src = RMT_CLK_SRC_APB,
- .resolution_hz = RMT_RESOLUTION_HZ,
- .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL,
- .trans_queue_depth = 1,
- .flags = {},
- };
- auto err = rmt_new_tx_channel(&conf, &_channel);
- if (err != ESP_OK) {
- return err;
- }
- rmt_tx_event_callbacks_t callbacks_cfg = {};
- callbacks_cfg.on_trans_done = txDoneCallback;
- err = rmt_tx_register_event_callbacks(_channel, &callbacks_cfg, this);
- if (err != ESP_OK) {
- return err;
- }
- return rmt_enable(_channel);
- }
- esp_err_t RmtDriver::unregisterIsr() {
- auto err = rmt_del_encoder(&_encoder.base);
- if (err != ESP_OK) {
- return err;
- }
- err = rmt_disable(_channel);
- if (err != ESP_OK) {
- return err;
- }
- return rmt_del_channel(_channel);
- }
- bool IRAM_ATTR RmtDriver::txDoneCallback(
- rmt_channel_handle_t tx_chan, const rmt_tx_done_event_data_t* edata, void* user_ctx) {
- auto* self = (RmtDriver*)user_ctx;
- auto taskWoken = pdTRUE;
- xSemaphoreGiveFromISR(self->_finishedFlag, &taskWoken);
- return taskWoken == pdTRUE;
- }
- esp_err_t RmtDriver::transmit(const Rgb* buffer) {
- rmt_encoder_reset(&_encoder.base);
- rmt_transmit_config_t cfg = {};
- return rmt_transmit(_channel, &_encoder.base, buffer, _count, &cfg);
- }
- };
- #endif // !SMARTLEDS_NEW_RMT_DRIVER
|