ESPHome 2025.5.0
Loading...
Searching...
No Matches
ssd1306_base.cpp
Go to the documentation of this file.
1#include "ssd1306_base.h"
2#include "esphome/core/log.h"
4
5namespace esphome {
6namespace ssd1306_base {
7
8static const char *const TAG = "ssd1306";
9
10static const uint8_t SSD1306_MAX_CONTRAST = 255;
11static const uint8_t SSD1305_MAX_BRIGHTNESS = 255;
12
13static const uint8_t SSD1306_COMMAND_DISPLAY_OFF = 0xAE;
14static const uint8_t SSD1306_COMMAND_DISPLAY_ON = 0xAF;
15static const uint8_t SSD1306_COMMAND_SET_DISPLAY_CLOCK_DIV = 0xD5;
16static const uint8_t SSD1306_COMMAND_SET_MULTIPLEX = 0xA8;
17static const uint8_t SSD1306_COMMAND_SET_DISPLAY_OFFSET_Y = 0xD3;
18static const uint8_t SSD1306_COMMAND_SET_START_LINE = 0x40;
19static const uint8_t SSD1306_COMMAND_CHARGE_PUMP = 0x8D;
20static const uint8_t SSD1306_COMMAND_MEMORY_MODE = 0x20;
21static const uint8_t SSD1306_COMMAND_SEGRE_MAP = 0xA0;
22static const uint8_t SSD1306_COMMAND_COM_SCAN_INC = 0xC0;
23static const uint8_t SSD1306_COMMAND_COM_SCAN_DEC = 0xC8;
24static const uint8_t SSD1306_COMMAND_SET_COM_PINS = 0xDA;
25static const uint8_t SSD1306_COMMAND_SET_CONTRAST = 0x81;
26static const uint8_t SSD1306_COMMAND_SET_PRE_CHARGE = 0xD9;
27static const uint8_t SSD1306_COMMAND_SET_VCOM_DETECT = 0xDB;
28static const uint8_t SSD1306_COMMAND_DISPLAY_ALL_ON_RESUME = 0xA4;
29static const uint8_t SSD1306_COMMAND_DEACTIVATE_SCROLL = 0x2E;
30static const uint8_t SSD1306_COMMAND_COLUMN_ADDRESS = 0x21;
31static const uint8_t SSD1306_COMMAND_PAGE_ADDRESS = 0x22;
32static const uint8_t SSD1306_COMMAND_NORMAL_DISPLAY = 0xA6;
33static const uint8_t SSD1306_COMMAND_INVERSE_DISPLAY = 0xA7;
34
35static const uint8_t SSD1305_COMMAND_SET_BRIGHTNESS = 0x82;
36static const uint8_t SSD1305_COMMAND_SET_AREA_COLOR = 0xD8;
37
38static const uint8_t SH1107_COMMAND_SET_START_LINE = 0xDC;
39static const uint8_t SH1107_COMMAND_CHARGE_PUMP = 0xAD;
40
43
44 // SH1107 resources
45 //
46 // Datasheet v2.3:
47 // www.displayfuture.com/Display/datasheet/controller/SH1107.pdf
48 // Adafruit C++ driver:
49 // github.com/adafruit/Adafruit_SH110x
50 // Adafruit CircuitPython driver:
51 // github.com/adafruit/Adafruit_CircuitPython_DisplayIO_SH1107
52
53 // Turn off display during initialization (0xAE)
54 this->command(SSD1306_COMMAND_DISPLAY_OFF);
55
56 // If SH1107, use POR defaults (0x50) = divider 1, frequency +0%
57 if (!this->is_sh1107_()) {
58 // Set oscillator frequency to 4'b1000 with no clock division (0xD5)
59 this->command(SSD1306_COMMAND_SET_DISPLAY_CLOCK_DIV);
60 // Oscillator frequency <= 4'b1000, no clock division
61 this->command(0x80);
62 }
63
64 // Enable low power display mode for SSD1305 (0xD8)
65 if (this->is_ssd1305_()) {
66 this->command(SSD1305_COMMAND_SET_AREA_COLOR);
67 this->command(0x05);
68 }
69
70 // Set mux ratio to [Y pixels - 1] (0xA8)
71 this->command(SSD1306_COMMAND_SET_MULTIPLEX);
72 this->command(this->get_height_internal() - 1);
73
74 // Set Y offset (0xD3)
75 this->command(SSD1306_COMMAND_SET_DISPLAY_OFFSET_Y);
76 this->command(0x00 + this->offset_y_);
77
78 if (this->is_sh1107_()) {
79 // Set start line at line 0 (0xDC)
80 this->command(SH1107_COMMAND_SET_START_LINE);
81 this->command(0x00);
82 } else {
83 // Set start line at line 0 (0x40)
84 this->command(SSD1306_COMMAND_SET_START_LINE | 0x00);
85 }
86
87 if (this->is_ssd1305_()) {
88 // SSD1305 does not have charge pump
89 } else if (this->is_sh1107_()) {
90 // Enable charge pump (0xAD)
91 this->command(SH1107_COMMAND_CHARGE_PUMP);
92 if (this->external_vcc_) {
93 this->command(0x8A);
94 } else {
95 this->command(0x8B);
96 }
97 } else {
98 // Enable charge pump (0x8D)
99 this->command(SSD1306_COMMAND_CHARGE_PUMP);
100 if (this->external_vcc_) {
101 this->command(0x10);
102 } else {
103 this->command(0x14);
104 }
105 }
106
107 // Set addressing mode to horizontal (0x20)
108 this->command(SSD1306_COMMAND_MEMORY_MODE);
109 if (!this->is_sh1107_()) {
110 // SH1107 memory mode is a 1 byte command
111 this->command(0x00);
112 }
113 // X flip mode (0xA0, 0xA1)
114 this->command(SSD1306_COMMAND_SEGRE_MAP | this->flip_x_);
115
116 // Y flip mode (0xC0, 0xC8)
117 this->command(SSD1306_COMMAND_COM_SCAN_INC | (this->flip_y_ << 3));
118
119 if (!this->is_sh1107_()) {
120 // Set pin configuration (0xDA)
121 this->command(SSD1306_COMMAND_SET_COM_PINS);
122 switch (this->model_) {
127 this->command(0x02);
128 break;
137 this->command(0x12);
138 break;
141 // Not used, but prevents build warning
142 break;
143 }
144 }
145
146 // Pre-charge period (0xD9)
147 this->command(SSD1306_COMMAND_SET_PRE_CHARGE);
148 if (this->external_vcc_) {
149 this->command(0x22);
150 } else {
151 this->command(0xF1);
152 }
153
154 // Set V_COM (0xDB)
155 this->command(SSD1306_COMMAND_SET_VCOM_DETECT);
156 switch (this->model_) {
160 this->command(0x35);
161 break;
163 this->command(0x20);
164 break;
165 default:
166 this->command(0x00);
167 break;
168 }
169
170 // Display output follow RAM (0xA4)
171 this->command(SSD1306_COMMAND_DISPLAY_ALL_ON_RESUME);
172
173 // Inverse display mode (0xA6, 0xA7)
174 this->set_invert(this->invert_);
175
176 // Disable scrolling mode (0x2E)
177 this->command(SSD1306_COMMAND_DEACTIVATE_SCROLL);
178
179 // Contrast and brighrness
180 // SSD1306 does not have brightness setting
181 set_contrast(this->contrast_);
182 if (this->is_ssd1305_())
184
185 this->fill(Color::BLACK); // clear display - ensures we do not see garbage at power-on
186 this->display(); // ...write buffer, which actually clears the display's memory
187
188 this->turn_on();
189}
191 if (this->is_sh1106_() || this->is_sh1107_()) {
192 this->write_display_data();
193 return;
194 }
195
196 this->command(SSD1306_COMMAND_COLUMN_ADDRESS);
197 switch (this->model_) {
200 this->command(0x20 + this->offset_x_);
201 this->command(0x20 + this->offset_x_ + this->get_width_internal() - 1);
202 break;
204 this->command(0x1C + this->offset_x_);
205 this->command(0x1C + this->offset_x_ + this->get_width_internal() - 1);
206 break;
207 default:
208 this->command(0 + this->offset_x_); // Page start address, 0
209 this->command(this->get_width_internal() + this->offset_x_ - 1);
210 break;
211 }
212
213 this->command(SSD1306_COMMAND_PAGE_ADDRESS);
214 // Page start address, 0
215 this->command(0);
216 // Page end address:
217 this->command((this->get_height_internal() / 8) - 1);
218
219 this->write_display_data();
220}
222 return this->model_ == SH1106_MODEL_96_16 || this->model_ == SH1106_MODEL_128_32 ||
224}
225bool SSD1306::is_sh1107_() const { return this->model_ == SH1107_MODEL_128_64 || this->model_ == SH1107_MODEL_128_128; }
227 return this->model_ == SSD1305_MODEL_128_64 || this->model_ == SSD1305_MODEL_128_64;
228}
230 this->do_update_();
231 this->display();
232}
233
234void SSD1306::set_invert(bool invert) {
235 this->invert_ = invert;
236 // Inverse display mode (0xA6, 0xA7)
237 this->command(SSD1306_COMMAND_NORMAL_DISPLAY | this->invert_);
238}
239float SSD1306::get_contrast() { return this->contrast_; };
240void SSD1306::set_contrast(float contrast) {
241 // validation
242 this->contrast_ = clamp(contrast, 0.0F, 1.0F);
243 // now write the new contrast level to the display (0x81)
244 this->command(SSD1306_COMMAND_SET_CONTRAST);
245 this->command(int(SSD1306_MAX_CONTRAST * (this->contrast_)));
246}
247float SSD1306::get_brightness() { return this->brightness_; };
248void SSD1306::set_brightness(float brightness) {
249 // validation
250 if (!this->is_ssd1305_())
251 return;
252 this->brightness_ = clamp(brightness, 0.0F, 1.0F);
253 // now write the new brightness level to the display (0x82)
254 this->command(SSD1305_COMMAND_SET_BRIGHTNESS);
255 this->command(int(SSD1305_MAX_BRIGHTNESS * (this->brightness_)));
256}
257bool SSD1306::is_on() { return this->is_on_; }
259 this->command(SSD1306_COMMAND_DISPLAY_ON);
260 this->is_on_ = true;
261}
263 this->command(SSD1306_COMMAND_DISPLAY_OFF);
264 this->is_on_ = false;
265}
267 switch (this->model_) {
270 return 128;
275 return 32;
279 return 64;
282 return 16;
285 return 48;
287 return 40;
288 default:
289 return 0;
290 }
291}
293 switch (this->model_) {
301 return 128;
304 return 96;
309 return 64;
311 return 72;
312 default:
313 return 0;
314 }
315}
317 return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) / 8u;
318}
320 if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0)
321 return;
322
323 uint16_t pos = x + (y / 8) * this->get_width_internal();
324 uint8_t subpos = y & 0x07;
325 if (color.is_on()) {
326 this->buffer_[pos] |= (1 << subpos);
327 } else {
328 this->buffer_[pos] &= ~(1 << subpos);
329 }
330}
331void SSD1306::fill(Color color) {
332 uint8_t fill = color.is_on() ? 0xFF : 0x00;
333 for (uint32_t i = 0; i < this->get_buffer_length_(); i++)
334 this->buffer_[i] = fill;
335}
337 if (this->reset_pin_ != nullptr) {
338 this->reset_pin_->setup();
339 this->reset_pin_->digital_write(true);
340 delay(1);
341 // Trigger Reset
342 this->reset_pin_->digital_write(false);
343 delay(10);
344 // Wake up
345 this->reset_pin_->digital_write(true);
346 }
347}
348const char *SSD1306::model_str_() {
349 switch (this->model_) {
351 return "SSD1306 128x32";
353 return "SSD1306 128x64";
355 return "SSD1306 64x32";
357 return "SSD1306 96x16";
359 return "SSD1306 64x48";
361 return "SSD1306 72x40";
363 return "SH1106 128x32";
365 return "SH1106 128x64";
367 return "SH1106 96x16";
369 return "SH1106 64x48";
371 return "SH1107 128x64";
373 return "SSD1305 128x32";
375 return "SSD1305 128x64";
376 default:
377 return "Unknown";
378 }
379}
380
381} // namespace ssd1306_base
382} // namespace esphome
virtual void setup()=0
virtual void digital_write(bool value)=0
void init_internal_(uint32_t buffer_length)
void fill(Color color) override
virtual void write_display_data()=0
virtual void command(uint8_t value)=0
void draw_absolute_pixel_internal(int x, int y, Color color) override
void set_brightness(float brightness)
void set_contrast(float contrast)
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:28
constexpr const T & clamp(const T &v, const T &lo, const T &hi, Compare comp)
Definition helpers.h:101
static const Color BLACK
Definition color.h:168
bool is_on() ESPHOME_ALWAYS_INLINE
Definition color.h:46
uint16_t x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6