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