kopia lustrzana https://github.com/espressif/esp-idf
135 wiersze
4.9 KiB
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;
|
|
}
|
|
}
|
|
}
|