Implement 4-quadrant dirty rectangle optimization and 30 FPS limiting for ST7796

Add intelligent partial screen update system using bitwise XOR change detection
and 4-quadrant tracking (top-left, top-right, bottom-left, bottom-right). Each
changed pixel is routed to its quadrant, with sophisticated merge logic that
combines adjacent rectangles when beneficial (<40% overhead). This dramatically
reduces SPI bandwidth for UIs with scattered updates (e.g., corners, sidebars).

Key changes:
- 4-quadrant dirty rectangle tracking with automatic merging
- XOR-based change detection for fast byte-level comparison
- Expose st7796_set_window() for partial region updates
- 30 FPS frame rate limiter (33ms per frame) to prevent excessive refreshes
- Smart sleep timing when frame rate limit is active

Performance: Up to 99% reduction in SPI traffic for corner-based UIs
(e.g., 4 small regions vs full 480x320 screen updates).

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Adolfo Reyna
2026-02-11 12:56:10 -05:00
parent b59d716965
commit eacc03a38c
5 changed files with 370 additions and 48 deletions

View File

@@ -268,7 +268,7 @@ static void write_command_with_data(uint8_t cmd, const uint8_t *data, size_t len
* This compensates for displays where the physical screen doesn't align
* with the controller's framebuffer (common with ST7789/ST7796).
*/
static void set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
void st7796_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
uint8_t data[4];
// Add offsets for display positioning
@@ -475,7 +475,7 @@ void st7796_init(const struct st7796_config *c, uint16_t w, uint16_t h) {
* @param color RGB565 color value (0x0000=black, 0xFFFF=white)
*/
void st7796_fill(uint16_t color) {
set_window(0, 0, width - 1, height - 1);
st7796_set_window(0, 0, width - 1, height - 1);
dc_data();
cs_select();
@@ -535,7 +535,7 @@ void st7796_put(uint16_t color) {
* @param y Starting Y coordinate
*/
void st7796_set_cursor(uint16_t x, uint16_t y) {
set_window(x, y, width - 1, height - 1);
st7796_set_window(x, y, width - 1, height - 1);
}
/**
@@ -614,8 +614,8 @@ void st7796_write_raw(const uint8_t *data, size_t len) {
*/
void st7796_draw_pixel(uint16_t x, uint16_t y, uint16_t color) {
if (x >= width || y >= height) return; // Bounds check
set_window(x, y, x, y); // 1x1 window
st7796_set_window(x, y, x, y); // 1x1 window
uint8_t data[2] = {(color >> 8) & 0xFF, color & 0xFF};
dc_data();
@@ -676,8 +676,8 @@ void st7796_fill_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t c
if (x >= width || y >= height) return;
if (x + w > width) w = width - x;
if (y + h > height) h = height - y;
set_window(x, y, x + w - 1, y + h - 1);
st7796_set_window(x, y, x + w - 1, y + h - 1);
dc_data();
cs_select();