ESPHome  2024.4.1
waveshare_213v3.cpp
Go to the documentation of this file.
1 #include "waveshare_epaper.h"
2 #include "esphome/core/log.h"
4 
5 namespace esphome {
6 namespace waveshare_epaper {
7 
8 static const char *const TAG = "waveshare_2.13v3";
9 
10 static const uint8_t PARTIAL_LUT[] = {
11  0x32, // cmd
12  0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
13  0x0, 0x0, 0x0, 0x0, 0x40, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0,
14  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
15  0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
16  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
17  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
18  0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
19  0x0, 0x0, 0x0, 0x0, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x0, 0x0, 0x0,
20 };
21 
22 static const uint8_t FULL_LUT[] = {
23  0x32, // CMD
24  0x80, 0x4A, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x4A, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0,
25  0x0, 0x0, 0x0, 0x0, 0x80, 0x4A, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x4A, 0x80, 0x0,
26  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
27  0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xF, 0x0, 0x0, 0xF, 0x0, 0x0, 0x2, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0,
28  0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
29  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
30  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
31  0x0, 0x0, 0x0, 0x0, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x0, 0x0, 0x0,
32 };
33 
34 static const uint8_t SW_RESET = 0x12;
35 static const uint8_t ACTIVATE = 0x20;
36 static const uint8_t WRITE_BUFFER = 0x24;
37 static const uint8_t WRITE_BASE = 0x26;
38 
39 static const uint8_t DRV_OUT_CTL[] = {0x01, 0x27, 0x01, 0x00}; // driver output control
40 static const uint8_t GATEV[] = {0x03, 0x17};
41 static const uint8_t SRCV[] = {0x04, 0x41, 0x0C, 0x32};
42 static const uint8_t SLEEP[] = {0x10, 0x01};
43 static const uint8_t DATA_ENTRY[] = {0x11, 0x03}; // data entry mode
44 static const uint8_t TEMP_SENS[] = {0x18, 0x80}; // Temp sensor
45 static const uint8_t DISPLAY_UPDATE[] = {0x21, 0x00, 0x80}; // Display update control
46 static const uint8_t UPSEQ[] = {0x22, 0xC0};
47 static const uint8_t ON_FULL[] = {0x22, 0xC7};
48 static const uint8_t ON_PARTIAL[] = {0x22, 0x0F};
49 static const uint8_t VCOM[] = {0x2C, 0x36};
50 static const uint8_t CMD5[] = {0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00};
51 static const uint8_t BORDER_PART[] = {0x3C, 0x80}; // border waveform
52 static const uint8_t BORDER_FULL[] = {0x3C, 0x05}; // border waveform
53 static const uint8_t CMD1[] = {0x3F, 0x22};
54 static const uint8_t RAM_X_START[] = {0x44, 0x00, 121 / 8}; // set ram_x_address_start_end
55 static const uint8_t RAM_Y_START[] = {0x45, 0x00, 0x00, 250 - 1, 0}; // set ram_y_address_start_end
56 static const uint8_t RAM_X_POS[] = {0x4E, 0x00}; // set ram_x_address_counter
57 // static const uint8_t RAM_Y_POS[] = {0x4F, 0x00, 0x00}; // set ram_y_address_counter
58 #define SEND(x) this->cmd_data(x, sizeof(x))
59 
60 void WaveshareEPaper2P13InV3::write_lut_(const uint8_t *lut) {
61  this->wait_until_idle_();
62  this->cmd_data(lut, sizeof(PARTIAL_LUT));
63  SEND(CMD1);
64  SEND(GATEV);
65  SEND(SRCV);
66  SEND(VCOM);
67 }
68 
69 // write the buffer starting on line top, up to line bottom.
70 void WaveshareEPaper2P13InV3::write_buffer_(uint8_t cmd, int top, int bottom) {
71  this->wait_until_idle_();
72  this->set_window_(top, bottom);
73  this->command(cmd);
74  this->start_data_();
75  auto width_bytes = this->get_width_internal() / 8;
76  this->write_array(this->buffer_ + top * width_bytes, (bottom - top) * width_bytes);
77  this->end_data_();
78 }
79 
81  if (this->reset_pin_ != nullptr) {
82  this->reset_pin_->digital_write(false);
83  delay(2);
84  this->reset_pin_->digital_write(true);
85  }
86 }
87 
89  setup_pins_();
90  delay(20);
91  this->send_reset_();
92  // as a one-off delay this is not worth working around.
93  delay(100); // NOLINT
94  this->wait_until_idle_();
95  this->command(SW_RESET);
96  this->wait_until_idle_();
97 
98  SEND(DRV_OUT_CTL);
99  SEND(DATA_ENTRY);
100  SEND(CMD5);
101  this->set_window_(0, this->get_height_internal());
102  SEND(BORDER_FULL);
103  SEND(DISPLAY_UPDATE);
104  SEND(TEMP_SENS);
105  this->wait_until_idle_();
106  this->write_lut_(FULL_LUT);
107 }
108 
109 // t and b are y positions, i.e. line numbers.
111  uint8_t buffer[3];
112 
113  SEND(RAM_X_START);
114  SEND(RAM_Y_START);
115  SEND(RAM_X_POS);
116  buffer[0] = 0x4F;
117  buffer[1] = (uint8_t) t;
118  buffer[2] = (uint8_t) (t >> 8);
119  SEND(buffer);
120 }
121 
122 // must implement, but we override setup to have more control
124 
126  this->send_reset_();
127  this->set_timeout(100, [this] {
128  this->write_lut_(PARTIAL_LUT);
129  SEND(BORDER_PART);
130  SEND(UPSEQ);
131  this->command(ACTIVATE);
132  this->set_timeout(100, [this] {
133  this->wait_until_idle_();
134  this->write_buffer_(WRITE_BUFFER, 0, this->get_height_internal());
135  SEND(ON_PARTIAL);
136  this->command(ACTIVATE); // Activate Display Update Sequence
137  this->is_busy_ = false;
138  });
139  });
140 }
141 
143  ESP_LOGI(TAG, "Performing full e-paper update.");
144  this->write_lut_(FULL_LUT);
145  this->write_buffer_(WRITE_BUFFER, 0, this->get_height_internal());
146  this->write_buffer_(WRITE_BASE, 0, this->get_height_internal());
147  SEND(ON_FULL);
148  this->command(ACTIVATE); // don't wait here
149  this->is_busy_ = false;
150 }
151 
153  if (this->is_busy_ || (this->busy_pin_ != nullptr && this->busy_pin_->digital_read()))
154  return;
155  this->is_busy_ = true;
156  const bool partial = this->at_update_ != 0;
157  this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
158  if (partial) {
159  this->partial_update_();
160  } else {
161  this->full_update_();
162  }
163 }
164 
166 
168 
169 uint32_t WaveshareEPaper2P13InV3::idle_timeout_() { return 5000; }
170 
172  LOG_DISPLAY("", "Waveshare E-Paper", this)
173  ESP_LOGCONFIG(TAG, " Model: 2.13inV3");
174  LOG_PIN(" CS Pin: ", this->cs_)
175  LOG_PIN(" Reset Pin: ", this->reset_pin_)
176  LOG_PIN(" DC Pin: ", this->dc_pin_)
177  LOG_PIN(" Busy Pin: ", this->busy_pin_)
178  LOG_UPDATE_INTERVAL(this)
179 }
180 
181 void WaveshareEPaper2P13InV3::set_full_update_every(uint32_t full_update_every) {
182  this->full_update_every_ = full_update_every;
183 }
184 
185 } // namespace waveshare_epaper
186 } // namespace esphome
virtual void digital_write(bool value)=0
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition: component.cpp:69
GPIOPin * cs_
Definition: spi.h:395
virtual bool digital_read()=0
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 write_buffer_(uint8_t cmd, int top, int bottom)
void set_full_update_every(uint32_t full_update_every)
stm32_cmd_t * cmd
Definition: stm32flash.h:96
void cmd_data(const uint8_t *data, size_t length)
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26