Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor and test LUT functions #353

Merged
merged 15 commits into from
Sep 24, 2024
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
format-check:
runs-on: ubuntu-latest
container:
image: "espressif/idf:release-v5.2"
image: "espressif/idf:release-v5.3"
steps:
- uses: actions/checkout@v4
- run: |
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ set(app_sources "src/epdiy.c"
"src/output_common/lut.S"
"src/output_common/line_queue.c"
"src/output_common/render_context.c"
"src/output_common/render_method.c"
"src/font.c"
"src/displays.c"
"src/diff.S"
Expand Down
4 changes: 4 additions & 0 deletions examples/fb_mode_test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
cmake_minimum_required(VERSION 3.10.0)
set(EXTRA_COMPONENT_DIRS "../../")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(firmware)
4 changes: 4 additions & 0 deletions examples/fb_mode_test/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
set(app_sources "main.c")

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
idf_component_register(SRCS ${app_sources} REQUIRES epdiy)
203 changes: 203 additions & 0 deletions examples/fb_mode_test/main/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
/*
* Visual tests for framebuffer modes that are not commonly used by the high-level API.
* Currently, includes 2 pixel per byte (ppB) with static origin color and 8ppB with static origin
* color.
*
* After running this, you should see two identical test images, with a "ladder" of black triangles
* next to a black rectangle with a ladder of white triangles on it.
*/

#include <esp_heap_caps.h>
#include <esp_log.h>
#include <esp_sleep.h>
#include <esp_timer.h>
#include <esp_types.h>
#include <esp_assert.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <epdiy.h>

#include "sdkconfig.h"

#define WAVEFORM EPD_BUILTIN_WAVEFORM

// choose the default demo board depending on the architecture
#ifdef CONFIG_IDF_TARGET_ESP32
#define DEMO_BOARD epd_board_v6
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
#define DEMO_BOARD epd_board_v7
#endif

// Singular framebuffer to use for all of the tests.
// Allocated for 2ppB, the least compact that we test here.
uint8_t* framebuffer;
int fb_size;

static inline void checkError(enum EpdDrawError err) {
if (err != EPD_DRAW_SUCCESS) {
ESP_LOGE("demo", "draw error: %X", err);
}
}

/**
* Clears the screen to white and resets the framebuffer.
*/
void clear() {
epd_poweron();
epd_clear();
epd_poweroff();
memset(framebuffer, 0xFF, fb_size);
}

/**
* Draw triangles at varying alignments into the framebuffer in 8ppB mode.
* start_line, start_column specify the start position.
* The bits that belong to a triangle are flipped, i.e., it is drawn at the
* inverse color to the background it is drawn onto.
*/
void draw_8bpp_triangles(int start_line, int start_column) {
start_column /= 8;
int line_bytes = epd_width() / 8;

for (int align = 0; align < 16; align++) {
for (int height = 0; height < 16; height++) {
for (int len = 0; len <= height; len++) {
int line = (start_line + 16 * align + height);
int column = align + len;
uint8_t* line_address = framebuffer + (line_bytes * line);
*(line_address + start_column + column / 8) ^= 1 << (column % 8);
}
}
}
}

/**
* Draw triangles at varying alignments into the framebuffer in 2ppB mode.
* start_line, start_column specify the start position.
* color specifies the color to draw in.
*/
void draw_2bpp_triangles(int start_line, int start_column, uint8_t color) {
int height = 16;

for (int align = 0; align < 16; align++) {
int x0 = start_column + align;
int y0 = start_line + height * align;
int x1 = x0;
int y1 = y0 + height - 1;
int x2 = x0 + height - 1;
int y2 = y0 + height - 1;

epd_fill_triangle(x0, y0, x1, y1, x2, y2, color, framebuffer);
}
}

void test_8ppB() {
EpdRect area = epd_full_screen();
enum EpdDrawMode mode;

// bytes in a line in 8ppB mode
int line_bytes = epd_width() / 8;

int start_line = 100;

// draw differently aligned black triangles to check for uniformity
draw_8bpp_triangles(start_line, 80);

int black_start_column = 160;

// draw a black area
for (int line = 0; line < 300; line++) {
uint8_t* line_address = framebuffer + (line_bytes * (start_line + line));
memset(line_address + black_start_column / 8, 0, 32);
}

// update the display. In the first update, white pixels are no-opps,
// in the second update, black pixels are no-ops.
epd_poweron();
mode = MODE_PACKING_8PPB | MODE_DU | PREVIOUSLY_WHITE;
checkError(epd_draw_base(area, framebuffer, area, mode, 25, NULL, NULL, &epdiy_ED047TC2));
epd_poweroff();

// draw white triangles on the black background
draw_8bpp_triangles(start_line, black_start_column + 16);

epd_poweron();
mode = MODE_PACKING_8PPB | MODE_DU | PREVIOUSLY_BLACK;
checkError(epd_draw_base(area, framebuffer, area, mode, 25, NULL, NULL, &epdiy_ED047TC2));
epd_poweroff();
}

void test_2ppB() {
EpdRect area = epd_full_screen();
enum EpdDrawMode mode;
int start_column = 500;
int start_line = 100;

// draw differently aligned black triangles to check for uniformity
draw_2bpp_triangles(start_line, start_column, 0);

int black_start_column = start_column + 60;

// draw a black area
EpdRect black_area = { .x = black_start_column, .y = 100, .width = 256, .height = 300 };
epd_fill_rect(black_area, 0, framebuffer);

// Do not overdraw the 8ppB image
uint8_t* drawn_columns = malloc(epd_width() / 2);
assert(drawn_columns != NULL);
memset(drawn_columns, 0, epd_width() / 2);
memset(drawn_columns + start_column / 2, 255, (epd_width() - start_column) / 2);

// update the display. In the first update, white pixels are no-opps,
// in the second update, black pixels are no-ops.
epd_poweron();
mode = MODE_PACKING_2PPB | MODE_DU | PREVIOUSLY_WHITE;
checkError(
epd_draw_base(area, framebuffer, area, mode, 25, NULL, drawn_columns, &epdiy_ED047TC2)
);
epd_poweroff();

// draw white triangles on the black background
draw_2bpp_triangles(start_line, black_start_column + 16, 255);

epd_poweron();
mode = MODE_PACKING_2PPB | MODE_DU | PREVIOUSLY_BLACK;
checkError(
epd_draw_base(area, framebuffer, area, mode, 25, NULL, drawn_columns, &epdiy_ED047TC2)
);
epd_poweroff();

free(drawn_columns);
}

void app_main() {
epd_init(&DEMO_BOARD, &ED060XC3, EPD_OPTIONS_DEFAULT);

// Set VCOM for boards that allow to set this in software (in mV).
// This will print an error if unsupported. In this case,
// set VCOM using the hardware potentiometer and delete this line.
epd_set_vcom(2100);

epd_set_lcd_pixel_clock_MHz(10);

fb_size = epd_width() * epd_height() / 2;
framebuffer = heap_caps_aligned_alloc(16, fb_size, MALLOC_CAP_SPIRAM);

clear();

test_8ppB();

memset(framebuffer, 0xFF, fb_size);

test_2ppB();

printf("going to sleep...\n");
epd_deinit();
esp_deep_sleep_start();
}
Empty file.
Loading