109 lines
3.2 KiB
C++
109 lines
3.2 KiB
C++
#ifndef PLATFORM_NATIVE
|
|
|
|
#include "drivers/Esp32DriverRGBW.h"
|
|
|
|
#include <driver/gpio.h>
|
|
#include <driver/rmt.h>
|
|
|
|
// Timing constants
|
|
static constexpr uint16_t DIVIDER = 4;
|
|
static constexpr double RMT_DURATION_NS = 12.5; // Minimum time of a single RMT duration based on clock ns
|
|
static constexpr uint32_t T0H = 300;
|
|
static constexpr uint32_t T0L = 900;
|
|
static constexpr uint32_t T1H = 600;
|
|
static constexpr uint32_t T1L = 600;
|
|
static constexpr uint32_t TRS = 80000;
|
|
static constexpr rmt_item32_t bit0Data = {uint32_t(T0H / (RMT_DURATION_NS * DIVIDER)), 1, uint32_t(T0L / (RMT_DURATION_NS * DIVIDER)), 0};
|
|
static constexpr rmt_item32_t bit1Data = {uint32_t(T1H / (RMT_DURATION_NS * DIVIDER)), 1, uint32_t(T1L / (RMT_DURATION_NS * DIVIDER)), 0};
|
|
|
|
// Function registered at the RMT driver that converts regular uint8_t values containing r,g,b,w values
|
|
// to rmt_item32_t for each bit. (8 bit -> 32 * 8 bit)
|
|
static void IRAM_ATTR uint8ToRmtAdaptor(const void *src, rmt_item32_t *dest, size_t srcSize,
|
|
size_t wantedNum, size_t *translatedSize, size_t *itemNum)
|
|
{
|
|
if (src == NULL || dest == NULL)
|
|
{
|
|
*translatedSize = 0;
|
|
*itemNum = 0;
|
|
return;
|
|
}
|
|
|
|
size_t size = 0;
|
|
size_t num = 0;
|
|
uint8_t *psrc = (uint8_t *)src;
|
|
rmt_item32_t *pdest = dest;
|
|
while (size < srcSize && num < wantedNum)
|
|
{
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
// MSB first
|
|
const bool isBitSet = *psrc & (1 << (7 - i));
|
|
pdest->val = isBitSet ? bit1Data.val : bit0Data.val;
|
|
num++;
|
|
pdest++;
|
|
}
|
|
size++;
|
|
psrc++;
|
|
}
|
|
*translatedSize = size;
|
|
*itemNum = num;
|
|
}
|
|
|
|
void Esp32DriverRGBW::begin(int gpio, int rmtChannel)
|
|
{
|
|
rmtChannel_ = rmtChannel;
|
|
transmitting_ = false;
|
|
|
|
rmt_config_t rmt_tx;
|
|
rmt_tx.channel = static_cast<rmt_channel_t>(rmtChannel);
|
|
rmt_tx.gpio_num = static_cast<gpio_num_t>(gpio);
|
|
rmt_tx.rmt_mode = RMT_MODE_TX;
|
|
rmt_tx.mem_block_num = 1;
|
|
rmt_tx.clk_div = DIVIDER;
|
|
rmt_tx.tx_config.loop_en = false;
|
|
rmt_tx.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW;
|
|
rmt_tx.tx_config.carrier_en = false;
|
|
rmt_tx.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
|
|
rmt_tx.tx_config.idle_output_en = true;
|
|
|
|
ESP_ERROR_CHECK(rmt_config(&rmt_tx));
|
|
ESP_ERROR_CHECK(rmt_driver_install(rmt_tx.channel, 0, 0));
|
|
|
|
rmt_translator_init((rmt_channel_t)rmtChannel, uint8ToRmtAdaptor);
|
|
}
|
|
|
|
void Esp32DriverRGBW::end()
|
|
{
|
|
ESP_ERROR_CHECK(rmt_driver_uninstall((rmt_channel_t)rmtChannel_));
|
|
}
|
|
|
|
void Esp32DriverRGBW::writeSync(const uint32_t *rgbwData, int numLeds)
|
|
{
|
|
waitForTransmissionToFinish();
|
|
auto data = reinterpret_cast<const uint8_t *>(rgbwData);
|
|
ESP_ERROR_CHECK(rmt_write_sample((rmt_channel_t)rmtChannel_, data, numLeds * 4, true));
|
|
}
|
|
|
|
void Esp32DriverRGBW::writeAsync(const uint32_t *rgbwData, int numLeds)
|
|
{
|
|
waitForTransmissionToFinish();
|
|
auto data = reinterpret_cast<const uint8_t *>(rgbwData);
|
|
ESP_ERROR_CHECK(rmt_write_sample((rmt_channel_t)rmtChannel_, data, numLeds * 4, false));
|
|
transmitting_ = true;
|
|
}
|
|
|
|
bool Esp32DriverRGBW::waitForTransmissionToFinish(int waitMs)
|
|
{
|
|
if (!transmitting_)
|
|
return true;
|
|
auto ret = rmt_wait_tx_done((rmt_channel_t)rmtChannel_, waitMs / portTICK_PERIOD_MS);
|
|
if (ret == ESP_OK)
|
|
{
|
|
transmitting_ = false;
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
#endif |