ESP-IDF Firmware
Firmware architecture and call graph
Loading...
Searching...
No Matches
led_strip_rmt_dev_idf4.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.h"
12#include "led_strip.h"
13#include "led_strip_interface.h"
14
15static const char *TAG = "led_strip_rmt";
16
17#define WS2812_T0H_NS (300)
18#define WS2812_T0L_NS (900)
19#define WS2812_T1H_NS (900)
20#define WS2812_T1L_NS (300)
21
22#define SK6812_T0H_NS (300)
23#define SK6812_T0L_NS (900)
24#define SK6812_T1H_NS (600)
25#define SK6812_T1L_NS (600)
26
27#define LED_STRIP_RESET_MS (10)
28
29// the memory size of each RMT channel, in words (4 bytes)
30#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
31#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 64
32#else
33#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 48
34#endif
35
36static uint32_t led_t0h_ticks = 0;
37static uint32_t led_t1h_ticks = 0;
38static uint32_t led_t0l_ticks = 0;
39static uint32_t led_t1l_ticks = 0;
40
41typedef struct {
42 led_strip_t base;
43 rmt_channel_t rmt_channel;
44 uint32_t strip_len;
45 uint8_t bytes_per_pixel;
46 uint8_t buffer[0];
48
49static void IRAM_ATTR ws2812_rmt_adapter(const void *src, rmt_item32_t *dest, size_t src_size,
50 size_t wanted_num, size_t *translated_size, size_t *item_num)
51{
52 if (src == NULL || dest == NULL) {
53 *translated_size = 0;
54 *item_num = 0;
55 return;
56 }
57 const rmt_item32_t bit0 = {{{ led_t0h_ticks, 1, led_t0l_ticks, 0 }}}; //Logical 0
58 const rmt_item32_t bit1 = {{{ led_t1h_ticks, 1, led_t1l_ticks, 0 }}}; //Logical 1
59 size_t size = 0;
60 size_t num = 0;
61 uint8_t *psrc = (uint8_t *)src;
62 rmt_item32_t *pdest = dest;
63 while (size < src_size && num < wanted_num) {
64 for (int i = 0; i < 8; i++) {
65 // MSB first
66 if (*psrc & (1 << (7 - i))) {
67 pdest->val = bit1.val;
68 } else {
69 pdest->val = bit0.val;
70 }
71 num++;
72 pdest++;
73 }
74 size++;
75 psrc++;
76 }
77 *translated_size = size;
78 *item_num = num;
79}
80
81static esp_err_t led_strip_rmt_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
82{
83 led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
84 ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of the maximum number of leds");
85 uint32_t start = index * rmt_strip->bytes_per_pixel;
86 // In thr order of GRB
87 rmt_strip->buffer[start + 0] = green & 0xFF;
88 rmt_strip->buffer[start + 1] = red & 0xFF;
89 rmt_strip->buffer[start + 2] = blue & 0xFF;
90 if (rmt_strip->bytes_per_pixel > 3) {
91 rmt_strip->buffer[start + 3] = 0;
92 }
93 return ESP_OK;
94}
95
97{
98 led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
99 ESP_RETURN_ON_ERROR(rmt_write_sample(rmt_strip->rmt_channel, rmt_strip->buffer, rmt_strip->strip_len * rmt_strip->bytes_per_pixel, true), TAG,
100 "transmit RMT samples failed");
101 vTaskDelay(pdMS_TO_TICKS(LED_STRIP_RESET_MS));
102 return ESP_OK;
103}
104
106{
107 led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
108 // Write zero to turn off all LEDs
109 memset(rmt_strip->buffer, 0, rmt_strip->strip_len * rmt_strip->bytes_per_pixel);
110 return led_strip_rmt_refresh(strip);
111}
112
114{
115 led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
116 ESP_RETURN_ON_ERROR(rmt_driver_uninstall(rmt_strip->rmt_channel), TAG, "uninstall RMT driver failed");
117 free(rmt_strip);
118 return ESP_OK;
119}
120
122{
123 led_strip_rmt_obj *rmt_strip = NULL;
124 esp_err_t ret = ESP_OK;
125 ESP_RETURN_ON_FALSE(led_config && dev_config && ret_strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
126 ESP_RETURN_ON_FALSE(led_config->led_pixel_format < LED_PIXEL_FORMAT_INVALID, ESP_ERR_INVALID_ARG, TAG, "invalid led_pixel_format");
127 ESP_RETURN_ON_FALSE(dev_config->flags.with_dma == 0, ESP_ERR_NOT_SUPPORTED, TAG, "DMA is not supported");
128
129 uint8_t bytes_per_pixel = 3;
130 if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRBW) {
131 bytes_per_pixel = 4;
132 } else if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRB) {
133 bytes_per_pixel = 3;
134 } else {
135 assert(false);
136 }
137
138 // allocate memory for led_strip object
139 rmt_strip = calloc(1, sizeof(led_strip_rmt_obj) + led_config->max_leds * bytes_per_pixel);
140 ESP_RETURN_ON_FALSE(rmt_strip, ESP_ERR_NO_MEM, TAG, "request memory for les_strip failed");
141
142 // install RMT channel driver
143 rmt_config_t config = RMT_DEFAULT_CONFIG_TX(led_config->strip_gpio_num, dev_config->rmt_channel);
144 // set the minimal clock division because the LED strip needs a high clock resolution
145 config.clk_div = 2;
146
147 uint8_t mem_block_num = 2;
148 // override the default value if the user specify the mem block size
149 if (dev_config->mem_block_symbols) {
151 }
152 config.mem_block_num = mem_block_num;
153
154 ESP_GOTO_ON_ERROR(rmt_config(&config), err, TAG, "RMT config failed");
155 ESP_GOTO_ON_ERROR(rmt_driver_install(config.channel, 0, 0), err, TAG, "RMT install failed");
156
157 uint32_t counter_clk_hz = 0;
158 rmt_get_counter_clock((rmt_channel_t)dev_config->rmt_channel, &counter_clk_hz);
159 // ns -> ticks
160 float ratio = (float)counter_clk_hz / 1e9;
161 if (led_config->led_model == LED_MODEL_WS2812) {
162 led_t0h_ticks = (uint32_t)(ratio * WS2812_T0H_NS);
163 led_t0l_ticks = (uint32_t)(ratio * WS2812_T0L_NS);
164 led_t1h_ticks = (uint32_t)(ratio * WS2812_T1H_NS);
165 led_t1l_ticks = (uint32_t)(ratio * WS2812_T1L_NS);
166 } else if (led_config->led_model == LED_MODEL_SK6812) {
167 led_t0h_ticks = (uint32_t)(ratio * SK6812_T0H_NS);
168 led_t0l_ticks = (uint32_t)(ratio * SK6812_T0L_NS);
169 led_t1h_ticks = (uint32_t)(ratio * SK6812_T1H_NS);
170 led_t1l_ticks = (uint32_t)(ratio * SK6812_T1L_NS);
171 } else {
172 assert(false);
173 }
174
175 // adapter to translates the LES strip date frame into RMT symbols
176 rmt_translator_init((rmt_channel_t)dev_config->rmt_channel, ws2812_rmt_adapter);
177
178 rmt_strip->bytes_per_pixel = bytes_per_pixel;
179 rmt_strip->rmt_channel = (rmt_channel_t)dev_config->rmt_channel;
180 rmt_strip->strip_len = led_config->max_leds;
183 rmt_strip->base.clear = led_strip_rmt_clear;
184 rmt_strip->base.del = led_strip_rmt_del;
185
186 *ret_strip = &rmt_strip->base;
187 return ESP_OK;
188
189err:
190 if (rmt_strip) {
191 free(rmt_strip);
192 }
193 return ret;
194}
#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(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)
static esp_err_t led_strip_rmt_refresh(led_strip_t *strip)
static uint32_t led_t1l_ticks
#define LED_STRIP_RESET_MS
#define WS2812_T1H_NS
static void 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)
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)
#define WS2812_T1L_NS
static esp_err_t led_strip_rmt_clear(led_strip_t *strip)
static uint32_t led_t0h_ticks
#define SK6812_T1H_NS
static esp_err_t led_strip_rmt_del(led_strip_t *strip)
static uint32_t led_t0l_ticks
esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const led_strip_rmt_config_t *dev_config, led_strip_handle_t *ret_strip)
Create LED strip based on RMT TX channel.
#define SK6812_T1L_NS
#define WS2812_T0H_NS
#define WS2812_T0L_NS
#define SK6812_T0L_NS
#define SK6812_T0H_NS
static uint32_t led_t1h_ticks
@ LED_MODEL_WS2812
@ LED_MODEL_SK6812
@ 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
LED Strip RMT specific configuration.
struct led_strip_rmt_config_t::@177205126266303010206200207206146127175132325264 flags
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(* clear)(led_strip_t *strip)
Clear LED strip (turn off all LEDs).