How to setup RMT timings for neopixel LED's
Posted: Thu May 06, 2021 5:32 am
Hello. I am learning about the RMT and neopixels. I have found adafruit neopixel library :
https://github.com/adafruit/Adafruit_NeoPixel
The library is using RMT to drive the neopixels.
I have also read espressif documentation on rmt and found this great example project:
https://github.com/adafruit/Adafruit_NeoPixel
Both projects are very simmilar in terms of RMT, however, it is still not fully clear to me how RMT timings are setup. In the espressif RMT example, the rmt_item_t is setup as following :
I want t understand how these values correspond to actual time . What is the formula behind it?
In the neopixel adafruit library the things get even more confusing , please see the following functions
In the esp_show function, the timings for t0h,t1h,t0l,t1l are being setup, but I cannot grasp how are they doing it...
Could someone please clarify this. Any help is appreciated
https://github.com/adafruit/Adafruit_NeoPixel
The library is using RMT to drive the neopixels.
I have also read espressif documentation on rmt and found this great example project:
https://github.com/adafruit/Adafruit_NeoPixel
Both projects are very simmilar in terms of RMT, however, it is still not fully clear to me how RMT timings are setup. In the espressif RMT example, the rmt_item_t is setup as following :
Code: Select all
const rmt_item32_t bit0 = {{{ 32767, 1, 15000, 0 }}}; //Logical 0
const rmt_item32_t bit1 = {{{ 32767, 1, 32767, 0 }}}; //Logical 1
In the neopixel adafruit library the things get even more confusing , please see the following functions
Code: Select all
static void IRAM_ATTR ws2812_rmt_adapter(const void *src, rmt_item32_t *dest, size_t src_size,
size_t wanted_num, size_t *translated_size, size_t *item_num)
{
if (src == NULL || dest == NULL)
{
*translated_size = 0;
*item_num = 0;
return;
}
const rmt_item32_t bit0 = {{{t0h_ticks, 1, t0l_ticks, 0}}}; //Logical 0
const rmt_item32_t bit1 = {{{t1h_ticks, 1, t1l_ticks, 0}}}; //Logical 1
size_t size = 0;
size_t num = 0;
uint8_t *psrc = (uint8_t *)src;
rmt_item32_t *pdest = dest;
while (size < src_size && num < wanted_num)
{
for (int i = 0; i < 8; i++)
{
// MSB first
if (*psrc & (1 << (7 - i)))
{
pdest->val = bit1.val;
}
else
{
pdest->val = bit0.val;
}
num++;
pdest++;
}
size++;
psrc++;
}
*translated_size = size;
*item_num = num;
}
void espShow(uint8_t pin, uint8_t *pixels, uint32_t numBytes)
{
// Reserve channel
rmt_channel_t channel = ADAFRUIT_RMT_CHANNEL_MAX;
for (size_t i = 0; i < ADAFRUIT_RMT_CHANNEL_MAX; i++)
{
if (!rmt_reserved_channels[i])
{
rmt_reserved_channels[i] = true;
channel = i;
}
}
if (channel == ADAFRUIT_RMT_CHANNEL_MAX)
{
// Ran out of channels!
return;
}
// Match default TX config from ESP-IDF version 3.4
rmt_config_t config = {
.rmt_mode = RMT_MODE_TX,
.channel = channel,
.gpio_num = pin,
.clk_div = 2,
.mem_block_num = 1,
.tx_config = {
//.carrier_freq_hz = 38000,
//.carrier_level = RMT_CARRIER_LEVEL_HIGH,
.idle_level = RMT_IDLE_LEVEL_LOW,
//.carrier_duty_percent = 33,
.carrier_en = false,
.loop_en = false,
.idle_output_en = true,
}};
rmt_config(&config);
rmt_driver_install(config.channel, 0, 0);
// Convert NS timings to ticks
uint32_t counter_clk_hz = 0;
// this emulates the rmt_get_counter_clock() function from ESP-IDF 3.4
if (RMT_LL_HW_BASE->conf_ch[config.channel].conf1.ref_always_on == RMT_BASECLK_REF)
{
cout << "hello, world ref" << endl; // Say Hello
//Serial.println("hello mate ref");
uint32_t div_cnt = RMT_LL_HW_BASE->conf_ch[config.channel].conf0.div_cnt;
uint32_t div = div_cnt == 0 ? 256 : div_cnt;
counter_clk_hz = REF_CLK_FREQ / (div);
}
else
{
cout << "hello, world apb" << endl; // Say Hello
//std:cout<<"hello mate apb"<<std<<endl;
uint32_t div_cnt = RMT_LL_HW_BASE->conf_ch[config.channel].conf0.div_cnt;
uint32_t div = div_cnt == 0 ? 256 : div_cnt;
counter_clk_hz = APB_CLK_FREQ / (div);
}
// NS to tick converter
float ratio = (float)counter_clk_hz / 1e9;
t0h_ticks = (uint32_t)(ratio * WS2812_T0H_NS);
t0l_ticks = (uint32_t)(ratio * WS2812_T0L_NS);
t1h_ticks = (uint32_t)(ratio * WS2812_T1H_NS);
t1l_ticks = (uint32_t)(ratio * WS2812_T1L_NS);
// Initialize automatic timing translator
rmt_translator_init(config.channel, ws2812_rmt_adapter);
// Write and wait to finish
rmt_write_sample(config.channel, pixels, (size_t)numBytes, true);
rmt_wait_tx_done(config.channel, pdMS_TO_TICKS(100));
// Free channel again
rmt_driver_uninstall(config.channel);
rmt_reserved_channels[channel] = false;
gpio_set_direction(pin, GPIO_MODE_OUTPUT);
}
Could someone please clarify this. Any help is appreciated