ESPHome  2022.8.0
ili9341_display.cpp
Go to the documentation of this file.
1 #include "ili9341_display.h"
2 #include "esphome/core/log.h"
4 #include "esphome/core/helpers.h"
5 #include "esphome/core/hal.h"
6 
7 namespace esphome {
8 namespace ili9341 {
9 
10 static const char *const TAG = "ili9341";
11 
13  this->init_internal_(this->get_buffer_length_());
14  this->dc_pin_->setup(); // OUTPUT
15  this->dc_pin_->digital_write(false);
16  if (this->reset_pin_ != nullptr) {
17  this->reset_pin_->setup(); // OUTPUT
18  this->reset_pin_->digital_write(true);
19  }
20  if (this->led_pin_ != nullptr) {
21  this->led_pin_->setup();
22  this->led_pin_->digital_write(true);
23  }
24  this->spi_setup();
25 
26  this->reset_();
27 }
28 
30  LOG_DISPLAY("", "ili9341", this);
31  ESP_LOGCONFIG(TAG, " Width: %d, Height: %d, Rotation: %d", this->width_, this->height_, this->rotation_);
32  LOG_PIN(" Reset Pin: ", this->reset_pin_);
33  LOG_PIN(" DC Pin: ", this->dc_pin_);
34  LOG_PIN(" Busy Pin: ", this->busy_pin_);
35  LOG_PIN(" Backlight Pin: ", this->led_pin_);
36  LOG_UPDATE_INTERVAL(this);
37 }
38 
40 void ILI9341Display::command(uint8_t value) {
41  this->start_command_();
42  this->write_byte(value);
43  this->end_command_();
44 }
45 
47  if (this->reset_pin_ != nullptr) {
48  this->reset_pin_->digital_write(false);
49  delay(10);
50  this->reset_pin_->digital_write(true);
51  delay(10);
52  }
53 }
54 
55 void ILI9341Display::data(uint8_t value) {
56  this->start_data_();
57  this->write_byte(value);
58  this->end_data_();
59 }
60 
61 void ILI9341Display::send_command(uint8_t command_byte, const uint8_t *data_bytes, uint8_t num_data_bytes) {
62  this->command(command_byte); // Send the command byte
63  this->start_data_();
64  this->write_array(data_bytes, num_data_bytes);
65  this->end_data_();
66 }
67 
68 uint8_t ILI9341Display::read_command(uint8_t command_byte, uint8_t index) {
69  uint8_t data = 0x10 + index;
70  this->send_command(0xD9, &data, 1); // Set Index Register
71  uint8_t result;
72  this->start_command_();
73  this->write_byte(command_byte);
74  this->start_data_();
75  do {
76  result = this->read_byte();
77  } while (index--);
78  this->end_data_();
79  return result;
80 }
81 
83  this->do_update_();
84  this->display_();
85 }
86 
88  // we will only update the changed window to the display
89  uint16_t w = this->x_high_ - this->x_low_ + 1;
90  uint16_t h = this->y_high_ - this->y_low_ + 1;
91 
92  set_addr_window_(this->x_low_, this->y_low_, w, h);
93  this->start_data_();
94  uint32_t start_pos = ((this->y_low_ * this->width_) + x_low_);
95  for (uint16_t row = 0; row < h; row++) {
96  uint32_t pos = start_pos + (row * width_);
97  uint32_t rem = w;
98 
99  while (rem > 0) {
100  uint32_t sz = buffer_to_transfer_(pos, rem);
101  this->write_array(transfer_buffer_, 2 * sz);
102  pos += sz;
103  rem -= sz;
104  }
105  }
106  this->end_data_();
107 
108  // invalidate watermarks
109  this->x_low_ = this->width_;
110  this->y_low_ = this->height_;
111  this->x_high_ = 0;
112  this->y_high_ = 0;
113 }
114 
117  memset(this->buffer_, color332, this->get_buffer_length_());
118  this->x_low_ = 0;
119  this->y_low_ = 0;
120  this->x_high_ = this->get_width_internal() - 1;
121  this->y_high_ = this->get_height_internal() - 1;
122 }
123 
125  if (color.raw_32 == Color::BLACK.raw_32) {
126  memset(transfer_buffer_, 0, sizeof(transfer_buffer_));
127  } else {
128  uint8_t *dst = transfer_buffer_;
129  auto color565 = display::ColorUtil::color_to_565(color);
130 
131  while (dst < transfer_buffer_ + sizeof(transfer_buffer_)) {
132  *dst++ = (uint8_t)(color565 >> 8);
133  *dst++ = (uint8_t) color565;
134  }
135  }
136 
137  uint32_t rem = this->get_width_internal() * this->get_height_internal();
138 
139  this->set_addr_window_(0, 0, this->get_width_internal(), this->get_height_internal());
140  this->start_data_();
141 
142  while (rem > 0) {
143  size_t sz = rem <= sizeof(transfer_buffer_) ? rem : sizeof(transfer_buffer_);
144  this->write_array(transfer_buffer_, sz);
145  rem -= sz;
146  }
147 
148  this->end_data_();
149 
150  memset(buffer_, 0, (this->get_width_internal()) * (this->get_height_internal()));
151 }
152 
154  if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0)
155  return;
156 
157  // low and high watermark may speed up drawing from buffer
158  this->x_low_ = (x < this->x_low_) ? x : this->x_low_;
159  this->y_low_ = (y < this->y_low_) ? y : this->y_low_;
160  this->x_high_ = (x > this->x_high_) ? x : this->x_high_;
161  this->y_high_ = (y > this->y_high_) ? y : this->y_high_;
162 
163  uint32_t pos = (y * width_) + x;
164  if (this->buffer_color_mode_ == BITS_8) {
166  buffer_[pos] = color332;
167  } else { // if (this->buffer_color_mode_ == BITS_8_INDEXED) {
168  uint8_t index = display::ColorUtil::color_to_index8_palette888(color, this->palette_);
169  buffer_[pos] = index;
170  }
171 }
172 
173 // should return the total size: return this->get_width_internal() * this->get_height_internal() * 2 // 16bit color
174 // values per bit is huge
176 
178  this->dc_pin_->digital_write(false);
179  this->enable();
180 }
181 
184  this->dc_pin_->digital_write(true);
185  this->enable();
186 }
188 
189 void ILI9341Display::init_lcd_(const uint8_t *init_cmd) {
190  uint8_t cmd, x, num_args;
191  const uint8_t *addr = init_cmd;
192  while ((cmd = progmem_read_byte(addr++)) > 0) {
193  x = progmem_read_byte(addr++);
194  num_args = x & 0x7F;
195  send_command(cmd, addr, num_args);
196  addr += num_args;
197  if (x & 0x80)
198  delay(150); // NOLINT
199  }
200 }
201 
202 void ILI9341Display::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t w, uint16_t h) {
203  uint16_t x2 = (x1 + w - 1), y2 = (y1 + h - 1);
204  this->command(ILI9341_CASET); // Column address set
205  this->start_data_();
206  this->write_byte(x1 >> 8);
207  this->write_byte(x1);
208  this->write_byte(x2 >> 8);
209  this->write_byte(x2);
210  this->end_data_();
211  this->command(ILI9341_PASET); // Row address set
212  this->start_data_();
213  this->write_byte(y1 >> 8);
214  this->write_byte(y1);
215  this->write_byte(y2 >> 8);
216  this->write_byte(y2);
217  this->end_data_();
218  this->command(ILI9341_RAMWR); // Write to RAM
219 }
220 
221 void ILI9341Display::invert_display_(bool invert) { this->command(invert ? ILI9341_INVON : ILI9341_INVOFF); }
222 
225 
226 uint32_t ILI9341Display::buffer_to_transfer_(uint32_t pos, uint32_t sz) {
227  uint8_t *src = buffer_ + pos;
228  uint8_t *dst = transfer_buffer_;
229 
230  if (sz > sizeof(transfer_buffer_) / 2) {
231  sz = sizeof(transfer_buffer_) / 2;
232  }
233 
234  for (uint32_t i = 0; i < sz; ++i) {
235  uint16_t color;
236  if (this->buffer_color_mode_ == BITS_8) {
238  } else { // if (this->buffer_color_mode == BITS_8_INDEXED) {
241  }
242  *dst++ = (uint8_t)(color >> 8);
243  *dst++ = (uint8_t) color;
244  }
245 
246  return sz;
247 }
248 
249 // M5Stack display
251  this->init_lcd_(INITCMD_M5STACK);
252  this->width_ = 320;
253  this->height_ = 240;
254  this->invert_display_(true);
256 }
257 
258 // 24_TFT display
260  this->init_lcd_(INITCMD_TFT);
261  this->width_ = 240;
262  this->height_ = 320;
264 }
265 
266 // 24_TFT rotated display
268  this->init_lcd_(INITCMD_TFT);
269  this->width_ = 320;
270  this->height_ = 240;
272 }
273 
274 } // namespace ili9341
275 } // namespace esphome
virtual void digital_write(bool value)=0
void init_lcd_(const uint8_t *init_cmd)
static uint16_t color_to_565(Color color, ColorOrder color_order=ColorOrder::COLOR_ORDER_RGB)
void send_command(uint8_t command_byte, const uint8_t *data_bytes, uint8_t num_data_bytes)
virtual void setup()=0
void init_internal_(uint32_t buffer_length)
void fill(Color color) override
void set_addr_window_(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
static uint8_t color_to_332(Color color, ColorOrder color_order=ColorOrder::COLOR_ORDER_RGB)
int16_t width_
Display width as modified by current rotation.
static Color index8_to_color_palette888(uint8_t index, const uint8_t *palette)
void draw_absolute_pixel_internal(int x, int y, Color color) override
uint32_t buffer_to_transfer_(uint32_t pos, uint32_t sz)
const float PROCESSOR
For components that use data from sensors like displays.
Definition: component.cpp:19
uint8_t progmem_read_byte(const uint8_t *addr)
Definition: core.cpp:56
static uint8_t color_to_index8_palette888(Color color, const uint8_t *palette)
uint8_t h
Definition: bl0939.h:21
static const Color BLACK
Definition: color.h:158
uint8_t read_command(uint8_t command_byte, uint8_t index)
float get_setup_priority() const override
Definition: a4988.cpp:4
int16_t height_
Display height as modified by current rotation.
static Color rgb332_to_color(uint8_t rgb332_color)
uint32_t raw_32
Definition: color.h:31
stm32_cmd_t * cmd
Definition: stm32flash.h:96
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:27