ESPHome 2026.1.0-dev
Loading...
Searching...
No Matches
hub75.cpp
Go to the documentation of this file.
1#include "hub75_component.h"
3
4#ifdef USE_ESP32
5
6namespace esphome::hub75 {
7
8static const char *const TAG = "hub75";
9
10// ========================================
11// Constructor
12// ========================================
13
14HUB75Display::HUB75Display(const Hub75Config &config) : config_(config) {
15 // Initialize runtime state from config
16 this->brightness_ = config.brightness;
17 this->enabled_ = (config.brightness > 0);
18}
19
20// ========================================
21// Core Component methods
22// ========================================
23
25 ESP_LOGCONFIG(TAG, "Setting up HUB75Display...");
26
27 // Create driver with pre-configured config
28 driver_ = new Hub75Driver(config_);
29 if (!driver_->begin()) {
30 ESP_LOGE(TAG, "Failed to initialize HUB75 driver!");
31 return;
32 }
33
34 this->enabled_ = true;
35}
36
38 LOG_DISPLAY("", "HUB75", this);
39
40 ESP_LOGCONFIG(TAG,
41 " Panel: %dx%d pixels\n"
42 " Layout: %dx%d panels\n"
43 " Virtual Display: %dx%d pixels",
44 config_.panel_width, config_.panel_height, config_.layout_cols, config_.layout_rows,
45 config_.panel_width * config_.layout_cols, config_.panel_height * config_.layout_rows);
46
47 ESP_LOGCONFIG(TAG,
48 " Scan Wiring: %d\n"
49 " Shift Driver: %d",
50 static_cast<int>(config_.scan_wiring), static_cast<int>(config_.shift_driver));
51
52 ESP_LOGCONFIG(TAG,
53 " Pins: R1:%i, G1:%i, B1:%i, R2:%i, G2:%i, B2:%i\n"
54 " Pins: A:%i, B:%i, C:%i, D:%i, E:%i\n"
55 " Pins: LAT:%i, OE:%i, CLK:%i",
56 config_.pins.r1, config_.pins.g1, config_.pins.b1, config_.pins.r2, config_.pins.g2, config_.pins.b2,
57 config_.pins.a, config_.pins.b, config_.pins.c, config_.pins.d, config_.pins.e, config_.pins.lat,
58 config_.pins.oe, config_.pins.clk);
59
60 ESP_LOGCONFIG(TAG,
61 " Clock Speed: %u MHz\n"
62 " Latch Blanking: %i\n"
63 " Clock Phase: %s\n"
64 " Min Refresh Rate: %i Hz\n"
65 " Bit Depth: %i\n"
66 " Double Buffer: %s",
67 static_cast<uint32_t>(config_.output_clock_speed) / 1000000, config_.latch_blanking,
68 TRUEFALSE(config_.clk_phase_inverted), config_.min_refresh_rate, HUB75_BIT_DEPTH,
69 YESNO(config_.double_buffer));
70}
71
72// ========================================
73// Display/PollingComponent methods
74// ========================================
75
77 if (!driver_) [[unlikely]]
78 return;
79 if (!this->enabled_) [[unlikely]]
80 return;
81
82 this->do_update_();
83
84 if (config_.double_buffer) {
85 driver_->flip_buffer();
86 }
87}
88
90 if (!driver_) [[unlikely]]
91 return;
92 if (!this->enabled_) [[unlikely]]
93 return;
94
95 // Special case: black (off) - use fast hardware clear
96 if (!color.is_on()) {
97 driver_->clear();
98 return;
99 }
100
101 // For non-black colors, fall back to base class (pixel-by-pixel)
102 Display::fill(color);
103}
104
105void HOT HUB75Display::draw_pixel_at(int x, int y, Color color) {
106 if (!driver_) [[unlikely]]
107 return;
108 if (!this->enabled_) [[unlikely]]
109 return;
110
111 if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) [[unlikely]]
112 return;
113
114 driver_->set_pixel(x, y, color.r, color.g, color.b);
115 App.feed_wdt();
116}
117
118void HOT HUB75Display::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
119 ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) {
120 if (!driver_) [[unlikely]]
121 return;
122 if (!this->enabled_) [[unlikely]]
123 return;
124
125 // Map ESPHome enums to hub75 enums
126 Hub75PixelFormat format;
127 Hub75ColorOrder color_order = Hub75ColorOrder::RGB;
128 int bytes_per_pixel;
129
130 // Determine format based on bitness
131 if (bitness == ColorBitness::COLOR_BITNESS_565) {
132 format = Hub75PixelFormat::RGB565;
133 bytes_per_pixel = 2;
134 } else if (bitness == ColorBitness::COLOR_BITNESS_888) {
135#ifdef USE_LVGL
136#if LV_COLOR_DEPTH == 32
137 // 32-bit: 4 bytes per pixel with padding byte (LVGL mode)
138 format = Hub75PixelFormat::RGB888_32;
139 bytes_per_pixel = 4;
140
141 // Map ESPHome ColorOrder to Hub75ColorOrder
142 // ESPHome ColorOrder is typically BGR for little-endian 32-bit
143 color_order = (order == ColorOrder::COLOR_ORDER_RGB) ? Hub75ColorOrder::RGB : Hub75ColorOrder::BGR;
144#elif LV_COLOR_DEPTH == 24
145 // 24-bit: 3 bytes per pixel, tightly packed
146 format = Hub75PixelFormat::RGB888;
147 bytes_per_pixel = 3;
148 // Note: 24-bit is always RGB order in LVGL
149#else
150 ESP_LOGE(TAG, "Unsupported LV_COLOR_DEPTH: %d", LV_COLOR_DEPTH);
151 return;
152#endif
153#else
154 // Non-LVGL mode: standard 24-bit RGB888
155 format = Hub75PixelFormat::RGB888;
156 bytes_per_pixel = 3;
157 color_order = (order == ColorOrder::COLOR_ORDER_RGB) ? Hub75ColorOrder::RGB : Hub75ColorOrder::BGR;
158#endif
159 } else {
160 ESP_LOGE(TAG, "Unsupported bitness: %d", static_cast<int>(bitness));
161 return;
162 }
163
164 // Check if buffer is tightly packed (no stride)
165 const int stride_px = x_offset + w + x_pad;
166 const bool is_packed = (x_offset == 0 && x_pad == 0 && y_offset == 0);
167
168 if (is_packed) {
169 // Tightly packed buffer - single bulk call for best performance
170 driver_->draw_pixels(x_start, y_start, w, h, ptr, format, color_order, big_endian);
171 } else {
172 // Buffer has stride (padding between rows) - draw row by row
173 for (int yy = 0; yy < h; ++yy) {
174 const size_t row_offset = ((y_offset + yy) * stride_px + x_offset) * bytes_per_pixel;
175 const uint8_t *row_ptr = ptr + row_offset;
176
177 driver_->draw_pixels(x_start, y_start + yy, w, 1, row_ptr, format, color_order, big_endian);
178 }
179 }
180}
181
182void HUB75Display::set_brightness(uint8_t brightness) {
183 this->brightness_ = brightness;
184 this->enabled_ = (brightness > 0);
185 if (this->driver_ != nullptr) {
186 this->driver_->set_brightness(brightness);
187 }
188}
189
190} // namespace esphome::hub75
191
192#endif
uint8_t h
Definition bl0906.h:2
void feed_wdt(uint32_t time=0)
void update() override
Definition hub75.cpp:76
void draw_pixel_at(int x, int y, Color color) override
Definition hub75.cpp:105
HUB75Display(const Hub75Config &config)
Definition hub75.cpp:14
void set_brightness(uint8_t brightness)
Definition hub75.cpp:182
void setup() override
Definition hub75.cpp:24
void dump_config() override
Definition hub75.cpp:37
void fill(Color color) override
Definition hub75.cpp:89
void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) override
Definition hub75.cpp:118
Application App
Global storage of Application pointer - only one Application can exist.
uint8_t g
Definition color.h:34
uint8_t b
Definition color.h:38
bool is_on() ESPHOME_ALWAYS_INLINE
Definition color.h:70
uint8_t r
Definition color.h:30
uint16_t x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6