ESP-IDF Firmware
Firmware architecture and call graph
Loading...
Searching...
No Matches
led_strip_rmt_dev.c
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6#include <stdlib.h>
7#include <string.h>
8#include <sys/cdefs.h>
9#include "esp_log.h"
10#include "esp_check.h"
11#include "driver/rmt_tx.h"
12#include "led_strip.h"
13#include "led_strip_interface.h"
15
16#define LED_STRIP_RMT_DEFAULT_RESOLUTION 10000000 // 10MHz resolution
17#define LED_STRIP_RMT_DEFAULT_TRANS_QUEUE_SIZE 4
18// the memory size of each RMT channel, in words (4 bytes)
19#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
20#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 64
21#else
22#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 48
23#endif
24
25static const char *TAG = "led_strip_rmt";
26
27typedef struct {
29 rmt_channel_handle_t rmt_chan;
30 rmt_encoder_handle_t strip_encoder;
31 uint32_t strip_len;
33 uint8_t pixel_buf[];
35
36static esp_err_t led_strip_rmt_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
37{
38 led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
39 ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs");
40 uint32_t start = index * rmt_strip->bytes_per_pixel;
41 // In thr order of GRB, as LED strip like WS2812 sends out pixels in this order
42 rmt_strip->pixel_buf[start + 0] = green & 0xFF;
43 rmt_strip->pixel_buf[start + 1] = red & 0xFF;
44 rmt_strip->pixel_buf[start + 2] = blue & 0xFF;
45 if (rmt_strip->bytes_per_pixel > 3) {
46 rmt_strip->pixel_buf[start + 3] = 0;
47 }
48 return ESP_OK;
49}
50
51static esp_err_t led_strip_rmt_set_pixel_rgbw(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white)
52{
53 led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
54 ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs");
55 ESP_RETURN_ON_FALSE(rmt_strip->bytes_per_pixel == 4, ESP_ERR_INVALID_ARG, TAG, "wrong LED pixel format, expected 4 bytes per pixel");
56 uint8_t *buf_start = rmt_strip->pixel_buf + index * 4;
57 // SK6812 component order is GRBW
58 *buf_start = green & 0xFF;
59 *++buf_start = red & 0xFF;
60 *++buf_start = blue & 0xFF;
61 *++buf_start = white & 0xFF;
62 return ESP_OK;
63}
64
66{
67 led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
68 rmt_transmit_config_t tx_conf = {
69 .loop_count = 0,
70 };
71
72 ESP_RETURN_ON_ERROR(rmt_enable(rmt_strip->rmt_chan), TAG, "enable RMT channel failed");
73 ESP_RETURN_ON_ERROR(rmt_transmit(rmt_strip->rmt_chan, rmt_strip->strip_encoder, rmt_strip->pixel_buf,
74 rmt_strip->strip_len * rmt_strip->bytes_per_pixel, &tx_conf), TAG, "transmit pixels by RMT failed");
75 ESP_RETURN_ON_ERROR(rmt_tx_wait_all_done(rmt_strip->rmt_chan, -1), TAG, "flush RMT channel failed");
76 ESP_RETURN_ON_ERROR(rmt_disable(rmt_strip->rmt_chan), TAG, "disable RMT channel failed");
77 return ESP_OK;
78}
79
81{
82 led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
83 // Write zero to turn off all leds
84 memset(rmt_strip->pixel_buf, 0, rmt_strip->strip_len * rmt_strip->bytes_per_pixel);
85 return led_strip_rmt_refresh(strip);
86}
87
89{
90 led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
91 ESP_RETURN_ON_ERROR(rmt_del_channel(rmt_strip->rmt_chan), TAG, "delete RMT channel failed");
92 ESP_RETURN_ON_ERROR(rmt_del_encoder(rmt_strip->strip_encoder), TAG, "delete strip encoder failed");
93 free(rmt_strip);
94 return ESP_OK;
95}
96
98{
99 led_strip_rmt_obj *rmt_strip = NULL;
100 esp_err_t ret = ESP_OK;
101 ESP_GOTO_ON_FALSE(led_config && rmt_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
102 ESP_GOTO_ON_FALSE(led_config->led_pixel_format < LED_PIXEL_FORMAT_INVALID, ESP_ERR_INVALID_ARG, err, TAG, "invalid led_pixel_format");
103 uint8_t bytes_per_pixel = 3;
104 if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRBW) {
105 bytes_per_pixel = 4;
106 } else if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRB) {
107 bytes_per_pixel = 3;
108 } else {
109 assert(false);
110 }
111 rmt_strip = calloc(1, sizeof(led_strip_rmt_obj) + led_config->max_leds * bytes_per_pixel);
112 ESP_GOTO_ON_FALSE(rmt_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for rmt strip");
113 uint32_t resolution = rmt_config->resolution_hz ? rmt_config->resolution_hz : LED_STRIP_RMT_DEFAULT_RESOLUTION;
114
115 // for backward compatibility, if the user does not set the clk_src, use the default value
116 rmt_clock_source_t clk_src = RMT_CLK_SRC_DEFAULT;
117 if (rmt_config->clk_src) {
118 clk_src = rmt_config->clk_src;
119 }
120 size_t mem_block_symbols = LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS;
121 // override the default value if the user sets it
122 if (rmt_config->mem_block_symbols) {
123 mem_block_symbols = rmt_config->mem_block_symbols;
124 }
125 rmt_tx_channel_config_t rmt_chan_config = {
126 .clk_src = clk_src,
127 .gpio_num = led_config->strip_gpio_num,
128 .mem_block_symbols = mem_block_symbols,
129 .resolution_hz = resolution,
130 .trans_queue_depth = LED_STRIP_RMT_DEFAULT_TRANS_QUEUE_SIZE,
131 .flags.with_dma = rmt_config->flags.with_dma,
132 .flags.invert_out = led_config->flags.invert_out,
133 };
134 ESP_GOTO_ON_ERROR(rmt_new_tx_channel(&rmt_chan_config, &rmt_strip->rmt_chan), err, TAG, "create RMT TX channel failed");
135
136 led_strip_encoder_config_t strip_encoder_conf = {
137 .resolution = resolution,
138 .led_model = led_config->led_model
139 };
140 ESP_GOTO_ON_ERROR(rmt_new_led_strip_encoder(&strip_encoder_conf, &rmt_strip->strip_encoder), err, TAG, "create LED strip encoder failed");
141
142
143 rmt_strip->bytes_per_pixel = bytes_per_pixel;
144 rmt_strip->strip_len = led_config->max_leds;
148 rmt_strip->base.clear = led_strip_rmt_clear;
149 rmt_strip->base.del = led_strip_rmt_del;
150
151 *ret_strip = &rmt_strip->base;
152 return ESP_OK;
153err:
154 if (rmt_strip) {
155 if (rmt_strip->rmt_chan) {
156 rmt_del_channel(rmt_strip->rmt_chan);
157 }
158 if (rmt_strip->strip_encoder) {
159 rmt_del_encoder(rmt_strip->strip_encoder);
160 }
161 free(rmt_strip);
162 }
163 return ret;
164}
#define ESP_RETURN_ON_ERROR(x, log_tag, format,...)
#define ESP_GOTO_ON_ERROR(x, goto_tag, log_tag, format,...)
int esp_err_t
Definition esp_err.h:21
#define ESP_OK
Definition esp_err.h:23
static esp_err_t led_strip_rmt_refresh(led_strip_t *strip)
static esp_err_t led_strip_rmt_set_pixel_rgbw(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white)
#define LED_STRIP_RMT_DEFAULT_TRANS_QUEUE_SIZE
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)
static esp_err_t led_strip_rmt_clear(led_strip_t *strip)
#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS
static esp_err_t led_strip_rmt_del(led_strip_t *strip)
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)
Create LED strip based on RMT TX channel.
#define LED_STRIP_RMT_DEFAULT_RESOLUTION
esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
Create RMT encoder for encoding LED strip pixels into RMT symbols.
@ LED_PIXEL_FORMAT_GRB
@ LED_PIXEL_FORMAT_INVALID
@ LED_PIXEL_FORMAT_GRBW
struct led_strip_t * led_strip_handle_t
LED strip handle.
static const char * TAG
Definition main/main.c:31
LED Strip Configuration.
led_pixel_format_t led_pixel_format
struct led_strip_config_t::@145177150267040163336221331365072267202117177200 flags
Type of led strip encoder configuration.
LED Strip RMT specific configuration.
rmt_clock_source_t clk_src
struct led_strip_rmt_config_t::@177205126266303010206200207206146127175132325264 flags
rmt_channel_handle_t rmt_chan
rmt_encoder_handle_t strip_encoder
LED strip interface definition.
esp_err_t(* refresh)(led_strip_t *strip)
Refresh memory colors to LEDs.
esp_err_t(* set_pixel)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
Set RGB for a specific pixel.
esp_err_t(* del)(led_strip_t *strip)
Free LED strip resources.
esp_err_t(* set_pixel_rgbw)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white)
Set RGBW for a specific pixel. Similar to set_pixel but also set the white component.
esp_err_t(* clear)(led_strip_t *strip)
Clear LED strip (turn off all LEDs).