example: update led strip example with new rmt driver

pull/8968/head
morris 2022-04-07 13:12:16 +08:00
rodzic 977a2830dd
commit d537da5bfb
25 zmienionych plików z 803 dodań i 532 usunięć

Wyświetl plik

@ -1,4 +1,3 @@
idf_component_register(SRCS "led_strip_rmt_ws2812.c"
INCLUDE_DIRS "include"
PRIV_REQUIRES "driver"
)
idf_component_register(SRCS "src/led_strip_rmt_dev.c" "src/led_strip_rmt_encoder.c"
INCLUDE_DIRS "include" "interface"
PRIV_REQUIRES "driver")

Wyświetl plik

@ -1,6 +1,6 @@
# LED Strip Component
This directory contains an implementation for addressable LEDs using the RMT peripheral.
This directory contains an implementation for addressable LEDs by different peripherals. Currently only RMT is supported as the led strip backend.
It's compatible with:
@ -9,7 +9,6 @@ It's compatible with:
This component is used as part of the following ESP-IDF examples:
- [Blink Example](../../get-started/blink).
- [LED Strip Example](../../peripherals/rmt/led_strip).
To learn more about how to use this component, please check API Documentation from header file [led_strip.h](./include/led_strip.h).

Wyświetl plik

@ -1,146 +1,94 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_err.h"
/**
* @brief LED strip handle
*/
typedef struct led_strip_t *led_strip_handle_t;
/**
* @brief LED Strip Type
*
*/
typedef struct led_strip_s led_strip_t;
* @brief Set RGB for a specific pixel
*
* @param strip: LED strip
* @param index: index of pixel to set
* @param red: red part of color
* @param green: green part of color
* @param blue: blue part of color
*
* @return
* - ESP_OK: Set RGB for a specific pixel successfully
* - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters
* - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred
*/
esp_err_t led_strip_set_pixel(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue);
/**
* @brief LED Strip Device Type
*
*/
typedef void *led_strip_dev_t;
* @brief Refresh memory colors to LEDs
*
* @param strip: LED strip
*
* @return
* - ESP_OK: Refresh successfully
* - ESP_FAIL: Refresh failed because some other error occurred
*
* @note:
* After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip.
*/
esp_err_t led_strip_refresh(led_strip_handle_t strip);
/**
* @brief Declare of LED Strip Type
*
*/
struct led_strip_s {
/**
* @brief Set RGB for a specific pixel
*
* @param strip: LED strip
* @param index: index of pixel to set
* @param red: red part of color
* @param green: green part of color
* @param blue: blue part of color
*
* @return
* - ESP_OK: Set RGB for a specific pixel successfully
* - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters
* - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred
*/
esp_err_t (*set_pixel)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue);
/**
* @brief Refresh memory colors to LEDs
*
* @param strip: LED strip
* @param timeout_ms: timeout value for refreshing task
*
* @return
* - ESP_OK: Refresh successfully
* - ESP_ERR_TIMEOUT: Refresh failed because of timeout
* - ESP_FAIL: Refresh failed because some other error occurred
*
* @note:
* After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip.
*/
esp_err_t (*refresh)(led_strip_t *strip, uint32_t timeout_ms);
/**
* @brief Clear LED strip (turn off all LEDs)
*
* @param strip: LED strip
* @param timeout_ms: timeout value for clearing task
*
* @return
* - ESP_OK: Clear LEDs successfully
* - ESP_ERR_TIMEOUT: Clear LEDs failed because of timeout
* - ESP_FAIL: Clear LEDs failed because some other error occurred
*/
esp_err_t (*clear)(led_strip_t *strip, uint32_t timeout_ms);
/**
* @brief Free LED strip resources
*
* @param strip: LED strip
*
* @return
* - ESP_OK: Free resources successfully
* - ESP_FAIL: Free resources failed because error occurred
*/
esp_err_t (*del)(led_strip_t *strip);
};
* @brief Clear LED strip (turn off all LEDs)
*
* @param strip: LED strip
*
* @return
* - ESP_OK: Clear LEDs successfully
* - ESP_FAIL: Clear LEDs failed because some other error occurred
*/
esp_err_t led_strip_clear(led_strip_handle_t strip);
/**
* @brief LED Strip Configuration Type
*
*/
* @brief Free LED strip resources
*
* @param strip: LED strip
*
* @return
* - ESP_OK: Free resources successfully
* - ESP_FAIL: Free resources failed because error occurred
*/
esp_err_t led_strip_del(led_strip_handle_t strip);
/**
* @brief LED Strip Configuration
*/
typedef struct {
uint32_t max_leds; /*!< Maximum LEDs in a single strip */
led_strip_dev_t dev; /*!< LED strip device (e.g. RMT channel, PWM channel, etc) */
uint32_t strip_gpio_num; /*!< GPIO number that used by LED strip */
uint32_t max_leds; /*!< Maximum LEDs in a single strip */
} led_strip_config_t;
/**
* @brief Default configuration for LED strip
* @brief Create LED strip based on RMT TX channel
*
*/
#define LED_STRIP_DEFAULT_CONFIG(number, dev_hdl) \
{ \
.max_leds = number, \
.dev = dev_hdl, \
}
/**
* @brief Install a new ws2812 driver (based on RMT peripheral)
*
* @param config: LED strip configuration
* @return
* LED strip instance or NULL
*/
led_strip_t *led_strip_new_rmt_ws2812(const led_strip_config_t *config);
/**
* @brief Init the RMT peripheral and LED strip configuration.
*
* @param[in] channel: RMT peripheral channel number.
* @param[in] gpio: GPIO number for the RMT data output.
* @param[in] led_num: number of addressable LEDs.
* @param config LED strip specific configuration
* @param ret_strip Returned LED strip handle
* @return
* LED strip instance or NULL
* - ESP_OK: create LED strip handle successfully
* - ESP_ERR_INVALID_ARG: create LED strip handle failed because of invalid argument
* - ESP_ERR_NO_MEM: create LED strip handle failed because of out of memory
* - ESP_FAIL: create LED strip handle failed because some other error
*/
led_strip_t * led_strip_init(uint8_t channel, uint8_t gpio, uint16_t led_num);
/**
* @brief Denit the RMT peripheral.
*
* @param[in] strip: LED strip
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t led_strip_denit(led_strip_t *strip);
esp_err_t led_strip_new_rmt_device(const led_strip_config_t *config, led_strip_handle_t *ret_strip);
#ifdef __cplusplus
}

Wyświetl plik

@ -0,0 +1,78 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct led_strip_t led_strip_t; /*!< Type of LED strip */
/**
* @brief LED strip interface definition
*/
struct led_strip_t {
/**
* @brief Set RGB for a specific pixel
*
* @param strip: LED strip
* @param index: index of pixel to set
* @param red: red part of color
* @param green: green part of color
* @param blue: blue part of color
*
* @return
* - ESP_OK: Set RGB for a specific pixel successfully
* - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters
* - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred
*/
esp_err_t (*set_pixel)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue);
/**
* @brief Refresh memory colors to LEDs
*
* @param strip: LED strip
* @param timeout_ms: timeout value for refreshing task
*
* @return
* - ESP_OK: Refresh successfully
* - ESP_FAIL: Refresh failed because some other error occurred
*
* @note:
* After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip.
*/
esp_err_t (*refresh)(led_strip_t *strip);
/**
* @brief Clear LED strip (turn off all LEDs)
*
* @param strip: LED strip
* @param timeout_ms: timeout value for clearing task
*
* @return
* - ESP_OK: Clear LEDs successfully
* - ESP_FAIL: Clear LEDs failed because some other error occurred
*/
esp_err_t (*clear)(led_strip_t *strip);
/**
* @brief Free LED strip resources
*
* @param strip: LED strip
*
* @return
* - ESP_OK: Free resources successfully
* - ESP_FAIL: Free resources failed because error occurred
*/
esp_err_t (*del)(led_strip_t *strip);
};
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -1,216 +0,0 @@
/*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_attr.h"
#include "led_strip.h"
#include "driver/rmt.h"
#define RMT_TX_CHANNEL RMT_CHANNEL_0
static const char *TAG = "ws2812";
#define STRIP_CHECK(a, str, goto_tag, ret_value, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
ret = ret_value; \
goto goto_tag; \
} \
} while (0)
#define WS2812_T0H_NS (350)
#define WS2812_T0L_NS (1000)
#define WS2812_T1H_NS (1000)
#define WS2812_T1L_NS (350)
#define WS2812_RESET_US (280)
static uint32_t ws2812_t0h_ticks = 0;
static uint32_t ws2812_t1h_ticks = 0;
static uint32_t ws2812_t0l_ticks = 0;
static uint32_t ws2812_t1l_ticks = 0;
static uint32_t ws2812_reset_ticks = 0;
typedef struct {
led_strip_t parent;
rmt_channel_t rmt_channel;
uint32_t strip_len;
uint8_t buffer[0];
} ws2812_t;
/**
* @brief Conver RGB data to RMT format.
*
* @note For WS2812, R,G,B each contains 256 different choices (i.e. uint8_t)
*
* @param[in] src: source data, to converted to RMT format
* @param[in] dest: place where to store the convert result
* @param[in] src_size: size of source data
* @param[in] wanted_num: number of RMT items that want to get
* @param[out] translated_size: number of source data that got converted
* @param[out] item_num: number of RMT items which are converted from source data
*/
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 = {{{ ws2812_t0h_ticks, 1, ws2812_t0l_ticks, 0 }}}; //Logical 0
const rmt_item32_t bit1 = {{{ ws2812_t1h_ticks, 1, ws2812_t1l_ticks, 0 }}}; //Logical 1
const rmt_item32_t reset = {{{ ws2812_reset_ticks, 0, 0, 0 }}}; // Reset signal
const rmt_item32_t nop = {{{ 0, 0, 0, 0 }}}; // Null signal
size_t size = 0;
size_t num = 0;
uint8_t *psrc = (uint8_t *)src;
rmt_item32_t *pdest = dest;
while (size < (src_size - 1) && num < wanted_num) {
// MSB first, so we decremented `i` from 7 to 0.
// Note that `i` must be signed (e.g. `int`) for this to work!
for (int i = 7; i >= 0; i--) {
(pdest++)->val = (*psrc & (1 << i)) ? bit1.val : bit0.val;
}
num += 8;
size++;
psrc++;
}
// Send reset signal (LOW for `WS2812_RESET_US` microseconds)
// The check of the size is still needed, because `src_size` could be 0.
// (Note that the check could be replaced by `src_size > 0`,
// but it is more clear this way.)
if (size < src_size && num < wanted_num) {
(pdest++)->val = reset.val; // The first bit is the reset signal
// we just sent the first bit, so we start the loop with i = 1
for (int i = 1; i < 8; i++) { // complete the byte with 7 NOP signals
(pdest++)->val = nop.val;
}
num += 8;
size++;
// we don't need to increment `psrc`, because we no longer use it
}
*translated_size = size;
*item_num = num;
}
static esp_err_t ws2812_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
{
esp_err_t ret = ESP_OK;
ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
STRIP_CHECK(index < ws2812->strip_len, "index out of the maximum number of leds", err, ESP_ERR_INVALID_ARG);
uint32_t start = index * 3;
// In the order of GRB
ws2812->buffer[start + 0] = green & 0xFF;
ws2812->buffer[start + 1] = red & 0xFF;
ws2812->buffer[start + 2] = blue & 0xFF;
return ESP_OK;
err:
return ret;
}
static esp_err_t ws2812_refresh(led_strip_t *strip, uint32_t timeout_ms)
{
esp_err_t ret = ESP_OK;
ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
STRIP_CHECK(rmt_write_sample(ws2812->rmt_channel, ws2812->buffer, ws2812->strip_len * 3 + 1, true) == ESP_OK,
"transmit RMT samples failed", err, ESP_FAIL);
return rmt_wait_tx_done(ws2812->rmt_channel, pdMS_TO_TICKS(timeout_ms));
err:
return ret;
}
static esp_err_t ws2812_clear(led_strip_t *strip, uint32_t timeout_ms)
{
ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
// Write zero to turn off all leds
memset(ws2812->buffer, 0, ws2812->strip_len * 3);
return ws2812_refresh(strip, timeout_ms);
}
static esp_err_t ws2812_del(led_strip_t *strip)
{
ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
free(ws2812);
return ESP_OK;
}
led_strip_t *led_strip_new_rmt_ws2812(const led_strip_config_t *config)
{
led_strip_t *ret = NULL;
STRIP_CHECK(config, "configuration can't be null", err, NULL);
// 24 bits per led + reset
uint32_t ws2812_size = sizeof(ws2812_t) + config->max_leds * 3 + 1;
ws2812_t *ws2812 = calloc(1, ws2812_size);
STRIP_CHECK(ws2812, "request memory for ws2812 failed", err, NULL);
uint32_t counter_clk_hz = 0;
STRIP_CHECK(rmt_get_counter_clock((rmt_channel_t)config->dev, &counter_clk_hz) == ESP_OK,
"get rmt counter clock failed", err, NULL);
// ns -> ticks
float ratio = (float)counter_clk_hz / 1e9;
ws2812_t0h_ticks = (uint32_t)(ratio * WS2812_T0H_NS);
ws2812_t0l_ticks = (uint32_t)(ratio * WS2812_T0L_NS);
ws2812_t1h_ticks = (uint32_t)(ratio * WS2812_T1H_NS);
ws2812_t1l_ticks = (uint32_t)(ratio * WS2812_T1L_NS);
ws2812_reset_ticks = (uint32_t)(ratio * WS2812_RESET_US * 1000);
// set ws2812 to rmt adapter
rmt_translator_init((rmt_channel_t)config->dev, ws2812_rmt_adapter);
ws2812->rmt_channel = (rmt_channel_t)config->dev;
ws2812->strip_len = config->max_leds;
ws2812->parent.set_pixel = ws2812_set_pixel;
ws2812->parent.refresh = ws2812_refresh;
ws2812->parent.clear = ws2812_clear;
ws2812->parent.del = ws2812_del;
return &ws2812->parent;
err:
return ret;
}
led_strip_t * led_strip_init(uint8_t channel, uint8_t gpio, uint16_t led_num)
{
static led_strip_t *pStrip;
rmt_config_t config = RMT_DEFAULT_CONFIG_TX(gpio, channel);
// set counter clock to 40MHz
config.clk_div = 2;
ESP_ERROR_CHECK(rmt_config(&config));
ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
// install ws2812 driver
led_strip_config_t strip_config = LED_STRIP_DEFAULT_CONFIG(led_num, (led_strip_dev_t)config.channel);
pStrip = led_strip_new_rmt_ws2812(&strip_config);
if ( !pStrip ) {
ESP_LOGE(TAG, "install WS2812 driver failed");
return NULL;
}
// Clear LED strip (turn off all LEDs)
ESP_ERROR_CHECK(pStrip->clear(pStrip, 100));
return pStrip;
}
esp_err_t led_strip_denit(led_strip_t *strip)
{
ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent);
ESP_ERROR_CHECK(rmt_driver_uninstall(ws2812->rmt_channel));
return strip->del(strip);
}

