Added 4 grayscale support to epd

This commit is contained in:
2026-04-04 15:18:06 -04:00
parent 2ffd258f2f
commit 7e21bde538
4 changed files with 8591 additions and 2429 deletions
+2 -2
View File
@@ -77,9 +77,9 @@ extern "C" void app_main()
ESP_LOGI(TAG, "Initializing EPD");
epd_init();
epd_init_display();
epd_init_display(true);
// epd_clear(epd_color::WHITE);
epd_draw_bitmap(epd_color::WHITE, test_image);
epd_draw_bitmap_grayscale(epd_color::WHITE, gImage_4G1);
epd_refresh();
epd_shutdown_display();
+8417 -2405
View File
File diff suppressed because it is too large Load Diff
+170 -21
View File
@@ -19,9 +19,11 @@ internal constexpr size_t kTotal_bytes = (EPD_WIDTH * EPD_HEIGHT) / 8;
internal uint8 g_scratch_buffer[4096];
internal struct epd_refresh_stats{
time_t last_full_refresh;
int fast_count;
} g_epd_stats = {0, 0};
time_t last_full_refresh_bw;
int fast_count_bw;
time_t last_full_refresh_4g;
int fast_count_4g;
} g_epd_stats = {0, 0, 0, 0};
internal void epd_spi_init(void)
{
@@ -201,7 +203,7 @@ internal void epd_init_display_fast(void)
epd_writedata(0x1F);
epd_writecommand(0x50); // VCOM AND DATA INTERVAL SETTING
epd_writedata(0x10);
epd_writedata(0x29);
epd_writedata(0x07);
epd_writecommand(0x04); // POWER ON
@@ -221,7 +223,61 @@ internal void epd_init_display_fast(void)
epd_writedata(0x5A);
}
void epd_init_display()
internal void epd_init_display_4g_full(void)
{
ESP_LOGI(kTagEPD, "Performing FULL 4-GRAY initialization");
epd_writecommand(0X00); // PANEL SETTING
epd_writedata(0x1F);
epd_writecommand(0X50); // VCOM AND DATA INTERVAL SETTING
epd_writedata(0x29);
epd_writedata(0x07);
epd_writecommand(0x04); // POWER ON
vTaskDelay(pdMS_TO_TICKS(100)); // Standard delay for full
epd_wait_until_idle();
// Standard display drive (Full Booster values)
epd_writecommand(0x06); // Booster Soft Start
epd_writedata(0x17);
epd_writedata(0x17);
epd_writedata(0x28);
epd_writedata(0x17);
epd_writecommand(0xE0);
epd_writedata(0x02);
epd_writecommand(0xE5);
epd_writedata(0x5F); // 0x5F -- 4 Gray
}
internal void epd_init_display_4g_fast(void)
{
ESP_LOGI(kTagEPD, "Performing FAST 4-GRAY initialization");
epd_writecommand(0X00); // PANEL SETTING
epd_writedata(0x1F);
epd_writecommand(0X50); // VCOM AND DATA INTERVAL SETTING
epd_writedata(0x29);
epd_writedata(0x07);
epd_writecommand(0x04); // POWER ON
vTaskDelay(pdMS_TO_TICKS(10));
epd_wait_until_idle();
// Enhanced display drive (Fast Booster values)
epd_writecommand(0x06); // Booster Soft Start
epd_writedata(0x27);
epd_writedata(0x27);
epd_writedata(0x18);
epd_writedata(0x17);
epd_writecommand(0xE0);
epd_writedata(0x02);
epd_writecommand(0xE5);
epd_writedata(0x5F); // 0x5F -- 4 Gray
}
void epd_init_display(bool is_4gray)
{
g_is_asleep = false;
@@ -232,27 +288,47 @@ void epd_init_display()
vTaskDelay(pdMS_TO_TICKS(10));
time_t now = time(NULL);
double diff = difftime(now, g_epd_stats.last_full_refresh);
// LOGIC: Full refresh if > 24 hours OR if we hit 5 fast refreshes
// Case: first boot (stats=0) -> force full
bool force_full = (g_epd_stats.last_full_refresh == 0) || (diff > 86400.0) ||
(g_epd_stats.fast_count >= 5);
if (force_full)
if (is_4gray)
{
epd_init_display_full();
g_epd_stats.last_full_refresh = now;
g_epd_stats.fast_count = 0;
double diff = difftime(now, g_epd_stats.last_full_refresh_4g);
bool force_full = (g_epd_stats.last_full_refresh_4g == 0) || (diff > 86400.0) ||
(g_epd_stats.fast_count_4g >= 5);
if (force_full)
{
epd_init_display_4g_full();
g_epd_stats.last_full_refresh_4g = now;
g_epd_stats.fast_count_4g = 0;
}
else
{
epd_init_display_4g_fast();
g_epd_stats.fast_count_4g++;
}
ESP_LOGI(kTagEPD, "4G Refresh stats: (Fast count: %d/5, Age: %.1f hours)",
g_epd_stats.fast_count_4g, diff / 3600.0);
}
else
{
epd_init_display_fast();
g_epd_stats.fast_count++;
}
double diff = difftime(now, g_epd_stats.last_full_refresh_bw);
bool force_full = (g_epd_stats.last_full_refresh_bw == 0) || (diff > 86400.0) ||
(g_epd_stats.fast_count_bw >= 5);
ESP_LOGI(kTagEPD, "Refresh stats: (Fast count: %d/5, Age: %.1f hours)",
g_epd_stats.fast_count, diff / 3600.0);
if (force_full)
{
epd_init_display_full();
g_epd_stats.last_full_refresh_bw = now;
g_epd_stats.fast_count_bw = 0;
}
else
{
epd_init_display_fast();
g_epd_stats.fast_count_bw++;
}
ESP_LOGI(kTagEPD, "BW Refresh stats: (Fast count: %d/5, Age: %.1f hours)",
g_epd_stats.fast_count_bw, diff / 3600.0);
}
}
void epd_shutdown_display(void)
@@ -307,4 +383,77 @@ void epd_draw_bitmap(epd_color clearColor, const uint8 *bitmap)
epd_write_buffer(bitmap, kTotal_bytes);
ESP_LOGI(kTagEPD, "Data transmission complete (Refresh required)");
}
}
void epd_draw_bitmap_grayscale(epd_color clearColor, const uint8 *bitmap)
{
ESP_LOGI(kTagEPD, "Drawing 4-GRAY bitmap (with unpacking)");
// THE LOGIC:
// The input bitmap is 2-bits per pixel packed (4 pixels per byte).
// Total pixels: 800 * 480 = 384,000.
// Input size: 384,000 / 4 = 96,000 bytes.
// Output: Two frames of 800 * 480 / 8 = 48,000 bytes each.
auto process_layer = [&](uint8 cmd, bool is_new_layer)
{
epd_writecommand(cmd);
size_t scratch_idx = 0;
// Process 48,000 output bytes (each covers 8 pixels)
for (size_t i = 0; i < 48000; i++)
{
uint8 output_byte = 0;
// Each output byte comes from 2 input bytes (j=0, j=1)
for (int j = 0; j < 2; j++)
{
uint8 input_byte = bitmap[i * 2 + j];
// Extract 4 pixels from each input byte
for (int k = 0; k < 4; k++)
{
uint8 pixel_bits = (input_byte >> (6 - k * 2)) & 0x03; // Correct bit order
bool bit_val = false;
if (is_new_layer)
{
// NEW Layer (0x13) Mapping
if (pixel_bits == 0x03) bit_val = true; // White (11)
else if (pixel_bits == 0x00) bit_val = false; // Black (00)
else if (pixel_bits == 0x02) bit_val = true; // Gray1 (10)
else if (pixel_bits == 0x01) bit_val = false; // Gray2 (01)
}
else
{
// OLD Layer (0x10) Mapping
if (pixel_bits == 0x03) bit_val = true; // White (11)
else if (pixel_bits == 0x00) bit_val = false; // Black (00)
else if (pixel_bits == 0x02) bit_val = false; // Gray1 (10)
else if (pixel_bits == 0x01) bit_val = true; // Gray2 (01)
}
if (bit_val) output_byte |= (1 << (7 - (j * 4 + k)));
}
}
// The demo code applies a bitwise NOT to the result
g_scratch_buffer[scratch_idx++] = ~output_byte;
if (scratch_idx >= sizeof(g_scratch_buffer))
{
epd_write_buffer(g_scratch_buffer, scratch_idx);
scratch_idx = 0;
}
}
if (scratch_idx > 0)
{
epd_write_buffer(g_scratch_buffer, scratch_idx);
}
};
process_layer(0x10, false); // Old data
process_layer(0x13, true); // New data
ESP_LOGI(kTagEPD, "Data transmission complete (Refresh required)");
}
+2 -1
View File
@@ -27,9 +27,10 @@ enum class epd_color : uint8
void epd_init(void);
void epd_shutdown(void);
void epd_init_display();
void epd_init_display(bool is_4gray);
void epd_shutdown_display(void);
void epd_refresh(void);
void epd_clear(epd_color level);
void epd_draw_bitmap(epd_color clearColor, const uint8 *bitmap);
void epd_draw_bitmap_grayscale(epd_color clearColor, const uint8 *bitmap);
bool epd_is_asleep(void);