mirror of
https://github.com/jomjol/AI-on-the-edge-device.git
synced 2025-12-06 11:36:51 +03:00
144 lines
5.0 KiB
C++
144 lines
5.0 KiB
C++
/********************************************************************************
|
|
* 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 "RmtDriver4.h"
|
|
|
|
#if !SMARTLEDS_NEW_RMT_DRIVER
|
|
#include "SmartLeds.h"
|
|
|
|
namespace detail {
|
|
|
|
// 8 still seems to work, but timings become marginal
|
|
static const int DIVIDER = 4;
|
|
// minimum time of a single RMT duration based on clock ns
|
|
static const double RMT_DURATION_NS = 12.5;
|
|
|
|
RmtDriver::RmtDriver(const LedType& timing, int count, int pin, int channel_num, SemaphoreHandle_t finishedFlag)
|
|
: _timing(timing)
|
|
, _count(count)
|
|
, _pin((gpio_num_t)pin)
|
|
, _finishedFlag(finishedFlag)
|
|
, _channel((rmt_channel_t)channel_num) {
|
|
_bitToRmt[0].level0 = 1;
|
|
_bitToRmt[0].level1 = 0;
|
|
_bitToRmt[0].duration0 = _timing.T0H / (RMT_DURATION_NS * DIVIDER);
|
|
_bitToRmt[0].duration1 = _timing.T0L / (RMT_DURATION_NS * DIVIDER);
|
|
|
|
_bitToRmt[1].level0 = 1;
|
|
_bitToRmt[1].level1 = 0;
|
|
_bitToRmt[1].duration0 = _timing.T1H / (RMT_DURATION_NS * DIVIDER);
|
|
_bitToRmt[1].duration1 = _timing.T1L / (RMT_DURATION_NS * DIVIDER);
|
|
}
|
|
|
|
esp_err_t RmtDriver::init() {
|
|
rmt_config_t config = RMT_DEFAULT_CONFIG_TX(_pin, _channel);
|
|
config.rmt_mode = RMT_MODE_TX;
|
|
config.clk_div = DIVIDER;
|
|
config.mem_block_num = 1;
|
|
|
|
return rmt_config(&config);
|
|
}
|
|
|
|
esp_err_t RmtDriver::registerIsr(bool isFirstRegisteredChannel) {
|
|
auto err = rmt_driver_install(_channel, 0,
|
|
#if defined(CONFIG_RMT_ISR_IRAM_SAFE)
|
|
ESP_INTR_FLAG_IRAM
|
|
#else
|
|
0
|
|
#endif
|
|
);
|
|
if (err != ESP_OK) {
|
|
return err;
|
|
}
|
|
|
|
if (isFirstRegisteredChannel) {
|
|
rmt_register_tx_end_callback(txEndCallback, NULL);
|
|
}
|
|
|
|
err = rmt_translator_init(_channel, translateSample);
|
|
if (err != ESP_OK) {
|
|
return err;
|
|
}
|
|
return rmt_translator_set_context(_channel, this);
|
|
}
|
|
|
|
esp_err_t RmtDriver::unregisterIsr() { return rmt_driver_uninstall(_channel); }
|
|
|
|
void IRAM_ATTR RmtDriver::txEndCallback(rmt_channel_t channel, void* arg) {
|
|
xSemaphoreGiveFromISR(SmartLed::ledForChannel(channel)->_finishedFlag, nullptr);
|
|
}
|
|
|
|
void IRAM_ATTR RmtDriver::translateSample(const void* src, rmt_item32_t* dest, size_t src_size,
|
|
size_t wanted_rmt_items_num, size_t* out_consumed_src_bytes, size_t* out_used_rmt_items) {
|
|
RmtDriver* self;
|
|
ESP_ERROR_CHECK(rmt_translator_get_context(out_used_rmt_items, (void**)&self));
|
|
|
|
const auto& _bitToRmt = self->_bitToRmt;
|
|
const auto src_offset = self->_translatorSourceOffset;
|
|
|
|
auto* src_components = (const uint8_t*)src;
|
|
size_t consumed_src_bytes = 0;
|
|
size_t used_rmt_items = 0;
|
|
|
|
while (consumed_src_bytes < src_size && used_rmt_items + 7 < wanted_rmt_items_num) {
|
|
uint8_t val = *src_components;
|
|
|
|
// each bit, from highest to lowest
|
|
for (uint8_t j = 0; j != 8; j++, val <<= 1) {
|
|
dest->val = _bitToRmt[val >> 7].val;
|
|
++dest;
|
|
}
|
|
|
|
used_rmt_items += 8;
|
|
++src_components;
|
|
++consumed_src_bytes;
|
|
|
|
// skip alpha byte
|
|
if (((src_offset + consumed_src_bytes) % 4) == 3) {
|
|
++src_components;
|
|
++consumed_src_bytes;
|
|
|
|
// TRST delay after last pixel in strip
|
|
if (consumed_src_bytes == src_size) {
|
|
(dest - 1)->duration1 = self->_timing.TRS / (detail::RMT_DURATION_NS * detail::DIVIDER);
|
|
}
|
|
}
|
|
}
|
|
|
|
self->_translatorSourceOffset = src_offset + consumed_src_bytes;
|
|
*out_consumed_src_bytes = consumed_src_bytes;
|
|
*out_used_rmt_items = used_rmt_items;
|
|
}
|
|
|
|
esp_err_t RmtDriver::transmit(const Rgb* buffer) {
|
|
static_assert(sizeof(Rgb) == 4); // The translator code above assumes RGB is 4 bytes
|
|
|
|
_translatorSourceOffset = 0;
|
|
return rmt_write_sample(_channel, (const uint8_t*)buffer, _count * 4, false);
|
|
}
|
|
};
|
|
#endif // !SMARTLEDS_NEW_RMT_DRIVER
|