ESP-IDF Firmware
Firmware architecture and call graph
Loading...
Searching...
No Matches
led_strip_spi_dev.c File Reference
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_rom_gpio.h"
#include "soc/spi_periph.h"
#include "led_strip.h"
#include "led_strip_interface.h"
#include "hal/spi_hal.h"
Include dependency graph for led_strip_spi_dev.c:

Go to the source code of this file.

Data Structures

struct  led_strip_spi_obj

Macros

#define LED_STRIP_SPI_DEFAULT_RESOLUTION   (2.5 * 1000 * 1000)
#define LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE   4
#define SPI_BYTES_PER_COLOR_BYTE   3
#define SPI_BITS_PER_COLOR_BYTE   (SPI_BYTES_PER_COLOR_BYTE * 8)

Functions

static void __led_strip_spi_bit (uint8_t data, uint8_t *buf)
static esp_err_t led_strip_spi_set_pixel (led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
static 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)
static esp_err_t led_strip_spi_refresh (led_strip_t *strip)
static esp_err_t led_strip_spi_clear (led_strip_t *strip)
static esp_err_t led_strip_spi_del (led_strip_t *strip)
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.

Variables

static const char * TAG = "led_strip_spi"

Macro Definition Documentation

◆ LED_STRIP_SPI_DEFAULT_RESOLUTION

#define LED_STRIP_SPI_DEFAULT_RESOLUTION   (2.5 * 1000 * 1000)

Definition at line 18 of file led_strip_spi_dev.c.

Referenced by led_strip_new_spi_device().

◆ LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE

#define LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE   4

Definition at line 19 of file led_strip_spi_dev.c.

Referenced by led_strip_new_spi_device().

◆ SPI_BITS_PER_COLOR_BYTE

#define SPI_BITS_PER_COLOR_BYTE   (SPI_BYTES_PER_COLOR_BYTE * 8)

Definition at line 22 of file led_strip_spi_dev.c.

Referenced by led_strip_spi_refresh().

◆ SPI_BYTES_PER_COLOR_BYTE

#define SPI_BYTES_PER_COLOR_BYTE   3

Function Documentation

◆ __led_strip_spi_bit()

void __led_strip_spi_bit ( uint8_t data,
uint8_t * buf )
static

Definition at line 36 of file led_strip_spi_dev.c.

37{
38 // Each color of 1 bit is represented by 3 bits of SPI, low_level:100 ,high_level:110
39 // So a color byte occupies 3 bytes of SPI.
40 *(buf + 2) |= data & BIT(0) ? BIT(2) | BIT(1) : BIT(2);
41 *(buf + 2) |= data & BIT(1) ? BIT(5) | BIT(4) : BIT(5);
42 *(buf + 2) |= data & BIT(2) ? BIT(7) : 0x00;
43 *(buf + 1) |= BIT(0);
44 *(buf + 1) |= data & BIT(3) ? BIT(3) | BIT(2) : BIT(3);
45 *(buf + 1) |= data & BIT(4) ? BIT(6) | BIT(5) : BIT(6);
46 *(buf + 0) |= data & BIT(5) ? BIT(1) | BIT(0) : BIT(1);
47 *(buf + 0) |= data & BIT(6) ? BIT(4) | BIT(3) : BIT(4);
48 *(buf + 0) |= data & BIT(7) ? BIT(7) | BIT(6) : BIT(7);
49}
static float data[128 *2]
Definition test_fft2r.c:34

References data.

Referenced by led_strip_spi_clear(), led_strip_spi_set_pixel(), and led_strip_spi_set_pixel_rgbw().

Here is the caller graph for this function:

◆ led_strip_new_spi_device()

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.

Note
Although only the MOSI line is used for generating the signal, the whole SPI bus can't be used for other purposes.
Parameters
led_configLED strip configuration
spi_configSPI specific configuration
ret_stripReturned LED strip handle
Returns
  • ESP_OK: create LED strip handle successfully
  • ESP_ERR_INVALID_ARG: create LED strip handle failed because of invalid argument
  • ESP_ERR_NOT_SUPPORTED: create LED strip handle failed because of unsupported configuration
  • 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

Definition at line 123 of file led_strip_spi_dev.c.

