mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-23 17:24:44 +00:00
feat(rmt): Add simple callback encoder
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "led_strip_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/rmt_tx.h"
|
||||
|
||||
#define RMT_LED_STRIP_RESOLUTION_HZ 10000000 // 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution)
|
||||
#define RMT_LED_STRIP_GPIO_NUM 8
|
||||
|
||||
#define EXAMPLE_LED_NUMBERS 24
|
||||
|
||||
#define EXAMPLE_FRAME_DURATION_MS 20
|
||||
#define EXAMPLE_ANGLE_INC_FRAME 0.02
|
||||
#define EXAMPLE_ANGLE_INC_LED 0.3
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
static uint8_t led_strip_pixels[EXAMPLE_LED_NUMBERS * 3];
|
||||
|
||||
static const rmt_symbol_word_t ws2812_zero = {
|
||||
.level0 = 1,
|
||||
.duration0 = 0.3 * RMT_LED_STRIP_RESOLUTION_HZ / 1000000, // T0H=0.3us
|
||||
.level1 = 0,
|
||||
.duration1 = 0.9 * RMT_LED_STRIP_RESOLUTION_HZ / 1000000, // T0L=0.9us
|
||||
};
|
||||
|
||||
static const rmt_symbol_word_t ws2812_one = {
|
||||
.level0 = 1,
|
||||
.duration0 = 0.9 * RMT_LED_STRIP_RESOLUTION_HZ / 1000000, // T1H=0.9us
|
||||
.level1 = 0,
|
||||
.duration1 = 0.3 * RMT_LED_STRIP_RESOLUTION_HZ / 1000000, // T1L=0.3us
|
||||
};
|
||||
|
||||
//reset defaults to 50uS
|
||||
static const rmt_symbol_word_t ws2812_reset = {
|
||||
.level0 = 1,
|
||||
.duration0 = RMT_LED_STRIP_RESOLUTION_HZ / 1000000 * 50 / 2,
|
||||
.level1 = 0,
|
||||
.duration1 = RMT_LED_STRIP_RESOLUTION_HZ / 1000000 * 50 / 2,
|
||||
};
|
||||
|
||||
static size_t encoder_callback(const void *data, size_t data_size,
|
||||
size_t symbols_written, size_t symbols_free,
|
||||
rmt_symbol_word_t *symbols, bool *done, void *arg)
|
||||
{
|
||||
// We need a minimum of 8 symbol spaces to encode a byte. We only
|
||||
// need one to encode a reset, but it's simpler to simply demand that
|
||||
// there are 8 symbol spaces free to write anything.
|
||||
if (symbols_free < 8) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We can calculate where in the data we are from the symbol pos.
|
||||
// Alternatively, we could use some counter referenced by the arg
|
||||
// parameter to keep track of this.
|
||||
size_t data_pos = symbols_written / 8;
|
||||
uint8_t *data_bytes = (uint8_t*)data;
|
||||
if (data_pos < data_size) {
|
||||
// Encode a byte
|
||||
size_t symbol_pos = 0;
|
||||
for (int bitmask = 0x80; bitmask != 0; bitmask >>= 1) {
|
||||
if (data_bytes[data_pos]&bitmask) {
|
||||
symbols[symbol_pos++] = ws2812_one;
|
||||
} else {
|
||||
symbols[symbol_pos++] = ws2812_zero;
|
||||
}
|
||||
}
|
||||
// We're done; we should have written 8 symbols.
|
||||
return symbol_pos;
|
||||
} else {
|
||||
//All bytes already are encoded.
|
||||
//Encode the reset, and we're done.
|
||||
symbols[0] = ws2812_reset;
|
||||
*done = 1; //Indicate end of the transaction.
|
||||
return 1; //we only wrote one symbol
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Create RMT TX channel");
|
||||
rmt_channel_handle_t led_chan = NULL;
|
||||
rmt_tx_channel_config_t tx_chan_config = {
|
||||
.clk_src = RMT_CLK_SRC_DEFAULT, // select source clock
|
||||
.gpio_num = RMT_LED_STRIP_GPIO_NUM,
|
||||
.mem_block_symbols = 64, // increase the block size can make the LED less flickering
|
||||
.resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ,
|
||||
.trans_queue_depth = 4, // set the number of transactions that can be pending in the background
|
||||
};
|
||||
ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &led_chan));
|
||||
|
||||
ESP_LOGI(TAG, "Create simple callback-based encoder");
|
||||
rmt_encoder_handle_t simple_encoder = NULL;
|
||||
const rmt_simple_encoder_config_t simple_encoder_cfg = {
|
||||
.callback = encoder_callback
|
||||
//Note we don't set min_chunk_size here as the default of 64 is good enough.
|
||||
};
|
||||
ESP_ERROR_CHECK(rmt_new_simple_encoder(&simple_encoder_cfg, &simple_encoder));
|
||||
|
||||
ESP_LOGI(TAG, "Enable RMT TX channel");
|
||||
ESP_ERROR_CHECK(rmt_enable(led_chan));
|
||||
|
||||
ESP_LOGI(TAG, "Start LED rainbow chase");
|
||||
rmt_transmit_config_t tx_config = {
|
||||
.loop_count = 0, // no transfer loop
|
||||
};
|
||||
float offset = 0;
|
||||
while (1) {
|
||||
for (int led = 0; led < EXAMPLE_LED_NUMBERS; led++) {
|
||||
// Build RGB pixels. Each color is an offset sine, which gives a
|
||||
// hue-like effect.
|
||||
float angle = offset + (led * EXAMPLE_ANGLE_INC_LED);
|
||||
const float color_off = (M_PI * 2) / 3;
|
||||
led_strip_pixels[led * 3 + 0] = sin(angle + color_off * 0) * 127 + 128;
|
||||
led_strip_pixels[led * 3 + 1] = sin(angle + color_off * 1) * 127 + 128;
|
||||
led_strip_pixels[led * 3 + 2] = sin(angle + color_off * 2) * 117 + 128;;
|
||||
}
|
||||
// Flush RGB values to LEDs
|
||||
ESP_ERROR_CHECK(rmt_transmit(led_chan, simple_encoder, led_strip_pixels, sizeof(led_strip_pixels), &tx_config));
|
||||
ESP_ERROR_CHECK(rmt_tx_wait_all_done(led_chan, portMAX_DELAY));
|
||||
vTaskDelay(pdMS_TO_TICKS(EXAMPLE_FRAME_DURATION_MS));
|
||||
//Increase offset to shift pattern
|
||||
offset += EXAMPLE_ANGLE_INC_FRAME;
|
||||
if (offset > 2 * M_PI) {
|
||||
offset -= 2 * M_PI;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user