ESPHome  2025.2.0
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 
76  auto width_bytes = this->get_width_controller() / 8;
77  this->write_array(this->buffer_ + top * width_bytes, (bottom - top) * width_bytes);
78  this->end_data_();
79 }
80 
82  if (this->reset_pin_ != nullptr) {
83  this->reset_pin_->digital_write(false);
84  delay(2);
85  this->reset_pin_->digital_write(true);
86  }
87 }
88 
90  this->init_internal_(this->get_buffer_length_());
91  this->setup_pins_();
92  this->spi_setup();
93  this->reset_();
94 
95  delay(20);
96  this->send_reset_();
97  // as a one-off delay this is not worth working around.
98  delay(100); // NOLINT
99  this->wait_until_idle_();
100  this->command(SW_RESET);
101  this->wait_until_idle_();
102 
103  SEND(DRV_OUT_CTL);
104  SEND(DATA_ENTRY);
105  SEND(CMD5);
106  this->set_window_(0, this->get_height_internal());
107  SEND(BORDER_FULL);
108  SEND(DISPLAY_UPDATE);
109  SEND(TEMP_SENS);
110  this->wait_until_idle_();
111  this->write_lut_(FULL_LUT);
112 }
113 
114 // t and b are y positions, i.e. line numbers.
116  uint8_t buffer[3];
117 
118  SEND(RAM_X_START);
119  SEND(RAM_Y_START);
120  SEND(RAM_X_POS);
121  buffer[0] = 0x4F;
122  buffer[1] = (uint8_t) t;
123  buffer[2] = (uint8_t) (t >> 8);
124  SEND(buffer);
125 }
126 
127 // must implement, but we override setup to have more control
129 
131  this->send_reset_();
132  this->set_timeout(100, [this] {
133  this->write_lut_(PARTIAL_LUT);
134  SEND(BORDER_PART);
135  SEND(UPSEQ);
136  this->command(ACTIVATE);
137  this->set_timeout(100, [this] {
138  this->wait_until_idle_();
139  this->write_buffer_(WRITE_BUFFER, 0, this->get_height_internal());
140  SEND(ON_PARTIAL);
141  this->command(ACTIVATE); // Activate Display Update Sequence
142  this->is_busy_ = false;
143  });
144  });
145 }
146 
148  ESP_LOGI(TAG, "Performing full e-paper update.");
149  this->write_lut_(FULL_LUT);
150  this->write_buffer_(WRITE_BUFFER, 0, this->get_height_internal());
151  this->write_buffer_(WRITE_BASE, 0, this->get_height_internal());
152  SEND(ON_FULL);
153  this->command(ACTIVATE); // don't wait here
154  this->is_busy_ = false;
155 }
156 
158  if (this->is_busy_ || (this->busy_pin_ != nullptr && this->busy_pin_->digital_read()))
159  return;
160  this->is_busy_ = true;
161  const bool partial = this->at_update_ != 0;
162  this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
163  if (partial) {
164  this->partial_update_();
165  } else {
166  this->full_update_();
167  }
168 }
169 
172 
174 
175 uint32_t WaveshareEPaper2P13InV3::idle_timeout_() { return 5000; }
176 
178  LOG_DISPLAY("", "Waveshare E-Paper", this)
179  ESP_LOGCONFIG(TAG, " Model: 2.13inV3");
180  LOG_PIN(" CS Pin: ", this->cs_)
181  LOG_PIN(" Reset Pin: ", this->reset_pin_)
182  LOG_PIN(" DC Pin: ", this->dc_pin_)
183  LOG_PIN(" Busy Pin: ", this->busy_pin_)
184  LOG_UPDATE_INTERVAL(this)
185 }
186 
187 void WaveshareEPaper2P13InV3::set_full_update_every(uint32_t full_update_every) {
188  this->full_update_every_ = full_update_every;
189 }
190 
191 } // namespace waveshare_epaper
192 } // 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:397
void init_internal_(uint32_t buffer_length)
virtual bool digital_read()=0
Implementation of SPI Controller mode.
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