Now can display a monochrome image from byte array + added slow/fast init display routine
This commit is contained in:
@@ -15,6 +15,8 @@
|
|||||||
#include "network.hpp"
|
#include "network.hpp"
|
||||||
#include "provider.hpp"
|
#include "provider.hpp"
|
||||||
|
|
||||||
|
#include "test_image.h"
|
||||||
|
|
||||||
static const char *TAG = "ClientMain";
|
static const char *TAG = "ClientMain";
|
||||||
|
|
||||||
extern "C" void app_main()
|
extern "C" void app_main()
|
||||||
@@ -76,7 +78,8 @@ extern "C" void app_main()
|
|||||||
ESP_LOGI(TAG, "Initializing EPD");
|
ESP_LOGI(TAG, "Initializing EPD");
|
||||||
epd_init();
|
epd_init();
|
||||||
epd_init_display();
|
epd_init_display();
|
||||||
epd_clear(epd_color_t::WHITE);
|
// epd_clear(epd_color::WHITE);
|
||||||
|
epd_draw_bitmap(epd_color::WHITE, test_image);
|
||||||
epd_refresh();
|
epd_refresh();
|
||||||
epd_shutdown_display();
|
epd_shutdown_display();
|
||||||
|
|
||||||
|
|||||||
+3002
-4001
File diff suppressed because it is too large
Load Diff
+115
-40
@@ -1,17 +1,27 @@
|
|||||||
#include "epd.hpp"
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "driver/spi_master.h"
|
#include "driver/spi_master.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "epd.hpp"
|
||||||
|
|
||||||
internal const char *kTagEPD = "EPD";
|
internal const char *kTagEPD = "EPD";
|
||||||
|
|
||||||
internal spi_device_handle_t g_spi_handle;
|
internal spi_device_handle_t g_spi_handle;
|
||||||
internal bool g_is_asleep = true;
|
internal bool g_is_asleep = true;
|
||||||
|
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};
|
||||||
|
|
||||||
internal void epd_spi_init(void)
|
internal void epd_spi_init(void)
|
||||||
{
|
{
|
||||||
@@ -78,6 +88,7 @@ internal void epd_write_buffer(const uint8 *data, size_t len)
|
|||||||
// Pull DC High for Data
|
// Pull DC High for Data
|
||||||
gpio_set_level((gpio_num_t)TFT_DC, GPIO_HIGH);
|
gpio_set_level((gpio_num_t)TFT_DC, GPIO_HIGH);
|
||||||
|
|
||||||
|
int chunk_count = 0;
|
||||||
while (len > 0)
|
while (len > 0)
|
||||||
{
|
{
|
||||||
// max_transfer_sz is typically 4096 which is the limit for a single SPI
|
// max_transfer_sz is typically 4096 which is the limit for a single SPI
|
||||||
@@ -90,6 +101,28 @@ internal void epd_write_buffer(const uint8 *data, size_t len)
|
|||||||
spi_device_transmit(g_spi_handle, &t);
|
spi_device_transmit(g_spi_handle, &t);
|
||||||
data += chunk;
|
data += chunk;
|
||||||
len -= chunk;
|
len -= chunk;
|
||||||
|
|
||||||
|
// Yield every 16 chunks (~64KB) to prevent task watchdog timeout
|
||||||
|
if (++chunk_count % 16 == 0)
|
||||||
|
{
|
||||||
|
vTaskDelay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void epd_fill_layer(uint8 cmd, uint8 color_byte)
|
||||||
|
{
|
||||||
|
epd_writecommand(cmd);
|
||||||
|
|
||||||
|
memset(g_scratch_buffer, color_byte, sizeof(g_scratch_buffer));
|
||||||
|
|
||||||
|
size_t remaining = kTotal_bytes;
|
||||||
|
while (remaining > 0)
|
||||||
|
{
|
||||||
|
size_t to_write =
|
||||||
|
(remaining > sizeof(g_scratch_buffer)) ? sizeof(g_scratch_buffer) : remaining;
|
||||||
|
epd_write_buffer(g_scratch_buffer, to_write);
|
||||||
|
remaining -= to_write;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,16 +154,9 @@ void epd_shutdown(void)
|
|||||||
spi_bus_free(SPI2_HOST);
|
spi_bus_free(SPI2_HOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void epd_init_display()
|
internal void epd_init_display_full(void)
|
||||||
{
|
{
|
||||||
g_is_asleep = false;
|
ESP_LOGI(kTagEPD, "Performing FULL initialization");
|
||||||
|
|
||||||
// Module reset
|
|
||||||
gpio_set_level((gpio_num_t)TFT_RST, 0);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(10));
|
|
||||||
gpio_set_level((gpio_num_t)TFT_RST, 1);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(10));
|
|
||||||
|
|
||||||
epd_writecommand(0x01); // POWER SETTING
|
epd_writecommand(0x01); // POWER SETTING
|
||||||
epd_writedata(0x07);
|
epd_writedata(0x07);
|
||||||
epd_writedata(0x07);
|
epd_writedata(0x07);
|
||||||
@@ -160,13 +186,75 @@ void epd_init_display()
|
|||||||
epd_writedata(0x00);
|
epd_writedata(0x00);
|
||||||
|
|
||||||
epd_writecommand(0x50); // VCOM AND DATA INTERVAL SETTING
|
epd_writecommand(0x50); // VCOM AND DATA INTERVAL SETTING
|
||||||
epd_writedata(0x29); // BDV=10 (White Border), N2OCP=1 (Auto-copy NEW to OLD), DDX=01 (0=Black, 1=White)
|
epd_writedata(0x29); // BDV=10 (White Border), N2OCP=1 (Auto-copy NEW to OLD),
|
||||||
|
// DDX=01 (0=Black, 1=White)
|
||||||
epd_writedata(0x07);
|
epd_writedata(0x07);
|
||||||
|
|
||||||
epd_writecommand(0x60); // TCON SETTING
|
epd_writecommand(0x60); // TCON SETTING
|
||||||
epd_writedata(0x22);
|
epd_writedata(0x22);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void epd_init_display_fast(void)
|
||||||
|
{
|
||||||
|
ESP_LOGI(kTagEPD, "Performing FAST initialization");
|
||||||
|
epd_writecommand(0X00); // PANEL SETTING
|
||||||
|
epd_writedata(0x1F);
|
||||||
|
|
||||||
|
epd_writecommand(0x50); // VCOM AND DATA INTERVAL SETTING
|
||||||
|
epd_writedata(0x10);
|
||||||
|
epd_writedata(0x07);
|
||||||
|
|
||||||
|
epd_writecommand(0x04); // POWER ON
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
epd_wait_until_idle();
|
||||||
|
|
||||||
|
// Enhanced display drive (Booster values for fast mode)
|
||||||
|
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(0x5A);
|
||||||
|
}
|
||||||
|
|
||||||
|
void epd_init_display()
|
||||||
|
{
|
||||||
|
g_is_asleep = false;
|
||||||
|
|
||||||
|
// Module reset
|
||||||
|
gpio_set_level((gpio_num_t)TFT_RST, 0);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
|
gpio_set_level((gpio_num_t)TFT_RST, 1);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
epd_init_display_full();
|
||||||
|
g_epd_stats.last_full_refresh = now;
|
||||||
|
g_epd_stats.fast_count = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
epd_init_display_fast();
|
||||||
|
g_epd_stats.fast_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(kTagEPD, "Refresh stats: (Fast count: %d/5, Age: %.1f hours)",
|
||||||
|
g_epd_stats.fast_count, diff / 3600.0);
|
||||||
|
}
|
||||||
|
|
||||||
void epd_shutdown_display(void)
|
void epd_shutdown_display(void)
|
||||||
{
|
{
|
||||||
assert(!g_is_asleep);
|
assert(!g_is_asleep);
|
||||||
@@ -196,40 +284,27 @@ void epd_refresh(void)
|
|||||||
|
|
||||||
bool epd_is_asleep(void) { return g_is_asleep; }
|
bool epd_is_asleep(void) { return g_is_asleep; }
|
||||||
|
|
||||||
void epd_clear(epd_color_t level)
|
void epd_clear(epd_color level)
|
||||||
{
|
{
|
||||||
assert(!g_is_asleep);
|
|
||||||
|
|
||||||
// Directly pass the color preference to hardware (hardware polarity is
|
|
||||||
// configured in DDX)
|
|
||||||
uint8 color_byte = static_cast<uint8>(level);
|
uint8 color_byte = static_cast<uint8>(level);
|
||||||
ESP_LOGI(kTagEPD, "Clearing display (byte=0x%02X)", color_byte);
|
ESP_LOGI(kTagEPD, "Clearing display (byte=0x%02X)", color_byte);
|
||||||
|
|
||||||
constexpr size_t total_bytes = (EPD_WIDTH * EPD_HEIGHT) / 8;
|
epd_fill_layer(0x10,
|
||||||
|
0xFF); // Old data layer (0xFF is mapped to White)
|
||||||
|
epd_fill_layer(0x13, color_byte); // New data layer
|
||||||
|
|
||||||
auto write_layer = [&](uint8 cmd, uint8 fill_byte)
|
ESP_LOGI(kTagEPD, "Data transmission complete (Refresh required)");
|
||||||
{
|
}
|
||||||
uint8 chunk[256];
|
|
||||||
memset(chunk, fill_byte, sizeof(chunk));
|
|
||||||
|
|
||||||
epd_writecommand(cmd);
|
void epd_draw_bitmap(epd_color clearColor, const uint8 *bitmap)
|
||||||
size_t remaining = total_bytes;
|
{
|
||||||
int chunk_count = 0;
|
uint8 color_byte = static_cast<uint8>(clearColor);
|
||||||
while (remaining > 0)
|
ESP_LOGI(kTagEPD, "Drawing bitmap (clearColor byte=0x%02X)", color_byte);
|
||||||
{
|
|
||||||
size_t to_write = (remaining > sizeof(chunk)) ? sizeof(chunk) : remaining;
|
|
||||||
epd_write_buffer(chunk, to_write);
|
|
||||||
remaining -= to_write;
|
|
||||||
// Yield every 16 chunks (~4KB) to prevent task watchdog timeout
|
|
||||||
if (++chunk_count % 16 == 0)
|
|
||||||
vTaskDelay(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
write_layer(
|
epd_fill_layer(0x10, color_byte); // Send clear color to "Old" layer
|
||||||
0x10,
|
|
||||||
0xFF); // Old data layer (0xFF is mapped to White under new polarity)
|
epd_writecommand(0x13); // "New" data layer
|
||||||
write_layer(0x13, color_byte); // New data layer
|
epd_write_buffer(bitmap, kTotal_bytes);
|
||||||
|
|
||||||
ESP_LOGI(kTagEPD, "Data transmission complete (Refresh required)");
|
ESP_LOGI(kTagEPD, "Data transmission complete (Refresh required)");
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
#define EPD_WIDTH 800
|
#define EPD_WIDTH 800
|
||||||
#define EPD_HEIGHT 480
|
#define EPD_HEIGHT 480
|
||||||
|
|
||||||
enum class epd_color_t : uint8
|
enum class epd_color : uint8
|
||||||
{
|
{
|
||||||
BLACK = 0x00,
|
BLACK = 0x00,
|
||||||
WHITE = 0xFF
|
WHITE = 0xFF
|
||||||
@@ -30,5 +30,6 @@ void epd_shutdown(void);
|
|||||||
void epd_init_display();
|
void epd_init_display();
|
||||||
void epd_shutdown_display(void);
|
void epd_shutdown_display(void);
|
||||||
void epd_refresh(void);
|
void epd_refresh(void);
|
||||||
void epd_clear(epd_color_t level);
|
void epd_clear(epd_color level);
|
||||||
|
void epd_draw_bitmap(epd_color clearColor, const uint8 *bitmap);
|
||||||
bool epd_is_asleep(void);
|
bool epd_is_asleep(void);
|
||||||
Reference in New Issue
Block a user