Wyświetl plik

@ -0,0 +1,136 @@
/*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_check.h"
#include "driver/rmt_tx.h"
#include "led_strip.h"
#include "led_strip_interface.h"
#include "led_strip_rmt_encoder.h"
#define LED_SRIP_RMT_RESOLUTION 10000000 // 10MHz resolution
static const char *TAG = "led_strip_rmt";
typedef struct {
led_strip_t base;
rmt_channel_handle_t rmt_chan;
rmt_encoder_handle_t strip_encoder;
uint32_t strip_len;
uint8_t pixel_buf[];
} led_strip_rmt_obj;
static esp_err_t led_strip_rmt_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
{
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs");
uint32_t start = index * 3;
// In thr order of GRB, as LED strip like WS2812 sends out pixels in this order
rmt_strip->pixel_buf[start + 0] = green & 0xFF;
rmt_strip->pixel_buf[start + 1] = red & 0xFF;
rmt_strip->pixel_buf[start + 2] = blue & 0xFF;
return ESP_OK;
}
static esp_err_t led_strip_rmt_refresh(led_strip_t *strip)
{
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
rmt_transmit_config_t tx_conf = {
.loop_count = 0,
};
ESP_RETURN_ON_ERROR(rmt_transmit(rmt_strip->rmt_chan, rmt_strip->strip_encoder, rmt_strip->pixel_buf,
rmt_strip->strip_len * 3, &tx_conf), TAG, "transmit pixels by RMT failed");
ESP_RETURN_ON_ERROR(rmt_tx_wait_all_done(rmt_strip->rmt_chan, -1), TAG, "flush RMT channel failed");
return ESP_OK;
}
static esp_err_t led_strip_rmt_clear(led_strip_t *strip)
{
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
// Write zero to turn off all leds
memset(rmt_strip->pixel_buf, 0, rmt_strip->strip_len * 3);
return led_strip_rmt_refresh(strip);
}
static esp_err_t led_strip_rmt_del(led_strip_t *strip)
{
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
ESP_RETURN_ON_ERROR(rmt_disable(rmt_strip->rmt_chan), TAG, "disable RMT channel failed");
ESP_RETURN_ON_ERROR(rmt_del_channel(rmt_strip->rmt_chan), TAG, "delete RMT channel failed");
ESP_RETURN_ON_ERROR(rmt_del_encoder(rmt_strip->strip_encoder), TAG, "delete strip encoder failed");
free(rmt_strip);
return ESP_OK;
}
esp_err_t led_strip_new_rmt_device(const led_strip_config_t *config, led_strip_handle_t *ret_strip)
{
led_strip_rmt_obj *rmt_strip = NULL;
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
rmt_strip = calloc(1, sizeof(led_strip_rmt_obj) + config->max_leds * 3);
ESP_GOTO_ON_FALSE(rmt_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for rmt strip");
rmt_tx_channel_config_t rmt_chan_config = {
.clk_src = RMT_CLK_SRC_DEFAULT,
.gpio_num = config->strip_gpio_num,
.mem_block_symbols = 64,
.resolution_hz = LED_SRIP_RMT_RESOLUTION,
.trans_queue_depth = 4,
};
ESP_GOTO_ON_ERROR(rmt_new_tx_channel(&rmt_chan_config, &rmt_strip->rmt_chan), err, TAG, "create RMT TX channel failed");
led_strip_encoder_config_t strip_encoder_conf = {
.resolution = LED_SRIP_RMT_RESOLUTION,
};
ESP_GOTO_ON_ERROR(rmt_new_led_strip_encoder(&strip_encoder_conf, &rmt_strip->strip_encoder), err, TAG, "create LED strip encoder failed");
ESP_GOTO_ON_ERROR(rmt_enable(rmt_strip->rmt_chan), err, TAG, "enable RMT channel failed");
rmt_strip->strip_len = config->max_leds;
rmt_strip->base.set_pixel = led_strip_rmt_set_pixel;
rmt_strip->base.refresh = led_strip_rmt_refresh;
rmt_strip->base.clear = led_strip_rmt_clear;
rmt_strip->base.del = led_strip_rmt_del;
*ret_strip = &rmt_strip->base;
return ESP_OK;
err:
if (rmt_strip) {
if (rmt_strip->rmt_chan) {
rmt_del_channel(rmt_strip->rmt_chan);
}
if (rmt_strip->strip_encoder) {
rmt_del_encoder(rmt_strip->strip_encoder);
}
free(rmt_strip);
}
return ret;
}
esp_err_t led_strip_set_pixel(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
{
ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
return strip->set_pixel(strip, index, red, green, blue);
}
esp_err_t led_strip_refresh(led_strip_handle_t strip)
{
ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
return strip->refresh(strip);
}
esp_err_t led_strip_clear(led_strip_handle_t strip)
{
ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
return strip->clear(strip);
}
esp_err_t led_strip_del(led_strip_handle_t strip)
{
ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
return strip->del(strip);
}

Wyświetl plik

@ -0,0 +1,124 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_check.h"
#include "led_strip_rmt_encoder.h"
static const char *TAG = "led_encoder";
typedef struct {
rmt_encoder_t base;
rmt_encoder_t *bytes_encoder;
rmt_encoder_t *copy_encoder;
int state;
rmt_symbol_word_t reset_code;
} rmt_led_strip_encoder_t;
static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder;
rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder;
rmt_encode_state_t session_state = 0;
rmt_encode_state_t state = 0;
size_t encoded_symbols = 0;
switch (led_encoder->state) {
case 0: // send RGB data
encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
led_encoder->state = 1; // switch to next state when current encoding session finished
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out; // yield if there's no free space for encoding artifacts
}
// fall-through
case 1: // send reset code
encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code,
sizeof(led_encoder->reset_code), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
led_encoder->state = 0; // back to the initial encoding session
state |= RMT_ENCODING_COMPLETE;
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out; // yield if there's no free space for encoding artifacts
}
}
out:
*ret_state = state;
return encoded_symbols;
}
static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder)
{
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_del_encoder(led_encoder->bytes_encoder);
rmt_del_encoder(led_encoder->copy_encoder);
free(led_encoder);
return ESP_OK;
}
static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder)
{
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_encoder_reset(led_encoder->bytes_encoder);
rmt_encoder_reset(led_encoder->copy_encoder);
led_encoder->state = 0;
return ESP_OK;
}
esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
esp_err_t ret = ESP_OK;
rmt_led_strip_encoder_t *led_encoder = NULL;
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
led_encoder = calloc(1, sizeof(rmt_led_strip_encoder_t));
ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder");
led_encoder->base.encode = rmt_encode_led_strip;
led_encoder->base.del = rmt_del_led_strip_encoder;
led_encoder->base.reset = rmt_led_strip_encoder_reset;
// different led strip might have its own timing requirements, following parameter is for WS2812
rmt_bytes_encoder_config_t bytes_encoder_config = {
.bit0 = {
.level0 = 1,
.duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us
.level1 = 0,
.duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us
},
.bit1 = {
.level0 = 1,
.duration0 = 0.9 * config->resolution / 1000000, // T1H=0.9us
.level1 = 0,
.duration1 = 0.3 * config->resolution / 1000000, // T1L=0.3us
},
.flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0
};
ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed");
rmt_copy_encoder_config_t copy_encoder_config = {};
ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(&copy_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed");
uint32_t reset_ticks = config->resolution / 1000000 * 50 / 2; // reset code duration defaults to 50us
led_encoder->reset_code = (rmt_symbol_word_t) {
.level0 = 0,
.duration0 = reset_ticks,
.level1 = 0,
.duration1 = reset_ticks,
};
*ret_encoder = &led_encoder->base;
return ESP_OK;
err:
if (led_encoder) {
if (led_encoder->bytes_encoder) {
rmt_del_encoder(led_encoder->bytes_encoder);
}
if (led_encoder->copy_encoder) {
rmt_del_encoder(led_encoder->copy_encoder);
}
free(led_encoder);
}
return ret;
}

Wyświetl plik

@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "driver/rmt_encoder.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Type of led strip encoder configuration
*/
typedef struct {
uint32_t resolution; /*!< Encoder resolution, in Hz */
} led_strip_encoder_config_t;
/**
* @brief Create RMT encoder for encoding LED strip pixels into RMT symbols
*
* @param[in] config Encoder configuration
* @param[out] ret_encoder Returned encoder handle
* @return
* - ESP_ERR_INVALID_ARG for any invalid arguments
* - ESP_ERR_NO_MEM out of memory when creating led strip encoder
* - ESP_OK if creating encoder successfully
*/
esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder);
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -29,14 +29,12 @@ See [Development Boards](https://www.espressif.com/en/products/devkits) for more
### Configure the Project
Open the project configuration menu (`idf.py menuconfig`).
Open the project configuration menu (`idf.py menuconfig`).
In the `Example Configuration` menu:
* Select the LED type in the `Blink LED type` option.
* Use `GPIO` for regular LED blink.
* Use `RMT` for addressable LED blink.
* Use `RMT Channel` to select the RMT peripheral channel.
* Set the GPIO number used for the signal in the `Blink GPIO number` option.
* Set the blinking period in the `Blink period in ms` option.
@ -50,7 +48,7 @@ See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/l
## Example Output
As you run the example, you will see the LED blinking, according to the previously defined period. For the addressable LED, you can also change the LED color by setting the `pStrip_a->set_pixel(pStrip_a, 0, 16, 16, 16);` (LED Strip, Pixel Number, Red, Green, Blue) with values from 0 to 255 in the `blink.c` file.
As you run the example, you will see the LED blinking, according to the previously defined period. For the addressable LED, you can also change the LED color by setting the `led_strip_set_pixel(pStrip_a, 0, 16, 16, 16);` (LED Strip, Pixel Number, Red, Green, Blue) with values from 0 to 255 in the `blink.c` file.
```
I (315) example: Example configured to blink addressable LED!

Wyświetl plik

@ -13,18 +13,6 @@ menu "Example Configuration"
bool "RMT - Addressable LED"
endchoice
config BLINK_LED_RMT_CHANNEL
depends on BLINK_LED_RMT
int "RMT Channel"
range 0 7
default 0
help
Set the RMT peripheral channel.
ESP32 RMT channel from 0 to 7
ESP32-S2 RMT channel from 0 to 3
ESP32-S3 RMT channel from 0 to 3
ESP32-C3 RMT channel from 0 to 1
config BLINK_GPIO
int "Blink GPIO number"
range 0 48

Wyświetl plik

@ -24,19 +24,20 @@ static const char *TAG = "example";
static uint8_t s_led_state = 0;
#ifdef CONFIG_BLINK_LED_RMT
static led_strip_t *pStrip_a;
static led_strip_handle_t led_strip;
static void blink_led(void)
{
/* If the addressable LED is enabled */
if (s_led_state) {
/* Set the LED pixel using RGB from 0 (0%) to 255 (100%) for each color */
pStrip_a->set_pixel(pStrip_a, 0, 16, 16, 16);
led_strip_set_pixel(led_strip, 0, 16, 16, 16);
/* Refresh the strip to send data */
pStrip_a->refresh(pStrip_a, 100);
led_strip_refresh(led_strip);
} else {
/* Set all LED off to clear all pixels */
pStrip_a->clear(pStrip_a, 50);
led_strip_clear(led_strip);
}
}
@ -44,9 +45,13 @@ static void configure_led(void)
{
ESP_LOGI(TAG, "Example configured to blink addressable LED!");
/* LED strip initialization with the GPIO and pixels number*/
pStrip_a = led_strip_init(CONFIG_BLINK_LED_RMT_CHANNEL, BLINK_GPIO, 1);
led_strip_config_t strip_config = {
.strip_gpio_num = BLINK_GPIO,
.max_leds = 1, // at least one LED on board
};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &led_strip));
/* Set all LED off to clear all pixels */
pStrip_a->clear(pStrip_a, 50);
led_strip_clear(led_strip);
}
#elif CONFIG_BLINK_LED_GPIO

Wyświetl plik

@ -2,7 +2,5 @@
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/led_strip)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(led_strip)

Wyświetl plik

@ -1,37 +1,34 @@
| Supported Targets | ESP32 | ESP32-S2 | ESP32-C3 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- |
# RMT Transmit Example -- LED Strip
(See the README.md file in the upper level 'examples' directory for more information about examples.)
Although RMT peripheral is mainly designed for infrared remote applications, it can also support other generic protocols thanks to its flexible data format. [WS2812](http://www.world-semi.com/Certifications/WS2812B.html) is a digital RGB LED which integrates a driver circuit and a single control wire. The protocol data format defined in WS2812 is compatible to that in RMT peripheral. This example will illustrate how to drive an WS2812 LED strip based on the RMT driver.
Almost any waveform can be generated by RMT peripheral, as long as a proper encoder is implemented. The RMT encoder is used to encode user data (e.g. RGB pixels) into format that can be recognized by hardware.
This example shows how to drive an addressable LED strip [WS2812](http://www.world-semi.com/Certifications/WS2812B.html) by implementing the [led_strip_encoder](main/led_strip_encoder.c).
## How to Use Example
### Hardware Required
* A development board with ESP32 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
* A development board with any supported Espressif SOC chip (see `Supported Targets` table above)
* A USB cable for Power supply and programming
* A WS2812 LED strip
Connection :
```
--- 5V
|
+
GPIO18 +-----------------+---|>| (WS2812)
DI +
|
--- GND
--- 5V
|
+
RMT_LED_STRIP_GPIO_NUM +------ +---|>| (WS2812 LED strip)
DI +
|
--- GND
```
### Configure the Project
Open the project configuration menu (`idf.py menuconfig`).
In the `Example Configuration` menu:
* Set the GPIO number used for transmitting the IR signal under `RMT TX GPIO` option.
* Set the number of LEDs in a strip under `Number of LEDS in a strip` option.
The GPIO number used in this example can be changed according to your board, by the macro `RMT_LED_STRIP_GPIO_NUM` defined in the [source file](main/led_strip_example_main.c). The number of LEDs can be changed as well by `EXAMPLE_LED_NUMBERS`.
### Build and Flash
@ -41,11 +38,18 @@ Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Output
## Console Output
Connect the `DI` signal of WS2812 LED strip to the GPIO you set in menuconfig.
```
I (302) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (323) example: Create RMT TX channel
I (343) example: Install led strip encoder
I (353) example: Start LED rainbow chase
```
Run the example, you will see a rainbow chasing demonstration effect. To change the chasing speed, you can update the `EXAMPLE_CHASE_SPEED_MS` value in `led_strip_main.c` file.
After you seeing this log, you should see a rainbow chasing demonstration pattern. To change the chasing speed, you can update the `EXAMPLE_CHASE_SPEED_MS` value in [source file](main/led_strip_example_main.c).
## Troubleshooting

Wyświetl plik

@ -1,2 +1,2 @@
idf_component_register(SRCS "led_strip_main.c"
idf_component_register(SRCS "led_strip_example_main.c" "led_strip_encoder.c"
INCLUDE_DIRS ".")

Wyświetl plik

@ -1,13 +0,0 @@
menu "Example Configuration"
config EXAMPLE_RMT_TX_GPIO
int "RMT TX GPIO"
default 18
help
Set the GPIO number used for transmitting the RMT signal.
config EXAMPLE_STRIP_LED_NUMBER
int "Number of LEDS in a strip"
default 24
help
A single RGB strip contains several LEDs.
endmenu

Wyświetl plik

@ -0,0 +1,124 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_check.h"
#include "led_strip_encoder.h"
static const char *TAG = "led_encoder";
typedef struct {
rmt_encoder_t base;
rmt_encoder_t *bytes_encoder;
rmt_encoder_t *copy_encoder;
int state;
rmt_symbol_word_t reset_code;
} rmt_led_strip_encoder_t;
static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder;
rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder;
rmt_encode_state_t session_state = 0;
rmt_encode_state_t state = 0;
size_t encoded_symbols = 0;
switch (led_encoder->state) {
case 0: // send RGB data
encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
led_encoder->state = 1; // switch to next state when current encoding session finished
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out; // yield if there's no free space for encoding artifacts
}
// fall-through
case 1: // send reset code
encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code,
sizeof(led_encoder->reset_code), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
led_encoder->state = 0; // back to the initial encoding session
state |= RMT_ENCODING_COMPLETE;
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out; // yield if there's no free space for encoding artifacts
}
}
out:
*ret_state = state;
return encoded_symbols;
}
static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder)
{
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_del_encoder(led_encoder->bytes_encoder);
rmt_del_encoder(led_encoder->copy_encoder);
free(led_encoder);
return ESP_OK;
}
static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder)
{
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_encoder_reset(led_encoder->bytes_encoder);
rmt_encoder_reset(led_encoder->copy_encoder);
led_encoder->state = 0;
return ESP_OK;
}
esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
esp_err_t ret = ESP_OK;
rmt_led_strip_encoder_t *led_encoder = NULL;
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
led_encoder = calloc(1, sizeof(rmt_led_strip_encoder_t));
ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder");
led_encoder->base.encode = rmt_encode_led_strip;
led_encoder->base.del = rmt_del_led_strip_encoder;
led_encoder->base.reset = rmt_led_strip_encoder_reset;
// different led strip might have its own timing requirements, following parameter is for WS2812
rmt_bytes_encoder_config_t bytes_encoder_config = {
.bit0 = {
.level0 = 1,
.duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us
.level1 = 0,
.duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us
},
.bit1 = {
.level0 = 1,
.duration0 = 0.9 * config->resolution / 1000000, // T1H=0.9us
.level1 = 0,
.duration1 = 0.3 * config->resolution / 1000000, // T1L=0.3us
},
.flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0
};
ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed");
rmt_copy_encoder_config_t copy_encoder_config = {};
ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(&copy_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed");
uint32_t reset_ticks = config->resolution / 1000000 * 50 / 2; // reset code duration defaults to 50us
led_encoder->reset_code = (rmt_symbol_word_t) {
.level0 = 0,
.duration0 = reset_ticks,
.level1 = 0,
.duration1 = reset_ticks,
};
*ret_encoder = &led_encoder->base;
return ESP_OK;
err:
if (led_encoder) {
if (led_encoder->bytes_encoder) {
rmt_del_encoder(led_encoder->bytes_encoder);
}
if (led_encoder->copy_encoder) {
rmt_del_encoder(led_encoder->copy_encoder);
}
free(led_encoder);
}
return ret;
}

Wyświetl plik

@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "driver/rmt_encoder.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Type of led strip encoder configuration
*/
typedef struct {
uint32_t resolution; /*!< Encoder resolution, in Hz */
} led_strip_encoder_config_t;
/**
* @brief Create RMT encoder for encoding LED strip pixels into RMT symbols
*
* @param[in] config Encoder configuration
* @param[out] ret_encoder Returned encoder handle
* @return
* - ESP_ERR_INVALID_ARG for any invalid arguments
* - ESP_ERR_NO_MEM out of memory when creating led strip encoder
* - ESP_OK if creating encoder successfully
*/
esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder);
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -0,0 +1,128 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/rmt_tx.h"
#include "led_strip_encoder.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 0
#define EXAMPLE_LED_NUMBERS 24
#define EXAMPLE_CHASE_SPEED_MS 10
static const char *TAG = "example";
static uint8_t led_strip_pixels[EXAMPLE_LED_NUMBERS * 3];
/**
* @brief Simple helper function, converting HSV color space to RGB color space
*
* Wiki: https://en.wikipedia.org/wiki/HSL_and_HSV
*
*/
void led_strip_hsv2rgb(uint32_t h, uint32_t s, uint32_t v, uint32_t *r, uint32_t *g, uint32_t *b)
{
h %= 360; // h -> [0,360]
uint32_t rgb_max = v * 2.55f;
uint32_t rgb_min = rgb_max * (100 - s) / 100.0f;
uint32_t i = h / 60;
uint32_t diff = h % 60;
// RGB adjustment amount by hue
uint32_t rgb_adj = (rgb_max - rgb_min) * diff / 60;
switch (i) {
case 0:
*r = rgb_max;
*g = rgb_min + rgb_adj;
*b = rgb_min;
break;
case 1:
*r = rgb_max - rgb_adj;
*g = rgb_max;
*b = rgb_min;
break;
case 2:
*r = rgb_min;
*g = rgb_max;
*b = rgb_min + rgb_adj;
break;
case 3:
*r = rgb_min;
*g = rgb_max - rgb_adj;
*b = rgb_max;
break;
case 4:
*r = rgb_min + rgb_adj;
*g = rgb_min;
*b = rgb_max;
break;
default:
*r = rgb_max;
*g = rgb_min;
*b = rgb_max - rgb_adj;
break;
}
}
void app_main(void)
{
uint32_t red = 0;
uint32_t green = 0;
uint32_t blue = 0;
uint16_t hue = 0;
uint16_t start_rgb = 0;
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, "Install led strip encoder");
rmt_encoder_handle_t led_encoder = NULL;
led_strip_encoder_config_t encoder_config = {
.resolution = RMT_LED_STRIP_RESOLUTION_HZ,
};
ESP_ERROR_CHECK(rmt_new_led_strip_encoder(&encoder_config, &led_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
};
while (1) {
for (int i = 0; i < 3; i++) {
for (int j = i; j < EXAMPLE_LED_NUMBERS; j += 3) {
// Build RGB pixels
hue = j * 360 / EXAMPLE_LED_NUMBERS + start_rgb;
led_strip_hsv2rgb(hue, 100, 100, &red, &green, &blue);
led_strip_pixels[j * 3 + 0] = green;
led_strip_pixels[j * 3 + 1] = blue;
led_strip_pixels[j * 3 + 2] = red;
}
// Flush RGB values to LEDs
ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, led_strip_pixels, sizeof(led_strip_pixels), &tx_config));
vTaskDelay(pdMS_TO_TICKS(EXAMPLE_CHASE_SPEED_MS));
memset(led_strip_pixels, 0, sizeof(led_strip_pixels));
ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, led_strip_pixels, sizeof(led_strip_pixels), &tx_config));
vTaskDelay(pdMS_TO_TICKS(EXAMPLE_CHASE_SPEED_MS));
}
start_rgb += 60;
}
}

Wyświetl plik

@ -1,116 +0,0 @@
/* RMT example -- RGB LED Strip
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/rmt.h"
#include "led_strip.h"
static const char *TAG = "example";
#define RMT_TX_CHANNEL RMT_CHANNEL_0
#define EXAMPLE_CHASE_SPEED_MS (10)
/**
* @brief Simple helper function, converting HSV color space to RGB color space
*
* Wiki: https://en.wikipedia.org/wiki/HSL_and_HSV
*
*/
void led_strip_hsv2rgb(uint32_t h, uint32_t s, uint32_t v, uint32_t *r, uint32_t *g, uint32_t *b)
{
h %= 360; // h -> [0,360]
uint32_t rgb_max = v * 2.55f;
uint32_t rgb_min = rgb_max * (100 - s) / 100.0f;
uint32_t i = h / 60;
uint32_t diff = h % 60;
// RGB adjustment amount by hue
uint32_t rgb_adj = (rgb_max - rgb_min) * diff / 60;
switch (i) {
case 0:
*r = rgb_max;
*g = rgb_min + rgb_adj;
*b = rgb_min;
break;
case 1:
*r = rgb_max - rgb_adj;
*g = rgb_max;
*b = rgb_min;
break;
case 2:
*r = rgb_min;
*g = rgb_max;
*b = rgb_min + rgb_adj;
break;
case 3:
*r = rgb_min;
*g = rgb_max - rgb_adj;
*b = rgb_max;
break;
case 4:
*r = rgb_min + rgb_adj;
*g = rgb_min;
*b = rgb_max;
break;
default:
*r = rgb_max;
*g = rgb_min;
*b = rgb_max - rgb_adj;
break;
}
}
void app_main(void)
{
uint32_t red = 0;
uint32_t green = 0;
uint32_t blue = 0;
uint16_t hue = 0;
uint16_t start_rgb = 0;
rmt_config_t config = RMT_DEFAULT_CONFIG_TX(CONFIG_EXAMPLE_RMT_TX_GPIO, RMT_TX_CHANNEL);
// set counter clock to 40MHz
config.clk_div = 2;
ESP_ERROR_CHECK(rmt_config(&config));
ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
// install ws2812 driver
led_strip_config_t strip_config = LED_STRIP_DEFAULT_CONFIG(CONFIG_EXAMPLE_STRIP_LED_NUMBER, (led_strip_dev_t)config.channel);
led_strip_t *strip = led_strip_new_rmt_ws2812(&strip_config);
if (!strip) {
ESP_LOGE(TAG, "install WS2812 driver failed");
}
// Clear LED strip (turn off all LEDs)
ESP_ERROR_CHECK(strip->clear(strip, 100));
// Show simple rainbow chasing pattern
ESP_LOGI(TAG, "LED Rainbow Chase Start");
while (true) {
for (int i = 0; i < 3; i++) {
for (int j = i; j < CONFIG_EXAMPLE_STRIP_LED_NUMBER; j += 3) {
// Build RGB values
hue = j * 360 / CONFIG_EXAMPLE_STRIP_LED_NUMBER + start_rgb;
led_strip_hsv2rgb(hue, 100, 100, &red, &green, &blue);
// Write RGB values to strip driver
ESP_ERROR_CHECK(strip->set_pixel(strip, j, red, green, blue));
}
// Flush RGB values to LEDs
ESP_ERROR_CHECK(strip->refresh(strip, 100));
vTaskDelay(pdMS_TO_TICKS(EXAMPLE_CHASE_SPEED_MS));
strip->clear(strip, 50);
vTaskDelay(pdMS_TO_TICKS(EXAMPLE_CHASE_SPEED_MS));
}
start_rgb += 60;
}
}

Wyświetl plik

@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32
@pytest.mark.esp32s2
@pytest.mark.esp32s3
@pytest.mark.esp32c3
@pytest.mark.generic
def test_led_strip_example(dut: Dut) -> None:
dut.expect_exact('example: Create RMT TX channel')
dut.expect_exact('example: Install led strip encoder')
dut.expect_exact('example: Enable RMT TX channel')
dut.expect_exact('example: Start LED rainbow chase')

Wyświetl plik

@ -39,17 +39,20 @@
#include "led_strip.h"
#include "light_driver.h"
static led_strip_t *led_strip;
static led_strip_handle_t s_led_strip;
void light_driver_set_power(bool power)
{
ESP_ERROR_CHECK(led_strip->set_pixel(led_strip, 0, 255 * power, 255 * power, 255 * power));
ESP_ERROR_CHECK(led_strip->refresh(led_strip, 100));
ESP_ERROR_CHECK(led_strip_set_pixel(s_led_strip, 0, 255 * power, 255 * power, 255 * power));
ESP_ERROR_CHECK(led_strip_refresh(s_led_strip));
}
int light_driver_init(bool power)
void light_driver_init(bool power)
{
led_strip = led_strip_init(RMT_TX_CHANNEL, CONFIG_EXAMPLE_RMT_TX_GPIO, CONFIG_EXAMPLE_STRIP_LED_NUMBER);
led_strip_config_t led_strip_conf = {
.max_leds = CONFIG_EXAMPLE_STRIP_LED_NUMBER,
.strip_gpio_num = CONFIG_EXAMPLE_STRIP_LED_GPIO,
};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&led_strip_conf, &s_led_strip));
light_driver_set_power(power);
return ESP_OK;
}

Wyświetl plik

@ -37,8 +37,7 @@
#pragma once
#include "driver/rmt.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
@ -49,8 +48,7 @@ extern "C" {
#define LIGHT_DEFAULT_OFF 0
/* LED strip configuration */
#define RMT_TX_CHANNEL RMT_CHANNEL_0
#define CONFIG_EXAMPLE_RMT_TX_GPIO 8
#define CONFIG_EXAMPLE_STRIP_LED_GPIO 8
#define CONFIG_EXAMPLE_STRIP_LED_NUMBER 1
/**
@ -65,7 +63,7 @@ void light_driver_set_power(bool power);
*
* @param power power on/off
*/
int light_driver_init(bool power);
void light_driver_init(bool power);
#ifdef __cplusplus
} // extern "C"

Wyświetl plik

@ -1975,7 +1975,6 @@ examples/build_system/cmake/multi_config/main/func_prod.c
examples/build_system/cmake/multi_config/main/multi_config_example_main.c
examples/common_components/iperf/include/iperf.h
examples/common_components/iperf/iperf.c
examples/common_components/led_strip/include/led_strip.h
examples/common_components/protocol_examples_common/addr_from_stdin.c
examples/common_components/protocol_examples_common/connect.c
examples/common_components/protocol_examples_common/include/addr_from_stdin.h
@ -2073,7 +2072,6 @@ examples/peripherals/mcpwm/mcpwm_brushed_dc_control/main/mcpwm_brushed_dc_contro
examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/main/mcpwm_capture_hc_sr04.c
examples/peripherals/mcpwm/mcpwm_servo_control/main/mcpwm_servo_control_example_main.c
examples/peripherals/mcpwm/mcpwm_sync_example/main/mcpwm_sync_example.c
examples/peripherals/rmt/led_strip/main/led_strip_main.c
examples/peripherals/rmt/morse_code/main/morse_code_main.c
examples/peripherals/rmt/musical_buzzer/components/musical_buzzer/include/musical_buzzer.h
examples/peripherals/rmt/musical_buzzer/components/musical_buzzer/src/musical_buzzer_rmt.c