5#if FASTLED_ESP32_HAS_CLOCKLESS_SPI
17#include "esp_rom_gpio.h"
18#include "soc/spi_periph.h"
23#define LED_STRIP_SPI_DEFAULT_RESOLUTION (2.5 * 1000 * 1000)
24#define LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE 4
26#define SPI_BYTES_PER_COLOR_BYTE 3
27#define SPI_BITS_PER_COLOR_BYTE (SPI_BYTES_PER_COLOR_BYTE * 8)
29static const char *TAG =
"led_strip_spi";
33 spi_host_device_t spi_host;
34 spi_device_handle_t spi_device;
36 uint8_t bytes_per_pixel;
42static void __led_strip_spi_bit(uint8_t data, uint8_t *buf)
46 *(buf + 2) |= data & BIT(0) ? BIT(2) | BIT(1) : BIT(2);
47 *(buf + 2) |= data & BIT(1) ? BIT(5) | BIT(4) : BIT(5);
48 *(buf + 2) |= data & BIT(2) ? BIT(7) : 0x00;
50 *(buf + 1) |= data & BIT(3) ? BIT(3) | BIT(2) : BIT(3);
51 *(buf + 1) |= data & BIT(4) ? BIT(6) | BIT(5) : BIT(6);
52 *(buf + 0) |= data & BIT(5) ? BIT(1) | BIT(0) : BIT(1);
53 *(buf + 0) |= data & BIT(6) ? BIT(4) | BIT(3) : BIT(4);
54 *(buf + 0) |= data & BIT(7) ? BIT(7) | BIT(6) : BIT(7);
57static esp_err_t led_strip_spi_set_pixel(
led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
59 led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
60 ESP_RETURN_ON_FALSE(index < spi_strip->strip_len, ESP_ERR_INVALID_ARG, TAG,
"index out of maximum number of LEDs");
62 uint32_t start = index * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE;
63 uint8_t *pixel_buf = spi_strip->pixel_buf;
65 memset(pixel_buf + start, 0, spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);
67 __led_strip_spi_bit(red, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.
format.
r_pos]);
68 __led_strip_spi_bit(green, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.
format.
g_pos]);
69 __led_strip_spi_bit(blue, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.
format.
b_pos]);
71 __led_strip_spi_bit(0, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.
format.
w_pos]);
77static esp_err_t led_strip_spi_set_pixel_rgbw(
led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white)
79 led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
81 ESP_RETURN_ON_FALSE(index < spi_strip->strip_len, ESP_ERR_INVALID_ARG, TAG,
"index out of maximum number of LEDs");
82 ESP_RETURN_ON_FALSE(component_fmt.
format.
num_components == 4, ESP_ERR_INVALID_ARG, TAG,
"led doesn't have 4 components");
85 uint32_t start = index * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE;
86 uint8_t *pixel_buf = spi_strip->pixel_buf;
87 memset(pixel_buf + start, 0, spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);
89 __led_strip_spi_bit(red, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.
format.
r_pos]);
90 __led_strip_spi_bit(green, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.
format.
g_pos]);
91 __led_strip_spi_bit(blue, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.
format.
b_pos]);
92 __led_strip_spi_bit(white, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.
format.
w_pos]);
98static esp_err_t spi_led_strip_refresh_async(
led_strip_t *strip)
100 led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
101 spi_transaction_t tx_conf;
102 memset(&tx_conf, 0,
sizeof(tx_conf));
104 tx_conf.length = spi_strip->strip_len * spi_strip->bytes_per_pixel * SPI_BITS_PER_COLOR_BYTE;
105 tx_conf.tx_buffer = spi_strip->pixel_buf;
106 tx_conf.rx_buffer = NULL;
107 spi_device_queue_trans(spi_strip->spi_device, &tx_conf, portMAX_DELAY);
111static esp_err_t spi_led_strip_refresh_wait_done(
led_strip_t *strip)
113 led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
114 spi_transaction_t* tx_conf = 0;
115 spi_device_get_trans_result(spi_strip->spi_device, &tx_conf, portMAX_DELAY);
119static esp_err_t led_strip_spi_refresh(
led_strip_t *strip)
121 ESP_RETURN_ON_ERROR(spi_led_strip_refresh_async(strip), TAG,
"refresh async failed");
122 ESP_RETURN_ON_ERROR(spi_led_strip_refresh_wait_done(strip), TAG,
"wait for done failed");
127static esp_err_t led_strip_spi_clear(
led_strip_t *strip)
129 led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
131 memset(spi_strip->pixel_buf, 0, spi_strip->strip_len * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);
132 uint8_t *buf = spi_strip->pixel_buf;
133 for (
int index = 0; index < spi_strip->strip_len * spi_strip->bytes_per_pixel; index++) {
134 __led_strip_spi_bit(0, buf);
135 buf += SPI_BYTES_PER_COLOR_BYTE;
138 return led_strip_spi_refresh(strip);
141static esp_err_t led_strip_spi_del(
led_strip_t *strip)
143 led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
145 ESP_RETURN_ON_ERROR(spi_bus_remove_device(spi_strip->spi_device), TAG,
"delete spi device failed");
146 ESP_RETURN_ON_ERROR(spi_bus_free(spi_strip->spi_host), TAG,
"free spi bus failed");
154 led_strip_spi_obj *spi_strip = NULL;
155 esp_err_t ret = ESP_OK;
157 ESP_GOTO_ON_FALSE(led_config && spi_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG,
"invalid argument");
168 ESP_RETURN_ON_FALSE(mask == 0x07, ESP_ERR_INVALID_ARG, TAG,
"invalid order argument");
172 ESP_RETURN_ON_FALSE(mask == 0x0F, ESP_ERR_INVALID_ARG, TAG,
"invalid order argument");
174 ESP_RETURN_ON_FALSE(
false, ESP_ERR_INVALID_ARG, TAG,
"invalid number of color components: %d", component_fmt.
format.
num_components);
178 uint32_t mem_caps = MALLOC_CAP_DEFAULT;
179 if (spi_config->
flags.with_dma) {
181 mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA;
183 spi_strip = heap_caps_calloc(1,
sizeof(led_strip_spi_obj) + led_config->
max_leds * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE, mem_caps);
185 ESP_GOTO_ON_FALSE(spi_strip, ESP_ERR_NO_MEM, err, TAG,
"no mem for spi strip");
187 spi_strip->spi_host = spi_config->
spi_bus;
189 spi_clock_source_t clk_src = SPI_CLK_SRC_DEFAULT;
194 spi_bus_config_t spi_bus_cfg = {
201 .max_transfer_sz = led_config->
max_leds * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE,
203 ESP_GOTO_ON_ERROR(spi_bus_initialize(spi_strip->spi_host, &spi_bus_cfg, spi_config->
flags.with_dma ? SPI_DMA_CH_AUTO : SPI_DMA_DISABLED), err, TAG,
"create SPI bus failed");
206 esp_rom_gpio_connect_out_signal(led_config->
strip_gpio_num, spi_periph_signal[spi_strip->spi_host].spid_out,
true,
false);
209 spi_device_interface_config_t spi_dev_cfg = {
210 .clock_source = clk_src,
214 .clock_speed_hz = LED_STRIP_SPI_DEFAULT_RESOLUTION,
218 .queue_size = LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE,
221 ESP_GOTO_ON_ERROR(spi_bus_add_device(spi_strip->spi_host, &spi_dev_cfg, &spi_strip->spi_device), err, TAG,
"Failed to add spi device");
223 esp_rom_delay_us(10);
224 int clock_resolution_khz = 0;
225 spi_device_get_actual_freq(spi_strip->spi_device, &clock_resolution_khz);
229 ESP_GOTO_ON_FALSE((clock_resolution_khz < LED_STRIP_SPI_DEFAULT_RESOLUTION / 1000 + 300) && (clock_resolution_khz > LED_STRIP_SPI_DEFAULT_RESOLUTION / 1000 - 300), ESP_ERR_NOT_SUPPORTED, err,
230 TAG,
"unsupported clock resolution:%dKHz", clock_resolution_khz);
232 spi_strip->component_fmt = component_fmt;
233 spi_strip->bytes_per_pixel = bytes_per_pixel;
234 spi_strip->strip_len = led_config->
max_leds;
235 spi_strip->base.set_pixel = led_strip_spi_set_pixel;
236 spi_strip->base.set_pixel_rgbw = led_strip_spi_set_pixel_rgbw;
237 spi_strip->base.refresh = led_strip_spi_refresh;
238 spi_strip->base.refresh_async = spi_led_strip_refresh_async;
239 spi_strip->base.refresh_wait_done = spi_led_strip_refresh_wait_done;
240 spi_strip->base.clear = led_strip_spi_clear;
241 spi_strip->base.del = led_strip_spi_del;
243 *ret_strip = &spi_strip->base;
247 if (spi_strip->spi_device) {
248 spi_bus_remove_device(spi_strip->spi_device);
250 if (spi_strip->spi_host) {
251 spi_bus_free(spi_strip->spi_host);
LED strip interface definition.
esp_err_t led_strip_new_spi_device(const led_strip_config_t *led_config, const led_strip_spi_config_t *spi_config, led_strip_handle_t *ret_strip)
Create LED strip based on SPI MOSI channel.
spi_host_device_t spi_bus
spi_clock_source_t clk_src
struct led_strip_spi_config_t::@276143246045101136044262336246252357033024237362 flags
LED Strip SPI specific configuration.
#define LED_STRIP_COLOR_COMPONENT_FMT_GRB
Helper macros to set the color component format.
struct led_strip_t * led_strip_handle_t
Type of LED strip handle.
led_color_component_format_t color_component_format
struct led_strip_config_t::led_strip_extra_flags flags
struct led_color_component_format_t::format_layout format
LED Strip common configurations The common configurations are not specific to any backend peripheral.
#define FASTLED_UNUSED(x)