124{
125 led_strip_spi_obj *spi_strip = NULL;
126 esp_err_t ret = ESP_OK;
127 ESP_GOTO_ON_FALSE(led_config && spi_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
128 ESP_GOTO_ON_FALSE(led_config->led_pixel_format < LED_PIXEL_FORMAT_INVALID, ESP_ERR_INVALID_ARG, err, TAG, "invalid led_pixel_format");
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 uint32_t mem_caps = MALLOC_CAP_DEFAULT;
138 if (spi_config->flags.with_dma) {
139 // DMA buffer must be placed in internal SRAM
140 mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA;
141 }
142 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);
143
144 ESP_GOTO_ON_FALSE(spi_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for spi strip");
145
146 spi_strip->spi_host = spi_config->spi_bus;
147 // for backward compatibility, if the user does not set the clk_src, use the default value
148 spi_clock_source_t clk_src = SPI_CLK_SRC_DEFAULT;
149 if (spi_config->clk_src) {
150 clk_src = spi_config->clk_src;
151 }
152
153 spi_bus_config_t spi_bus_cfg = {
154 .mosi_io_num = led_config->strip_gpio_num,
155 //Only use MOSI to generate the signal, set -1 when other pins are not used.
156 .miso_io_num = -1,
157 .sclk_io_num = -1,
158 .quadwp_io_num = -1,
159 .quadhd_io_num = -1,
160 .max_transfer_sz = led_config->max_leds * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE,
161 };
162 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");
163
164 if (led_config->flags.invert_out == true) {
165 esp_rom_gpio_connect_out_signal(led_config->strip_gpio_num, spi_periph_signal[spi_strip->spi_host].spid_out, true, false);
166 }
167
168 spi_device_interface_config_t spi_dev_cfg = {
169 .clock_source = clk_src,
170 .command_bits = 0,
171 .address_bits = 0,
172 .dummy_bits = 0,
173 .clock_speed_hz = LED_STRIP_SPI_DEFAULT_RESOLUTION,
174 .mode = 0,
175 //set -1 when CS is not used
176 .spics_io_num = -1,
178 };
179
180 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");
181 //ensure the reset time is enough
182 esp_rom_delay_us(10);
183 int clock_resolution_khz = 0;
184 spi_device_get_actual_freq(spi_strip->spi_device, &clock_resolution_khz);
185 // TODO: ideally we should decide the SPI_BYTES_PER_COLOR_BYTE by the real clock resolution
186 // But now, let's fixed the resolution, the downside is, we don't support a clock source whose frequency is not multiple of LED_STRIP_SPI_DEFAULT_RESOLUTION
187 // clock_resolution between 2.2MHz to 2.8MHz is supported
188 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,
189 TAG, "unsupported clock resolution:%dKHz", clock_resolution_khz);
190
191 spi_strip->bytes_per_pixel = bytes_per_pixel;
192 spi_strip->strip_len = led_config->max_leds;
196 spi_strip->base.clear = led_strip_spi_clear;
197 spi_strip->base.del = led_strip_spi_del;
198
199 *ret_strip = &spi_strip->base;
200 return ESP_OK;
201err:
202 if (spi_strip) {
203 if (spi_strip->spi_device) {
204 spi_bus_remove_device(spi_strip->spi_device);
205 }
206 if (spi_strip->spi_host) {
207 spi_bus_free(spi_strip->spi_host);
208 }
209 free(spi_strip);
210 }
211 return ret;
212}
#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_spi_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
static esp_err_t led_strip_spi_refresh(led_strip_t *strip)
static 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)
#define SPI_BYTES_PER_COLOR_BYTE
#define LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE
static esp_err_t led_strip_spi_clear(led_strip_t *strip)
static esp_err_t led_strip_spi_del(led_strip_t *strip)
#define LED_STRIP_SPI_DEFAULT_RESOLUTION
@ LED_PIXEL_FORMAT_GRB
@ LED_PIXEL_FORMAT_INVALID
@ LED_PIXEL_FORMAT_GRBW
static const char * TAG
Definition main/main.c:31
led_pixel_format_t led_pixel_format
struct led_strip_config_t::@145177150267040163336221331365072267202117177200 flags
spi_host_device_t spi_bus
struct led_strip_spi_config_t::@242107237043306072174300312177366152113164360267 flags
spi_clock_source_t clk_src
spi_device_handle_t spi_device
spi_host_device_t spi_host
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).

References led_strip_spi_obj::base, led_strip_spi_obj::bytes_per_pixel, led_strip_t::clear, led_strip_spi_config_t::clk_src, led_strip_t::del, ESP_GOTO_ON_ERROR, ESP_OK, led_strip_config_t::flags, led_strip_spi_config_t::flags, led_strip_config_t::invert_out, led_strip_config_t::led_pixel_format, LED_PIXEL_FORMAT_GRB, LED_PIXEL_FORMAT_GRBW, LED_PIXEL_FORMAT_INVALID, led_strip_spi_clear(), LED_STRIP_SPI_DEFAULT_RESOLUTION, LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE, led_strip_spi_del(), led_strip_spi_refresh(), led_strip_spi_set_pixel(), led_strip_spi_set_pixel_rgbw(), led_strip_config_t::max_leds, led_strip_t::refresh, led_strip_t::set_pixel, led_strip_t::set_pixel_rgbw, led_strip_spi_config_t::spi_bus, SPI_BYTES_PER_COLOR_BYTE, led_strip_spi_obj::spi_device, led_strip_spi_obj::spi_host, led_strip_config_t::strip_gpio_num, led_strip_spi_obj::strip_len, TAG, and led_strip_spi_config_t::with_dma.

Here is the call graph for this function:

◆ led_strip_spi_clear()

esp_err_t led_strip_spi_clear ( led_strip_t * strip)
static

Definition at line 98 of file led_strip_spi_dev.c.

