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