led_strip: support dma feature and various clock source

This commit is contained in:
suda-morris 2022-12-22 13:38:07 +08:00
parent 867af76848
commit 9ad87cdff0
6 changed files with 112 additions and 42 deletions

View File

@ -1,12 +1,34 @@
# LED Strip Component
# LED Strip Driver
[![Component Registry](https://components.espressif.com/components/espressif/led_strip/badge.svg)](https://components.espressif.com/components/espressif/led_strip)
This directory contains an implementation for addressable LEDs by different peripherals. Currently only RMT is supported as the led strip backend.
This driver is designed for addressable LEDs like [WS2812](http://www.world-semi.com/Certifications/WS2812B.html), where each LED is controlled by a single data line.
The driver should be compatible with:
## Backend Controllers
* [WS2812](http://www.world-semi.com/Certifications/WS2812B.html)
* SK68XX
### The [RMT](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/rmt.html) Peripheral
To learn more about how to use this component, please check API Documentation from header file [led_strip.h](./include/led_strip.h).
This is the most economical way to drive the LEDs because it only consumes one RMT channel, leaving other channels free to use. However, the memory usage increases dramatically with the number of LEDs. If the RMT hardware can't be assist by DMA, the driver will going into interrupt very frequently, thus result in a high CPU usage. What's worse, if the RMT interrupt is delayed or not serviced in time (e.g. if Wi-Fi interrupt happens on the same CPU core), the RMT transaction will be corrupted and the LEDs will display incorrect colors. If you want to use RMT to drive a large number of LEDs, you'd better to enable the DMA feature if possible. [^1]
#### Allocate LED Strip Object with RMT Backend
```c
#define BLINK_GPIO 0
led_strip_handle_t led_strip;
/* LED strip initialization with the GPIO and pixels number*/
led_strip_config_t strip_config = {
.strip_gpio_num = BLINK_GPIO, // The GPIO that connected to the LED strip's data line
.max_leds = 1, // The number of LEDs in the strip
};
led_strip_rmt_config_t rmt_config = {
.clk_src = RMT_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption
.resolution_hz = 10 * 1000 * 1000, // 10MHz
.flags.with_dma = false, // wether to enable the DMA feature
};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip));
```
[^1]: The DMA feature is not available on all ESP chips. Please check the data sheet before using it.

View File

@ -1,4 +1,4 @@
version: "2.0.0"
version: "2.1.0"
description: Driver for Addressable LED Strip (WS2812, etc)
url: https://github.com/espressif/idf-extra-components/tree/master/led_strip
dependencies:

View File

@ -7,16 +7,12 @@
#include <stdint.h>
#include "esp_err.h"
#include "led_strip_rmt.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief LED strip handle
*/
typedef struct led_strip_t *led_strip_handle_t;
/**
* @brief Set RGB for a specific pixel
*
@ -69,35 +65,6 @@ esp_err_t led_strip_clear(led_strip_handle_t strip);
*/
esp_err_t led_strip_del(led_strip_handle_t strip);
/**
* @brief LED Strip Configuration
*/
typedef struct {
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 LED Strip RMT specific configuration
*/
typedef struct {
uint32_t resolution_hz; /*!< RMT tick resolution, if set to zero, a default resolution (10MHz) will be applied */
} led_strip_rmt_config_t;
/**
* @brief Create LED strip based on RMT TX channel
*
* @param led_config LED strip configuration
* @param rmt_config RMT specific configuration
* @param ret_strip Returned LED strip handle
* @return
* - 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
*/
esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const led_strip_rmt_config_t *rmt_config, led_strip_handle_t *ret_strip);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,45 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
#include "driver/rmt_types.h"
#include "led_strip_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief LED Strip RMT specific configuration
*/
typedef struct {
rmt_clock_source_t clk_src; /*!< RMT clock source */
uint32_t resolution_hz; /*!< RMT tick resolution, if set to zero, a default resolution (10MHz) will be applied */
struct {
uint32_t with_dma: 1; /*!< Use DMA to transmit data */
} flags;
} led_strip_rmt_config_t;
/**
* @brief Create LED strip based on RMT TX channel
*
* @param led_config LED strip configuration
* @param rmt_config RMT specific configuration
* @param ret_strip Returned LED strip handle
* @return
* - 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
*/
esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const led_strip_rmt_config_t *rmt_config, led_strip_handle_t *ret_strip);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,29 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief LED strip handle
*/
typedef struct led_strip_t *led_strip_handle_t;
/**
* @brief LED Strip Configuration
*/
typedef struct {
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;
#ifdef __cplusplus
}
#endif

View File

@ -75,12 +75,19 @@ esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const l
rmt_strip = calloc(1, sizeof(led_strip_rmt_obj) + led_config->max_leds * 3);
ESP_GOTO_ON_FALSE(rmt_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for rmt strip");
uint32_t resolution = rmt_config->resolution_hz ? rmt_config->resolution_hz : LED_STRIP_RMT_DEFAULT_RESOLUTION;
// for backward compatibility, if the user does not set the clk_src, use the default value
rmt_clock_source_t clk_src = RMT_CLK_SRC_DEFAULT;
if (rmt_config->clk_src) {
clk_src = rmt_config->clk_src;
}
rmt_tx_channel_config_t rmt_chan_config = {
.clk_src = RMT_CLK_SRC_DEFAULT,
.clk_src = clk_src,
.gpio_num = led_config->strip_gpio_num,
.mem_block_symbols = 64,
.resolution_hz = resolution,
.trans_queue_depth = 4,
.flags.with_dma = rmt_config->flags.with_dma,
};
ESP_GOTO_ON_ERROR(rmt_new_tx_channel(&rmt_chan_config, &rmt_strip->rmt_chan), err, TAG, "create RMT TX channel failed");