99{
100 led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
101 //Write zero to turn off all leds
102 memset(spi_strip->pixel_buf, 0, spi_strip->strip_len * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);
103 uint8_t *buf = spi_strip->pixel_buf;
104 for (int index = 0; index < spi_strip->strip_len * spi_strip->bytes_per_pixel; index++) {
105 __led_strip_spi_bit(0, buf);
107 }
108
109 return led_strip_spi_refresh(strip);
110}
static void __led_strip_spi_bit(uint8_t data, uint8_t *buf)

References __led_strip_spi_bit(), led_strip_spi_obj::bytes_per_pixel, led_strip_spi_refresh(), led_strip_spi_obj::pixel_buf, SPI_BYTES_PER_COLOR_BYTE, and led_strip_spi_obj::strip_len.

Referenced by led_strip_new_spi_device().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ led_strip_spi_del()

esp_err_t led_strip_spi_del ( led_strip_t * strip)
static

Definition at line 112 of file led_strip_spi_dev.c.

113{
114 led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
115
116 ESP_RETURN_ON_ERROR(spi_bus_remove_device(spi_strip->spi_device), TAG, "delete spi device failed");
117 ESP_RETURN_ON_ERROR(spi_bus_free(spi_strip->spi_host), TAG, "free spi bus failed");
118
119 free(spi_strip);
120 return ESP_OK;
121}
#define ESP_RETURN_ON_ERROR(x, log_tag, format,...)

References ESP_OK, ESP_RETURN_ON_ERROR, led_strip_spi_obj::spi_device, led_strip_spi_obj::spi_host, and TAG.

Referenced by led_strip_new_spi_device().

Here is the caller graph for this function:

◆ led_strip_spi_refresh()

esp_err_t led_strip_spi_refresh ( led_strip_t * strip)
static

Definition at line 84 of file led_strip_spi_dev.c.

85{
86 led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
87 spi_transaction_t tx_conf;
88 memset(&tx_conf, 0, sizeof(tx_conf));
89
90 tx_conf.length = spi_strip->strip_len * spi_strip->bytes_per_pixel * SPI_BITS_PER_COLOR_BYTE;
91 tx_conf.tx_buffer = spi_strip->pixel_buf;
92 tx_conf.rx_buffer = NULL;
93 ESP_RETURN_ON_ERROR(spi_device_transmit(spi_strip->spi_device, &tx_conf), TAG, "transmit pixels by SPI failed");
94
95 return ESP_OK;
96}
#define SPI_BITS_PER_COLOR_BYTE

References led_strip_spi_obj::bytes_per_pixel, ESP_OK, ESP_RETURN_ON_ERROR, led_strip_spi_obj::pixel_buf, SPI_BITS_PER_COLOR_BYTE, led_strip_spi_obj::spi_device, led_strip_spi_obj::strip_len, and TAG.

Referenced by led_strip_new_spi_device(), and led_strip_spi_clear().

Here is the caller graph for this function:

◆ led_strip_spi_set_pixel()

esp_err_t led_strip_spi_set_pixel ( led_strip_t * strip,
uint32_t index,
uint32_t red,
uint32_t green,
uint32_t blue )
static

Definition at line 51 of file led_strip_spi_dev.c.

52{
53 led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
54 ESP_RETURN_ON_FALSE(index < spi_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs");
55 // LED_PIXEL_FORMAT_GRB takes 72bits(9bytes)
56 uint32_t start = index * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE;
57 memset(spi_strip->pixel_buf + start, 0, spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);
58 __led_strip_spi_bit(green, &spi_strip->pixel_buf[start]);
60 __led_strip_spi_bit(blue, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 2]);
61 if (spi_strip->bytes_per_pixel > 3) {
62 __led_strip_spi_bit(0, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 3]);
63 }
64 return ESP_OK;
65}

References __led_strip_spi_bit(), led_strip_spi_obj::bytes_per_pixel, ESP_OK, led_strip_spi_obj::pixel_buf, SPI_BYTES_PER_COLOR_BYTE, and TAG.

Referenced by led_strip_new_spi_device().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ led_strip_spi_set_pixel_rgbw()

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 )
static

Definition at line 67 of file led_strip_spi_dev.c.

68{
69 led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
70 ESP_RETURN_ON_FALSE(index < spi_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs");
71 ESP_RETURN_ON_FALSE(spi_strip->bytes_per_pixel == 4, ESP_ERR_INVALID_ARG, TAG, "wrong LED pixel format, expected 4 bytes per pixel");
72 // LED_PIXEL_FORMAT_GRBW takes 96bits(12bytes)
73 uint32_t start = index * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE;
74 // SK6812 component order is GRBW
75 memset(spi_strip->pixel_buf + start, 0, spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);
76 __led_strip_spi_bit(green, &spi_strip->pixel_buf[start]);
78 __led_strip_spi_bit(blue, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 2]);
79 __led_strip_spi_bit(white, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 3]);
80
81 return ESP_OK;
82}

References __led_strip_spi_bit(), led_strip_spi_obj::bytes_per_pixel, ESP_OK, led_strip_spi_obj::pixel_buf, SPI_BYTES_PER_COLOR_BYTE, and TAG.

Referenced by led_strip_new_spi_device().

Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ TAG

const char* TAG = "led_strip_spi"
static

Definition at line 24 of file led_strip_spi_dev.c.