ESPHome  2024.5.4
led_strip.cpp
Go to the documentation of this file.
1 #include <cinttypes>
2 #include "led_strip.h"
3 
4 #ifdef USE_ESP32
5 
6 #include "esphome/core/helpers.h"
7 #include "esphome/core/log.h"
8 
9 #include <esp_attr.h>
10 
11 namespace esphome {
12 namespace esp32_rmt_led_strip {
13 
14 static const char *const TAG = "esp32_rmt_led_strip";
15 
16 static const uint32_t RMT_CLK_FREQ = 80000000;
17 
18 static const uint8_t RMT_CLK_DIV = 2;
19 
21  ESP_LOGCONFIG(TAG, "Setting up ESP32 LED Strip...");
22 
23  size_t buffer_size = this->get_buffer_size_();
24 
26  this->buf_ = allocator.allocate(buffer_size);
27  if (this->buf_ == nullptr) {
28  ESP_LOGE(TAG, "Cannot allocate LED buffer!");
29  this->mark_failed();
30  return;
31  }
32 
33  this->effect_data_ = allocator.allocate(this->num_leds_);
34  if (this->effect_data_ == nullptr) {
35  ESP_LOGE(TAG, "Cannot allocate effect data!");
36  this->mark_failed();
37  return;
38  }
39 
41  this->rmt_buf_ = rmt_allocator.allocate(buffer_size * 8); // 8 bits per byte, 1 rmt_item32_t per bit
42 
43  rmt_config_t config;
44  memset(&config, 0, sizeof(config));
45  config.channel = this->channel_;
46  config.rmt_mode = RMT_MODE_TX;
47  config.gpio_num = gpio_num_t(this->pin_);
48  config.mem_block_num = 1;
49  config.clk_div = RMT_CLK_DIV;
50  config.tx_config.loop_en = false;
51  config.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW;
52  config.tx_config.carrier_en = false;
53  config.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
54  config.tx_config.idle_output_en = true;
55 
56  if (rmt_config(&config) != ESP_OK) {
57  ESP_LOGE(TAG, "Cannot initialize RMT!");
58  this->mark_failed();
59  return;
60  }
61  if (rmt_driver_install(config.channel, 0, 0) != ESP_OK) {
62  ESP_LOGE(TAG, "Cannot install RMT driver!");
63  this->mark_failed();
64  return;
65  }
66 }
67 
68 void ESP32RMTLEDStripLightOutput::set_led_params(uint32_t bit0_high, uint32_t bit0_low, uint32_t bit1_high,
69  uint32_t bit1_low) {
70  float ratio = (float) RMT_CLK_FREQ / RMT_CLK_DIV / 1e09f;
71 
72  // 0-bit
73  this->bit0_.duration0 = (uint32_t) (ratio * bit0_high);
74  this->bit0_.level0 = 1;
75  this->bit0_.duration1 = (uint32_t) (ratio * bit0_low);
76  this->bit0_.level1 = 0;
77  // 1-bit
78  this->bit1_.duration0 = (uint32_t) (ratio * bit1_high);
79  this->bit1_.level0 = 1;
80  this->bit1_.duration1 = (uint32_t) (ratio * bit1_low);
81  this->bit1_.level1 = 0;
82 }
83 
85  // protect from refreshing too often
86  uint32_t now = micros();
87  if (*this->max_refresh_rate_ != 0 && (now - this->last_refresh_) < *this->max_refresh_rate_) {
88  // try again next loop iteration, so that this change won't get lost
89  this->schedule_show();
90  return;
91  }
92  this->last_refresh_ = now;
93  this->mark_shown_();
94 
95  ESP_LOGVV(TAG, "Writing RGB values to bus...");
96 
97  if (rmt_wait_tx_done(this->channel_, pdMS_TO_TICKS(1000)) != ESP_OK) {
98  ESP_LOGE(TAG, "RMT TX timeout");
99  this->status_set_warning();
100  return;
101  }
102  delayMicroseconds(50);
103 
104  size_t buffer_size = this->get_buffer_size_();
105 
106  size_t size = 0;
107  size_t len = 0;
108  uint8_t *psrc = this->buf_;
109  rmt_item32_t *pdest = this->rmt_buf_;
110  while (size < buffer_size) {
111  uint8_t b = *psrc;
112  for (int i = 0; i < 8; i++) {
113  pdest->val = b & (1 << (7 - i)) ? this->bit1_.val : this->bit0_.val;
114  pdest++;
115  len++;
116  }
117  size++;
118  psrc++;
119  }
120 
121  if (rmt_write_items(this->channel_, this->rmt_buf_, len, false) != ESP_OK) {
122  ESP_LOGE(TAG, "RMT TX error");
123  this->status_set_warning();
124  return;
125  }
126  this->status_clear_warning();
127 }
128 
130  int32_t r = 0, g = 0, b = 0;
131  switch (this->rgb_order_) {
132  case ORDER_RGB:
133  r = 0;
134  g = 1;
135  b = 2;
136  break;
137  case ORDER_RBG:
138  r = 0;
139  g = 2;
140  b = 1;
141  break;
142  case ORDER_GRB:
143  r = 1;
144  g = 0;
145  b = 2;
146  break;
147  case ORDER_GBR:
148  r = 2;
149  g = 0;
150  b = 1;
151  break;
152  case ORDER_BGR:
153  r = 2;
154  g = 1;
155  b = 0;
156  break;
157  case ORDER_BRG:
158  r = 1;
159  g = 2;
160  b = 0;
161  break;
162  }
163  uint8_t multiplier = this->is_rgbw_ || this->is_wrgb_ ? 4 : 3;
164  uint8_t white = this->is_wrgb_ ? 0 : 3;
165 
166  return {this->buf_ + (index * multiplier) + r + this->is_wrgb_,
167  this->buf_ + (index * multiplier) + g + this->is_wrgb_,
168  this->buf_ + (index * multiplier) + b + this->is_wrgb_,
169  this->is_rgbw_ || this->is_wrgb_ ? this->buf_ + (index * multiplier) + white : nullptr,
170  &this->effect_data_[index],
171  &this->correction_};
172 }
173 
175  ESP_LOGCONFIG(TAG, "ESP32 RMT LED Strip:");
176  ESP_LOGCONFIG(TAG, " Pin: %u", this->pin_);
177  ESP_LOGCONFIG(TAG, " Channel: %u", this->channel_);
178  const char *rgb_order;
179  switch (this->rgb_order_) {
180  case ORDER_RGB:
181  rgb_order = "RGB";
182  break;
183  case ORDER_RBG:
184  rgb_order = "RBG";
185  break;
186  case ORDER_GRB:
187  rgb_order = "GRB";
188  break;
189  case ORDER_GBR:
190  rgb_order = "GBR";
191  break;
192  case ORDER_BGR:
193  rgb_order = "BGR";
194  break;
195  case ORDER_BRG:
196  rgb_order = "BRG";
197  break;
198  default:
199  rgb_order = "UNKNOWN";
200  break;
201  }
202  ESP_LOGCONFIG(TAG, " RGB Order: %s", rgb_order);
203  ESP_LOGCONFIG(TAG, " Max refresh rate: %" PRIu32, *this->max_refresh_rate_);
204  ESP_LOGCONFIG(TAG, " Number of LEDs: %u", this->num_leds_);
205 }
206 
208 
209 } // namespace esp32_rmt_led_strip
210 } // namespace esphome
211 
212 #endif // USE_ESP32
This class represents the communication layer between the front-end MQTT layer and the hardware outpu...
Definition: light_state.h:34
light::ESPColorView get_view_internal(int32_t index) const override
Definition: led_strip.cpp:129
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:151
An STL allocator that uses SPI RAM.
Definition: helpers.h:651
uint32_t IRAM_ATTR HOT micros()
Definition: core.cpp:27
void set_led_params(uint32_t bit0_high, uint32_t bit0_low, uint32_t bit1_high, uint32_t bit1_low)
Definition: led_strip.cpp:68
void status_clear_warning()
Definition: component.cpp:166
void write_state(light::LightState *state) override
Definition: led_strip.cpp:84
const float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
Definition: component.cpp:18
std::string size_t len
Definition: helpers.h:292
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:118
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition: core.cpp:28
bool state
Definition: fan.h:34