esp-idf/examples/peripherals/rmt/led_strip_simple_encoder/main/led_strip_example_main.c

135 wiersze
4.9 KiB
C

/*
* 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;
}
}
}